I'm trying to link sqlite3 library to CMakeList in Clion using the following code:
find_package(SQLite3)
target_link_libraries(IIWProject SQLite::SQLite3)
Library has been loaded but when i Run the code, Clion shows the following error:
SQL logic error
The database has been loaded but when sqlite3_prepare_v2(db, query, -1, &stmt, NULL) was called return SQL logic error
void get_db(sqlite3 **db){
int rc;
if ((rc = sqlite3_open("db_project.db", db)) != SQLITE_OK){
//fprintf(stderr, "Failed to open DB.\n");
fprintf(stderr,"Failed to open DB: %s\n\r", sqlite3_errstr(rc));
exit(EXIT_FAILURE);
}
}
int clear_table(sqlite3 *db){
sqlite3_stmt *stmt;
int rc;
char* query = "DELETE FROM resources";
if ((rc=sqlite3_prepare_v2(db, query, -1, &stmt, NULL)) != SQLITE_OK){
fprintf(stderr,"Failed to prepare statement: %s\n\r", sqlite3_errstr(rc));
return 1;
}
if ((rc = sqlite3_step(stmt)) != SQLITE_DONE){
fprintf(stderr,"Delete failed: %s\n\r", sqlite3_errstr(rc));
return 1;
}
return 0;
}
How can I try to fix it?
EDIT:
If I compile, without Clion manually, with gcc -lsqlite3,it work
Now that we've established that the table doesn't exist when you run your program though your IDE...
The current working directory when you run your program through a command line is different than the current working directory your IDE runs it in. Since you're using a relative path to the database file, this means you're using a different one depending on how you run your program. Only one of the databases actually has the table(s) you're trying to use.
Some solutions:
Use an absolute path to the database.
Configure your IDE to use the same working directory as when you're running your program through a command line.
Related
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?
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.
https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html#defense-option-1-prepared-statements-with-parameterized-queries
How to use prepared statements with SQLite
For prepared statements see https://www.sqlite.org/c3ref/stmt.html.
Basic steps are:
create the prepared statement
bind values to parameters
run the SQL
destroy the object to avoid resource leaks
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
I'm trying to display history of firefox and chrome using C Application .For the history of chrome , it works well because the Sql command doesn't contain symbols but with chrome My sql request contains symbols , So this function doesn't give me result .It give me error :
no such table :moz_historyvisits
Or ,when i test this request from the command prompt it works well . What i think that the problem is the sql request contains (_)symbols .
Rq : For chrome history it works well . CallbackFirefox is to function to display result
I'm using windows and Code blocks as an IDE . When i execute select name from sqlite_master
int DisplayFirefoxHistory()
{
sqlite3 *db;
char *err_msg = 0;
system("cd C:/Users/******/AppData/Roaming/Mozilla/Firefox/Profiles/*.default");
int rc = sqlite3_open("places.sqlite", &db);
if (rc != SQLITE_OK) {
fprintf(stderr, "Cannot open database: %s\n",sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}
char *sql = "select url,datetime(visit_date/1000000-11644473600,'unixepoch') from moz_historyvisits,moz_places order by visit_date desc";
rc = sqlite3_exec(db, sql, callbackFirefox, NULL, &err_msg);
if (rc != SQLITE_OK ) {
fprintf(stderr, "Failed to select data\n");
fprintf(stderr, "SQL error: %s\n", err_msg);
sqlite3_free(err_msg);
sqlite3_close(db);
return 1;
}
sqlite3_close(db);
return 0;
}
system("cd C:/Users/******/AppData/Roaming/Mozilla/Firefox/Profiles/*.default");
system() starts a separate shell that is terminated after the command was executed, so this does not change the current directory of your actual program.
You should find out the directory name manually, and include it in the database file name.
I know there have been questions asked before about this problem but none seem to shine a light on my problem which is, I am trying to compile a C application and want to access SQLite from within the code (as per test app below) using Eclips as a compile and debugging environment.
I know the .h files are being accessed. the code has as many lines commented out to do with iostream as I have tried to compile this as a C++ app as well.
I get errors one for each of 2 the SQL API.
The real question is do I have to set and How do I set a dependency in Eclipse to allow the api to resolve. Thanks
the code
#include <sqlite3.h>
int main()
{
int RetVal;
RetVal = OpenDB();
return RetVal;
}
int OpenDB()
{
sqlite3 *db; // database connection
int rc; // return code
char *errmsg; // pointer to an error string
/*
* open SQLite database file test.db
* use ":memory:" to use an in-memory database
*/
rc = sqlite3_open(":memory:", &db); //fails on this line
if (rc != SQLITE_OK)
{
goto out;
}
/* use the database... */
out:
/*
* close SQLite database
*/
sqlite3_close(db); //fails on this line
return 0;
}
You need to link the sqlite3 library along with your program:
gcc main.c -lsqlite3
I'm having memory management related crashes when using SQLite. It only crashes once every 30 or so tries unless I enable Guard Malloc (a test mode) in Xcode, in which case it crashes the second time I prepare a statement, 100% of the time. I think it has to do with how I'm opening or using the database, but I can't find anything wrong, BUT I'm a newbie with SQLite. Is there anything I'm forgetting?
Wrapper function for opening:
int databaseConnect(sqlite3 **db){
int rc = sqlite3_open_v2(dbURL, db, SQLITE_OPEN_READWRITE, NULL);
if(rc!=SQLITE_OK){
fprintf(stderr, "Can't open database! Error: %s\n", sqlite3_errmsg(*db));
sqlite3_close_v2(*db);
return(SQL_ERROR);
}
return NO_ERROR;
}
Wrapper function for sending commands:
int databaseCommand(char* command, sqlite3* db){
char* error = NULL;
int ret = sqlite3_exec(db, command, NULL, 0, &error);
if (ret!=SQLITE_OK){
printf("SQL command aborted. Error: %s\n", error);
return SQL_ERROR; //EDIT: this will cause the database to close later
}
if (error) sqlite3_free(error);
return NO_ERROR;
}
How I use my opening function:
//ONCE IN MAIN THREAD, BEFORE ANY OTHER THREADS:
sqlite3* db = NULL;
databaseConnect(&db);
//call databaseCommmand a few times while creating tables...
sqlite3_close_v2(db);
//ONCE PER THREAD IN OTHER THREADS:
sqlite3* db = NULL; databaseConnect(&db);
How I use sqlite3_prepare_v2 in my non-main threads (and where it crashes):
struct LinkedList* databaseSelect(char* command, sqlite3* db){
sqlite3_stmt* stmt = NULL;
int retval = retval = sqlite3_prepare_v2(db,command,(strlen(command))*sizeof(char),&stmt,NULL); //crashes here the second time I run it
if(retval!=SQLITE_OK){
printf("Selecting data from database failed! Error: %s\n", sqlite3_errmsg(db));
sqlite3_free(stmt);
return NULL; //EDIT: this will cause the database to close later
}
// Then the function does stuff involving sqlite3_column_text and sqlite3_column_int…
sqlite3_free(stmt);
// return the linked list result
}
The error I get and the part of the SQLite3 library that causes it:
EXC_BAD_ACCESS (code=1) in this part of sqlite3.c:
/*
** Create a new virtual database engine.
*/
SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
Vdbe *p;
p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
if( p==0 ) return 0;
p->db = db;
if( db->pVdbe ){
db->pVdbe->pPrev = p; //error is right here; db->pVdbe is pointing to invalid address
}
p->pNext = db->pVdbe;
p->pPrev = 0;
db->pVdbe = p;
p->magic = VDBE_MAGIC_INIT;
return p;
}
Whenever I use sqlite3_column_text, I copy the result immediately. I do not modify the result. In databaseCommand and databaseSelect, char* command is null-terminated and valid (I checked). Each thread uses its own database handle, each connected to the same database. However, in this test case, there is only one thread connected to the database at any given time.
If there really is nothing wrong here, I have to assume that I trampled the memory elsewhere in my program, and I can't find anything in the rest of the program that even looks a bit dangerous. Plus it's suspicious that SQLite is the one thing crashing every time.
The sqlite3_prepare_v2 documentation says:
The calling procedure is responsible for deleting the compiled SQL statement using sqlite3_finalize() after it has finished with it.
sqlite3_free() can be used only for raw memory allocated with sqlite3_alloc(), or when a function such as sqlite3_exec() is documented as requiring it.
Since you are using multiple threads operating on same database just make sure you close and reopen the database from these thread after every operation. You should also try not to neglect the error condition and add the close statement there also as shown below.
if(retval!=SQLITE_OK){
printf("Selecting data from database failed! Error: %s\n", sqlite3_errmsg(db));
sqlite3_free(stmt);
sqlite3_close(your_db_ptr);
......
}
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. From here.
Hope this helps.
So, I have a tiny fragment of C code running on a windows box, that reads:
/* invoke command */
impl->procHandle = _spawnve(_P_NOWAIT, command, vargs, env);
if (impl->procHandle == -1) {
printf("Failed to invoke command: %s\n", strerror(errno));
impl->busy = false;
}
printf("VICTORY\n");
I wrote some unit tests around this where my "command" was C:\windows\system32\ipconfig.exe and it works, no problem.
Tried to use it for an application launcher... doo doo. Failed with the helpful error:
The application failed to initialize properly (0xc0150004).
Click on OK to terminate the application.
Ok... searching around I discovered that the error code is STATUS_SXS_ASSEMBLY_NOT_FOUND, and it happens when I try to launch notepad.exe as well. Missing assemblies?
Why is this happening?
How can I work around it?
I'm just guessing here, but I suspect it has something to do with needing the PATH variable to be set in the _spawnve(), but I dont know what it should be. I tried passing in the path, but that doesn't seem to help. Running this code:
int offset = 0;
while (vargs[offset] != NULL) {
printf("vargs %d: %s\n", offset, vargs[offset]);
++offset;
}
offset = 0;
while (env[offset] != NULL) {
printf("env %d: %s\n", offset, env[offset]);
++offset;
}
Yeilds:
vargs 0: C:\windows\system32\notepad.exe
env 0: PATH=c:\WINDOWS\system32
ie. I am passing in argv[0], and a path value; not other env variables or arguments.
Any ideas?
--
Edit:
So, it seems this error is occurring because the PATH is not correctly set when I invoke the command using _spawnve().
This is made obvious by invoking either _spawnv() or _spawnvpe(), both of which seem to work correctly.
However, that doesn't really help me, because I need to specify an additional PATH component for the application when it runs. Passing PATH=... into _spawnvpe() causes the same error, and obviously _spawnv is no used because it doesn't allow you to specify the PATH.
So really, the answer to this question is: Because the PATH variable is wrong.
...but I still have no idea what it should be. There seem to be no working examples of this that I can find anywhere. I'll accept any answer that links to an example of coding using _spawnve() or _spawnvpe() and passing the PATH variable into it (and working).
Edit #2:
Really. No, actually, this doesn't work. Here's an example of it not working. Forget linking to an example that works; just modify my example and post a diff that 1) passes in PATH and 2) runs without an error.
Nb. Want to see it work? change to _spawnv() or make the env value NULL and it runs just fine.
#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <errno.h>
int main(int argc, char *argv[]) {
char *path_value;
char buffer[4000];
const char *env[2];
const char *args[1];
char *command;
int result;
intptr_t procHandle;
path_value = getenv("PATH");
sprintf(buffer, "PATH=%s", path_value);
env[0] = buffer;
env[1] = NULL;
args[0] = NULL;
int offset = 0;
while (env[offset] != NULL) {
printf("env %d: %s\n", offset, env[offset]);
++offset;
}
offset = 0;
while (args[offset] != NULL) {
printf("arg %d: %s\n", offset, args[offset]);
++offset;
}
command = "C:\\windows\\system32\\notepad.exe";
procHandle = _spawnvpe(_P_NOWAIT, command, args, NULL);
if (procHandle == -1) {
printf("Failed to invoke command: %s\n", strerror(errno));
exit(1);
}
_cwait(&result, procHandle, 0);
if (result != 0)
printf("Command exited with error code %d\n", result);
}
Output:
env 0: PATH=.;c:\Program Files\Common Files\Microsoft Shared\Windows Live;c:\WINDOWS\system32;c:\WINDOWS;c:\WINDOWS\System32\Wbem;c:\Program Files\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\DTS\Binn\;c:\Program Files\CMake 2.8\bin;c:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;c:\Program Files\Common Files\Microsoft Shared\Windows Live
Command exited with error code -1072365564
This is wrong:
const char *args[1];
args[0] = NULL;
you need
const char *args[2];
args[0] = "notepad";
args[1] = NULL;
Other than that, your example code works, at least when compiled with Visual Studio 2010. I've tested it on both Windows 7 and Windows XP, and it works. Notepad runs.
What compiler are you using?
You are right, the second parameter to _spawnev() takes the name of the app to be executed inlcuding its full path.
To get around to know the path you could call the command processer cmd.exe and pass it along the name of the app to execute as a parameter to it using cmd.exe's option /C.
This works in all the cases where you could have started the application out of one of cmd.exe's command line windows.
cmd.exe knows the value of the environment variable PATH and used it to search through it for the app's path to start.
The path to cmd.exe itself could be read from the environment variable COMSPEC.
Update: For more on this issue (including examples) please read here.
As specified here _spawn, _wspawn Functions, only the functions with a 'p' letter in the name implicitely use the PATH environment variable. The others don't.
So you need to do this:
char *args[] = {"notepad.exe", NULL };
_spawnvpe(_P_NOWAIT, args[0], args, NULL);