sqlite3 one_file VFS Fails - c

I was trying to run test_onefile.c example from sqlite3 VFS examples, and I get the following failure:
test_onefile: test_onefile.c:693: fsDelete: Assertion `strpcmp("-journal", &zPath[nName])==0' failed.
I'm running the code as follows:
int retval;
fs_register();
int q_cnt = 5,q_size = 150,ind = 0;
char **queries = (char**) malloc(sizeof(char) * q_cnt * q_size);
sqlite3_stmt *stmt;
sqlite3 *handle;
retval = sqlite3_open_v2( "sampledb.sqlite2", &handle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE , "fs");
if(retval)
{
printf("Database connection failed\n");
return -1;
}
printf("Connection successful\n");
// Create the SQL query for creating a table
char create_table[100] = "CREATE TABLE IF NOT EXISTS users (uname TEXT,pass TEXT NOT NULL,activated INTEGER)";
// Execute the query for creating the table
retval = sqlite3_exec(handle,create_table,0,0,0);
// Insert first row and second row
queries[ind++] = "INSERT INTO users VALUES('manish','mani',1)";
retval = sqlite3_exec(handle,queries[ind-1],0,0,0);
queries[ind++] = "INSERT INTO users VALUES('mehul','pulsar',0)";
retval = sqlite3_exec(handle,queries[ind-1],0,0,0);
Edit:
The file it fails on is sampledb.sqlite2-wal, clearly not a journal file. However, I don't understand how it reached it.
Edit2:
Well, after removing the assertion in source file:
assert(strcmp("-journal", &zPath[nName])==0);
The code seems to work. However, I'm not a big fan of assertion deletion, as clearly it would lead to some unexpected behavior. The author had a reason to use the assertion.

The VFS implemented by test_onefile.c is quite old, and therefore does not support the additional files required for WAL mode.
To make it work with a modern SQLite, the fsDelete function should just ignore attempts to delete -wal or -shm files.

Related

How to get COUNT(*) value from sqlite3_exec()?

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.

C - How to use variables as part of an SQL Query?

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.

SQLite3: the database was created empty?

I'm trying to create a database with a table using sqlite3 on my C program, however the database is always created as empty, though it was created non-empty using the sqlite shell,
here is my code below:
int main(void)
{
printf("hello\n");
sqlite3 *sqdb;
sqlite3_initialize();
const char* db = "test";
sqlite3_open(db, &sqdb);
const char* stmt = "CREATE TABLE IF NOT EXISTS testtable(creationdate DATE, data VARCHAR);";
sqlite3_stmt *ppstmt;
if (sqlite3_prepare_v2(sqdb, stmt, -1, &ppstmt, 0)!=SQLITE_OK)printf("error!\n");
sqlite3_finalize(ppstmt);
getch();
return 0;
}
please help me to solve the problem.
sqlite3_prepare_v2() alone just compiles the SQL but does not run it. Call sqlite3_step() on the compiled statement to run it, or use sqlite3_exec() that combines prepare+step+finalize into one function call.
Try this:
int main(void)
{
printf("hello\n");
sqlite3 *sqdb;
int ret;
sqlite3_initialize();
const char* db = "test.sqlite3";
sqlite3_open(db, &sqdb);
const char* stmt = "CREATE TABLE IF NOT EXISTS testtable(creationdate DATE, data VARCHAR);";
sqlite3_stmt *ppstmt=NULL;
ret=sqlite3_exec(sqdb,stmt,0,0,0);
if(ret!=SQLITE_OK)printf("error!\n");
else printf("Table added\n");
sqlite3_finalize(ppstmt);
sqlite3_close(sqdb);
return 0;
}
Please do remember to close the DB after operation.

When does the SQLite statement "PRAGMA database_list;" return an empty result set?

Using the C api with sqlite (v 3.7.13), I'm trying to list all attached databases of the current connection:
sqlite3_stmt* pCompiledSql;
if(SQLITE_OK == sqlite3_prepare_v2(database, "PRAGMA database_list;", -1, &pCompiledSql, nullptr))
{
while(SQLITE_ROW == sqlite3_step(pCompiledSql))
{
const char* pName = reinterpret_cast<const char*>(sqlite3_column_text(pCompiledSql, 1));
const char* pFile = reinterpret_cast<const char*>(sqlite3_column_text(pCompiledSql, 2));
// Using pName and PFile...
}
}
Where database is a handle to an existing database with several databases attached. The same code works fine with statements like "SELECT * FROM testtable;"
However with the pragma call the first step call will just return an SQLITE_DONE straight away.
I'm pretty sure I'm ovelooking something obvious but without much experience with SQLite I'm stuck now... What can possibly go wrong here?
The fourth parameter of sqlite3_prepare_v2 is a pointer to the statement pointer, so it must not be pCompiledSql but &pCompiledSql.
Your compiler should have warned you about this.

sqlite c interface persistent error qt

I want to perform a simple query (drop table) with sqlite native interface and I persistently run into SQLITE_ERROR as I try to prepare the statement. I tried everything as I was afraid of string compatibility (qt strings can be a pain sometimes) but every it always gives me the same the code is the following:
sqlite3_stmt *query;
std::string tmp = "DROP TABLE ?";
if(sqlite3_prepare_v2(db, tmp.c_str(), tmp.size(), &query, NULL) != SQLITE_OK)return FALSE;
if(sqlite3_bind_text16(query, 1, str.utf16(), -1, SQLITE_TRANSIENT) != SQLITE_OK) return FALSE;
if(sqlite3_step(query) != SQLITE_OK) {
std::cerr << sqlite3_errmsg(db);
return FALSE;
}
sqlite3_finalize(query);
I hope sincerely someone out there can help.
You can't pass table names as parameters (it applies to most database APIs supporting parameters, maybe even all database APIs).

Resources