Reputation: 586
I want to make query like this one:
SELECT lyrics FROM cache WHERE author=%s0, title=%s1 LIMIT 1;
where strings %s0
and %s1
should be substituted. Assuming strings are not sanitized, UTF-8 encoded (As database itself), simple null-terminated char*
arrays. What are my options to do this? Are there any built-in functions in SQLite (C API) for this?
Upvotes: 1
Views: 1287
Reputation: 27106
Like mentioned in comments already prepared statements should be used.
Why Prepared Statements Should Be Favoured
When you create SQL queries yourself as a string, they almost always contain parts of a user's input. An attacker can take advantage of this by, for example, cleverly changing the semantics of the query using '
and thus gaining unauthorized access to data or destroying data.
This is called SQL injection and is one of the top most critical security risks, see here: https://www.owasp.org/images/7/72/OWASP_Top_10-2017_%28en%29.pdf.pdf
Defense
The use of prepared statements with variable binding (aka parameterized queries) is how all developers should first be taught how to write database queries.
How to use prepared statements with SQLite
For prepared statements see https://www.sqlite.org/c3ref/stmt.html.
Basic steps are:
Example
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"
void exit_with_error(sqlite3 *db, const char * msg) {
fprintf(stderr, "%s: %s\n", msg, sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
int main() {
sqlite3 *db;
sqlite3_stmt *stmt;
int rc = sqlite3_open("path-to-lyrics", &db);
if (rc != SQLITE_OK)
exit_with_error(db, "can't open db: ");
//create prepared statement
rc = sqlite3_prepare_v2(db, "SELECT lyrics FROM cache WHERE author=?1 AND title=?2 LIMIT 1;", -1, &stmt, 0);
if (rc != SQLITE_OK)
exit_with_error(db, "failure fetching data: ");
//bind values to parameters
sqlite3_bind_text(stmt, 1, "Don Brownrigg", -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, "Just Breathe", -1, SQLITE_STATIC);
//run the SQL
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) {
printf("%s\n", sqlite3_column_text(stmt, 0));
}
//destroy the object to avoid resource leaks
sqlite3_finalize(stmt);
sqlite3_close(db);
return 0;
}
Build
With CMake it could look like this:
cmake_minimum_required(VERSION 3.14)
project(sqlitequery C)
set(CMAKE_C_STANDARD 99)
add_executable(sqlitequery main.c)
target_link_libraries (sqlitequery sqlite3)
On command line one could build with something like:
gcc -Wall -Wextra main.c -lsqlite3 -o sqlitequery
Upvotes: 3