I have been trying to use the SQLite tutorial here to learn how to use SQLite in C. I was having trouble figuring out exactly how to use it, as it only mentions the sqlite3_exec, which seems incredibly un-intuitive to use for basic querying (it uses a callback for everything). Then I came across this answer, https://stackoverflow.com/a/31168999/11954200, which addresses this same issue and suggests using the various four sqlite statements that are essentially merged into the sqlite3_exec shorthand form. Here is my understanding so far:
// Query to get the rows
// Part1 -- Prepare the query: cursor.execute()
// http://www.sqlite.org/c3ref/prepare.html
sqlite3_stmt *stmt; // this is the prepared statement that the sqlite3_prepare writes to
rc = sqlite3_prepare(db, "SELECT * FROM mytable LIMIT 20", -1, &stmt, NULL);
if (rc != SQLITE_OK) {
printf("error: %s", sqlite3_errmsg(db));
return 0;
}
// Part2 -- equivalent of cursor.fetchone()
// http://www.sqlite.org/c3ref/step.html
int rownum=1;
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
// Part3 -- reference the values from the row
// http://www.sqlite.org/c3ref/column_blob.html
int id = sqlite3_column_int(stmt, 0);
const unsigned char * date = sqlite3_column_text(stmt, 1);
printf("Row: %d | ID: %d | Date: %s\n", rownum, id, date);
rownum++;
}
// Part4 -- equivalent of cursor.close()
// http://www.sqlite.org/c3ref/finalize.html
sqlite3_finalize(stmt);
In other words, in higher language parlance:
sqlite3_prepare(...) works like cursor.execute(...)
sqlite3_step(...) works like cursor.fetchone(...)
sqlite3_finalize(...) works like cursor.close(...);
Is this an accurate assessment of how these statements work in sqlite? Would the sqlite3_exec ever be used when fetching results?
Related
I know that there probably was plenty on that but after several days of searching I am unable to find how to do one simple passing of integer and char in one go to PostgreSQL from C under Linux.
In PHP it is easy, like 123, and in C using libpq it seem to be like something out of ordinary.
I had a look at PQexecParams but is seem to be not helping. Examples on the net are not helping as well and it seems to be an impossible mission.
Would someone be kind enough to translate this simple PHP statement to C and show me how to pass multiple vars of different types in one INSERT query.
col1 is INT
col2 is CHAR
$int1 = 1;
$char1 = 'text';
$query = "INSERT INTO table (col1, col2) values ('$int1',$char1)";
$result = ibase_query($query);
This would show what I am trying to do (please mind the code is very wrong):
void insert_CommsDb(PGconn *conn, PGresult *pgres, int csrv0) { const char * params[1];
params[0] = csrv0;
pgres = PQexecParams(conn, "INSERT INTO comms_db (srv0::int) values ($1)",
1,
NULL,
params,
1,
NULL,
0);
if (PQresultStatus(pgres) != PGRES_COMMAND_OK)
{
fprintf(stderr, "INSERT failed: %s", PQerrorMessage(conn));
exit_nicely(conn,pgres);
}
PQclear(pgres);
}
https://www.postgresql.org/docs/current/static/libpq-exec.html
As #joop commented above:
If the paramTypes argument is NULL, all the params are assumed to be strings.
So, you should transform your int argument to a string.
void insert_CommsDb(PGconn *conn, int csrv0)
{
PGresult *pgres;
char * params[1];
char buff[12];
sprintf(buff, "%d", csrv0);
params[0] = buff;
pgres = PQexecParams(conn
, "INSERT INTO comms_db (srv0::int) values ($1)" // The query (we dont need the cast here)
, 1 // number of params
, NULL // array with types, or NULL
, params // array with parameter values
, NULL // ARRAY with parameter lenghts
, NULL // array with per-param flags indicating binary/non binary
, 0 // set to 1 if we want BINARY results, 0 for txt
);
if (PQrresultStatus(pgres) != PGRES_COMMAND_OK)
{
fprintf(stderr, "INSERT failed: %s", PQerrorMessage(conn));
exit_nicely(conn,pgres);
}
PQclear(pgres);
}
wildplasser's answer shows the way in general.
Since you explicitly asked about several parameters, I'll add an example for that.
If you are not happy to convert integers to strings, the alternative would be to use the external binary format of the data type in question. That requires inside knowledge and probably reading the PostgreSQL source. For some data types, it can also depend on the hardware.
PGresult *res;
PGconn *conn;
Oid types[2];
char * values[2];
int lengths[2], formats[2];
int arg0;
/* connect to the database */
/*
* The first argument is in binary format.
* Apart from having to use the "external binary
* format" for the data, we have to specify
* type and length.
*/
arg0 = htonl(42); /* external binary format: network byte order */
types[0] = 23; /* OID of "int4" */
values[0] = (char *) &arg0;
lengths[0] = sizeof(int);
formats[0] = 1;
/* second argument is in text format */
types[1] = 0;
values[1] = "something";
lengths[1] = 0;
formats[1] = 0;
res = PQexecParams(
conn,
"INSERT INTO mytab (col1, col2) values ($1, $2)",
2,
types,
(const char * const *)values,
lengths,
formats,
0 /* results in text format */
);
I'd recommend that you use the text format for most data types.
The notable exception is bytea, where it usually is an advantage to use the binary format, as it saves space and CPU power. In this case, the external binary format is simply the bytes.
VS C++ not liking htonl(42):
arg0 = htonl(42); /* external binary format: network byte order */
In my C program I have to check if count of a table in database is one or zero and to do that i am executing query as follows:
char *sql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=family;";
int table_count = sqlite3_exec(db, sql, 0, 0, &err_msg);
printf("\n%d\n", table_count);
I'm expecting table_count to be 1 as only one table exists with name family but printf outputs table_count as '21' which is incorrect. How can we get the COUNT(*) value from C/C++ API in C program the right/correct way?
After reading SQLite Documentation and following other kind implicit/explicit suggestions in the comments on the question, I have realized my mistakes in that code snippet quoted in the question.
Mistake 1:
I did not implement callback function to receive the result set after the SQL query gets executed. [Have implemented this callback: see checkTable_Callback in code below]
Mistake 2:
That output of '21' is actually the error code and as per the SQLite documentation that error code corresponds to SQLite_MISUSE Which was being generated, perhaps, because I was using a separate function to open my test database file and instance of that opened database, i assume, stayed inside that openDb function, and when i used another function checkTableCount from where i took that messy snippet to quote in my question, there db instance perhaps was null, hence 21. Experts can elaborate further if that's why i was receiving error code 21. Anyways, now i have fixed that function and made that openDb return an opened db instance (better word?) and now 21 error is gone. [see code below]
Here is fixed and 'adapted-for-my-case' code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlite3.h" /* sqlite3.dll and sqlite3.h both reside in
my <program_source.c>'s folder */
static int checkTable_Callback(
void *unnecessary_here,
int number_of_columns_in_result_row, /* will always be 1 in this case */
char **value_of_count, /* will be either 0 or 1 in this case */
char **label_for_count) { /* will be COUNT(*) normally,
but modified via 'AS table_tablename' in this case*/
printf("COUNT(*) %s\t=>\t%s\n", label_for_count[0], value_of_count[0] );
return 0;
} // end of checkTable_Callback()
char * build_sql(const char *sql_partA, const char *sql_partB) {
size_t size = strlen(sql_partA) + strlen(sql_partB);
char *sql_final = malloc(size + 1);
strcpy(sql_final, sql_partA);
strcat(sql_final, sql_partB);
return sql_final; /* allocated memory to be freed at the end of calling function */
} // end of build_sql()
checkTableCount(sqlite3 *db, char *tablename) {
char *sql = build_sql(
build_sql(
build_sql(
build_sql(
"SELECT COUNT(*) AS table_",
tablename),
" FROM sqlite_master WHERE type='table' AND name='"),
tablename),
"';");
sqlite3_exec(db, sql, checkTable_Callback, 0, NULL);
/* error checking sacrificed for brevity of sample */
free(sql);
}// end of checkTableCount()
sqlite3 * openDb(char * db_name){
sqlite3 *db;
int result_code = sqlite3_open(db_name, &db);
if( result_code != 0 )
fprintf(stderr, "\tError: %s\n\n", sqlite3_errmsg(db));
return db;
} // end of openDb()
int main() {
sqlite3 * db = openDb("testing.db"); /* testing.db already has one table 'family'*/
checkTableCount(db, "family");
checkTableCount(db, "fam"); /* no such table exist */
sqlite3_close(db);
return 0;
} // end of main()
Now this quoted 'adapted-for-my-case' code rightly and correctly outputs the COUNT(*) as follows:
OUTPUT
COUNT(*) table_family => 1
COUNT(*) table_fam => 0
Note that I didn't bother to write a for-loop inside my callback function named checkTable_Callback to iterate through columns as shown in the official sample of callback function on this page because of the fact that our expected result row is certainly going to be only one containing only one column with label modified, via 'AS' clause, into 'table_tablename'. If not modified via 'AS clause', the returned column label would be 'COUNT(*)' in the result row.
Introduction
I'm attempting to incorporate variables into queries using C. I'm following this tutorial using sqlite tutorialspoint , and my first exposure to using SQL. The tutorial has shown me how to use Queries such as these:
Query
sql = "UPDATE COMPANY set SALARY = 25000.00 where ID=1; " \
"SELECT * from COMPANY";
*So how would i go about incorporating variables into this statement, for example if i wanted to replace 1 with a variable assigned to 'ID'.
For example(My failed attempt)
sql = "UPDATE COMPANY set SALARY = 25000.00 where ID=" + variable + ";" \
"SELECT * from COMPANY";
I've googling around however I couldn't really find any material on using variables in sql queries using the C language syntax. How would i go about this in the correct and safe way, to incorporate variables and without making a program vulnereable to SQL injection?
The C-API provides the functions sqlite3_prepare_v2 and sqlite3_bind so that you can bind parameters to prepared statements. What that means is, you can use a placeholder where you want to substitute parameters within a string.
Each placeholder is referenced by an index, so you can use as many parameters as you like (up to the compile-time limit set by SQLITE_MAX_VARIABLE_NUMBER). You then bind a parameter to the placeholder at a specified index.
There are a number of functions and methods to accomplish parameter substitution, but to get you started, here's an example which binds an integer to the 1st placeholder in an sql statement:
int rc;
sqlite3 *db;
sqlite3_stmt *stmt = NULL;
...
// here I assume you open the db, and provide any other working code as needed...
...
// the employee id number.
int id_num;
...
// create the sql statement, with a single placeholder marked by '?'.
char *sql = "UPDATE COMPANY set SALARY = 25000.00 where ID=?";
// prepare the sql statement.
rc = sqlite3_prepare_v2(db, sql, strlen(sql)+1, &stmt, NULL);
if (rc != SQLITE_OK) {
printf("Failed to prepare statement: %s\n\r", sqlite3_errstr(rc));
sqlite3_close(db);
return 1;
}
else {
printf("SQL statement prepared: OK\n\n\r");
}
// bind an integer to the parameter placeholder.
rc = sqlite3_bind_int(stmt, 1, id_num);
if (rc != SQLITE_OK) {
printf("Failed to bind parameter: %s\n\r", sqlite3_errstr(rc));
sqlite3_close(db);
return 1;
}
else {
printf("SQL bind integer param: OK\n\n\r");
}
// evaluate the prepared statement.
rc = sqlite3_step(stmt);
// other successful return codes are possible...
if (rc != SQLITE_DONE) {
printf("Failed to execute statement: %s\n\r", sqlite3_errstr(rc));
sqlite3_close(db);
return 1;
}
// deallocate/finalize the prepared statement when you no longer need it.
// you may also place this in any error handling sections.
sqlite3_finalize(stmt);
...
// close the db when finished.
sqlite3_close(db)
...
// finish your code.
The function below is supposed to check whether or not a specific entry exists in a table. If the entry exists, it returns a 1. If it doesn't, it returns a 0. However, it only returns a 0.
Table used: Database( ID int Primary Key, char(100) Place, char(100) Room ), all are NOT NULL. All of the queries shown in the results below are in Database.
//database is already open at this point
int searchForRoom(sqlite3 *db, char *place, char *room){
int result = 1;
sqlite3_stmt *stmt;
//Create SQL statement
char * sql = sqlite3_mprintf(
"Select EXISTS(Select * From Database "
"Where Place = '%q' and Room = '%q');"
, place, room);
sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL);
if (sqlite3_step(stmt) != SQLITE_ROW) {
printf("ERROR 1 reading data: %s\n", sqlite3_errmsg(db));
}
//only this line of code does not output the correct result
result = sqlite3_column_int(stmt, 0);
if (sqlite3_step(stmt) != SQLITE_DONE) {
printf("ERROR 2 reading data: %s\n", sqlite3_errmsg(db));
}
printf("%s, %s evals to %d\n", place, room, result);
sqlite3_finalize(stmt);
return result;
}
The result:
place1, venue1 evals to 0
place2, venue2 evals to 0
place3, venue3 evals to 0
"Select EXISTS(Select * From Database "
The EXISTS query returns either 0 (when no such row(s) exist) or 1 (when they do). It returned 0, so no such rows existed.
I don't know why or how, but it seems that restarting my computer actually solved the problem. The function now works perfectly fine. Sorry for wasting everyone's time.
I have to insert a string into a sqlite data base
my command ..
Err=sqlite_exec(DB, "create table tbl5(TEXT varchar(100));", xCallback, (void*)"First Test", &ErrMsg);
Err=sqlite_exec(DB, "insert into tbl5 values ('some string');", xCallback, (void*)"First Test", &ErrMsg);
works fine but when I want to put s="some string" ie
Err=sqlite_exec(DB, "insert into tbl5 values (s);", xCallback, (void*)"First Test", &ErrMsg);
then this is not working so how to add variable then It is not working so how to insert variable in sqlite database
thank u
Don't use sprintf() but sqlite3_mprintf(). Here is the documentation.
char s[20] = "some string";
char* query = sqlite3_mprintf("insert into tbl5 values ('%q');", s);
Otherwise you have a risk of SQL injection.
The resulting query string should be freed using sqlite3_free().
Also note the '%q' instead of the usual '%s'.
Other than the suggestions already given, you can also use prepared statements with bound parameters (this is also useful if you intend to repeat the statement several times with different parameters). see the sqlite3_prepare_v2 and sqlite3_bind_* for more information
sqlite3_stmt *stmt;
// Create a prepared statement.
Err = sqlite3_prepare_v2(DB, "insert into tbl5 values (?)", -1, &stmt, NULL);
if (Err != SQLITE_OK)
{
//...
}
// Bind our string to the statement.
Err = sqlite3_bind_text(stmt, 1, "some string", -1, SQLITE_TRANSIENT);
if (Err != SQLITE_OK)
{
//...
}
// Execute the statement.
Err = sqlite3_step(stmt);
if (Err != SQLITE_DONE)
{
//...
}
// Free the prepared statement.
Err = sqlite3_finalize(stmt);
You could use sprintf to create a formatted string.
char s[20] = "some string";
char query[100];
sprintf(query, "insert into tbl5 values (%s);", s);
It's up to you to make sure query is big enough.