Get return codes from sql operations - c++

I am using sqlite library for C++ to work with database. I want to get return values from sqlite3_exec() function as used in below code.
For eg., if I execute a "DELETE from COMPANY where id=2;", I want to distinguish between the results of this query(it it deleted an existing row or it didn't or if the table exists or not).
All I am able to do using below code is execute the SQL statement. Is it possible to do this?
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
static int callback(void *data, int argc, char **argv, char **azColName){
int i;
fprintf(stderr, "%s: ", (const char*)data);
for(i=0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main(int argc, char* argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
const char* data = "Callback function called";
/* Open database */
rc = sqlite3_open("test.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stderr, "Opened database successfully\n");
}
/* Create merged SQL statement */
sql = "DELETE from COMPANY where ID=2; " \
"SELECT * from COMPANY";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}else{
fprintf(stdout, "Operation done successfully\n");
}
sqlite3_close(db);
return 0;
}

Related

Segmentation Fault SQLite Backup

I want to backup the SQLite database from my file system to in memory database using C++. I read this website and try the example 1. It compiled perfectly but I get an error "Segmentation Fault". The code looks like this:
Ps: The last line printf("foo1"); is not printed
#include <stdio.h>
#include <sqlite3.h>
#include <nlohmann/json.hpp>
using namespace std;
using json = nlohmann::json;
static int callback(void *NotUsed, int count, char **data, char **column) {
int i;
int lastEntry = count - 1;
printf("{");
for (i=0; i<count; i++) {
if (i == lastEntry ) {
printf("\"%s\" : \"%s\"", column[i], data[i] ? data[i] : "NULL");
} else {
printf("\"%s\" : \"%s\",", column[i], data[i] ? data[i] : "NULL");
}
}
printf("}\n");
return 0;
}
int loadOrSaveDb(sqlite3 *pFile, const char *zFilename, int isSave){
int rc; /* Function return code */
sqlite3 *pInMemory; /* Database connection opened on zFilename */
sqlite3_backup *pBackup; /* Backup object used to copy data */
sqlite3 *pTo; /* Database to copy to (pFile or pInMemory) */
sqlite3 *pFrom; /* Database to copy from (pFile or pInMemory) */
/* Open the database file identified by zFilename. Exit early if this fails
** for any reason. */
rc = sqlite3_open(zFilename, &pFile);
if( rc==SQLITE_OK ){
pFrom = (isSave ? pInMemory : pFile);
pTo = (isSave ? pFile : pInMemory);
pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
if( pBackup ){
(void)sqlite3_backup_step(pBackup, -1);
(void)sqlite3_backup_finish(pBackup);
}
printf("foo");
rc = sqlite3_errcode(pTo);
}
/* Close the database connection opened on database file zFilename
** and return the result of this function. */
(void)sqlite3_close(pFile);
return rc;
}
int main(int argc, char* argv[]) {
sqlite3 *db;
char *zErrMsg = 0;
int rc;
string sql;
/* Open Database */
rc = sqlite3_open("test.db", &db);
if( rc ) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return(0);
} else {
fprintf(stderr, "Opened database successfully\n");
}
/* Create SQL Statement */
sql = "CREATE TABLE COMPANY(" \
"ID INT PRIMARY KEY NOT NULL," \
"name TEXT NOT NULL," \
"AGE INT NOT NULL," \
"ADDRESS CHAR(50)," \
"SALARY REAL );";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql.c_str(), callback, 0, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
fprintf(stdout, "Table created successfully\n");
}
/* Insert SQL statement */
sql = "INSERT INTO COMPANY " \
"VALUES (1, 'Paul', 32, 'California', 20000.00 ); " \
"INSERT INTO COMPANY " \
"VALUES (2, 'Allen', 25, 'Texas', 15000.00 ); " \
"INSERT INTO COMPANY " \
"VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );" \
"INSERT INTO COMPANY " \
"VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql.c_str(), callback, 0, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
fprintf(stdout, "Records created successfully\n");
}
/* Select SQL statement */
//sql = "SELECT * from COMPANY WHERE NAME LIKE 'Paul'";
sql = "SELECT * from COMPANY";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql.c_str(), callback, 0, &zErrMsg);
if( rc != SQLITE_OK ) {
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
fprintf(stdout, "Operation done successfully\n");
}
loadOrSaveDb(db, "test.db", 0);
sqlite3_close(db);
printf("foo1");
return 0;
}
The destination for sqlite3_backup_init has to be a database connection handle. In order to use sqlite3 *pInMemory; as the destination, you should initialise it with such a handle:
sqlite3 *pInMemory; /* Database connection opened on zFilename */
sqlite3_open(":memory:", &pInMemory);

how to write the result of sqlite3_exec not in stdout

I need to execute sql command "select" and return some data from the result of it. I'm trying to do it with sqlite3_exec, but it's only writting in stdout. What I need to do to write the data in array or something like this?
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
int i;
for(i=0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
void my_exec(char * sql) {
sqlite3 *db;
char *zErrMsg = nullptr;
int rc;
//char * sql;
/* Open database */
rc = sqlite3_open("data_base.db", &db);
if (rc) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
} else {
fprintf(stdout, "Opened database successfully\n");
}
/* Create SQL statement */
// sql
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, nullptr, &zErrMsg);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
fprintf(stdout, "Success\n");
}
/* Close database */
sqlite3_close(db);
}
Let's look at the fourth parameter of sqlite3_exec(). This is a pointer that is passed to the callback function. Give sqlite3_exec() a pointer to your data structure and store the results to that pointer in the callback.
You can for example use a vector:
std::vector<std::pair<std::string, std::string>> vec;
rc = sqlite3_exec(db, sql, callback, &vec, &zErrMsg);
The callback:
static int callback(void *dataPtr, int argc, char **argv, char **azColName){
auto vec = static_cast<std::vector<std::pair<std::string, std::string>>*>(dataPtr);
int i;
for(i=0; i<argc; i++){
vec->push_back({azColName[i], argv[i] ? argv[i] : "NULL"});
}
return 0;
}

sqlite3 Program received signal SIGSEGV, Segmentation fault in sqlite3_get_table ()

I have pasted my code below. It gives seg fault at sqlite3_get_table (). I want to get the number of row in table and return that. If number of row is greater than 0, the program needs to read all rows.
int countRowsInTable()
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char const *sql;
char ***pazResult;
int *pnRow; /* Number of result rows written here */
int *pnColumn; /* Number of result columns written here */
rc = sqlite3_open("DeviceDetails.db", &db);
if( rc )
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return(0);
}
else
{
fprintf(stderr, "Opened database successfully\n");
}
/* Create SQL statement */
sql = "select * from Device_Details";
/* Execute SQL statement */
// rc = sqlite3_exec(db, sql, 0/*callback*/, 0/*(void*)data*/, &zErrMsg);
rc = sqlite3_get_table(db, sql, pazResult, pnRow, pnColumn, &zErrMsg);
void sqlite3_free_table(char **result);
if( rc != SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
else
{
fprintf(stdout, "Operation done successfully\n");
cout<<"rows="<<pnRow<<endl;
sleep(10);
}
sqlite3_close(db);
cout<<"num rows =" << *pnRow <<endl;
}
after reading your suggestion I have changed my code. Now I use select count (*), but where (which) variable will hold the number of rows. Do, I need to implement the callback function in sqlite3_exec. Also I need to get data if row count is greater than zero.If I get the data in call back function, how to pass it to the function calling countRows in table? may be I can keep a global variable. As soon as call back is executed , it will signal the calling function through condition variable. So I have to maintain countRowsInTable function in a new thread. I there any simpler approach?
int countRowsInTable()
{
sqlite3 *db;
char *zErrMsg = new char[64];
int rc;
char const *sql;
char ***pazResult;
int *pnRow = new int; /* Number of result rows written here */
int *pnColumn = new int; /* Number of result columns written here */
//*pnRow = 0;
**pazResult = new char[20480];
rc = sqlite3_open("DeviceDetails.db", &db);
if( rc )
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return(0);
}
else
{
fprintf(stderr, "Opened database successfully\n");
}
/* Create SQL statement */
sql = "select count(*) from Device_Details";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, 0/*callback*/, 0/*(void*)data*/, &zErrMsg);
//rc = sqlite3_get_table(db, sql, pazResult, pnRow, pnColumn, &zErrMsg);
//void sqlite3_free_table(char **result);
if( rc != SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
else
{
fprintf(stdout, "Operation done successfully\n");
}
}
Your are not calling the function with the right parameters. You are passing uninitialized pointers, whereas you must create the variables and pass pointers on them so SQLite can write the values.
const char *sql = "select * from Device_Details";
char **result;
int nrow;
int ncolumn;
char *errmsg;
int rc;
rc = sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg);
However, you should be aware the SQLite manual discourage the use of the function: "This is a legacy interface that is preserved for backwards compatibility. Use of this interface is not recommended."
Also, you should remove void sqlite3_free_table(char **result) that you probably pasted by mistake.

MSVC2017 Statically linking SQLite3

I have a Microsoft Visual Code 2017 console application which I want to link statically against sqlite3. I have linked the sqlite3.lib file and included the sqlite3.h file. However, when I execute the program it still pops-up the message that it is missing sqlite3.dll. I thought that sqlite3 would be linked statically, what am I doing wrong?
Compiling goes without errors
This is my code:
#include "stdafx.h"
#include "sqlite3.h"
#pragma comment(lib, "sqlite3.lib")
static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
int i;
for(i=0; i<argc; i++) {
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main(int argc, _TCHAR* argv[]) {
sqlite3 *db;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open("test.db", &db);
if( rc ) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}
rc = sqlite3_exec(db, "create table stuff ( name )", callback, 0, &zErrMsg);
rc = sqlite3_exec(db, "insert into stuff values ('hello')", callback, 0, &zErrMsg);
rc = sqlite3_exec(db, "select * from stuff", callback, 0, &zErrMsg);
if(rc != SQLITE_OK) {
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
sqlite3_close(db);
return 0;
}
You can include the sqlite3.c file alongside your other .c or .cpp files. This is a single large file for the whole thing. Then it will be statically linked without dealing with .lib or .dll files.

sqlite3_exec callback is not called

I have to check if a table exists before it is created, by reading
How do I check in SQLite whether a table exists?, I use sqlite3_exec to do one step query with
SELECT name FROM sqlite_master WHERE type = 'table' AND name
='table1';
and use the callback to set a flag to identify the table exists or not.
Unfortunately, the callback will not be called, if the table is not yet created.
Why the callback is not being called? I know that callback is not called for queries without output results, e.g. "create table" etc, and only called with "SELECT" queries. But I am not aware that it may not even be called for "SELECT".
The following is the code sample to reproduce the problem.
#include <stdio.h>
#include <sqlite3.h>
bool isExist=false;
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
printf("I am being called\n");
if (argc>0) isExist = true;
return 0;
}
int main(int argc, char **argv){
sqlite3 *db;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open("test.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return(1);
}
//char* sqlCreateTable = "CREATE TABLE table1(name TEXT);";
//rc = sqlite3_exec(db, sqlCreateTable, callback, 0, &zErrMsg);
// callback will not be called if table is not yet created
char* sql_hasTable = "SELECT name FROM sqlite_master WHERE type = 'table' AND name ='table1';";
rc = sqlite3_exec(db, sql_hasTable, callback, 0, &zErrMsg);
if( rc!=SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
sqlite3_close(db);
return 0;
}