My goal is to have a successful SQLite3 close after an open from functions I created.
I expected the close to return a code of zero.
I'm passing the SQLite3 *db pointer after a successful open to a function of my
construction having an rc = sqlite3_close(db)
. Seems in the act of passing the
db pointer something is lost and the close errors out. As a design feature I intend
to have many functions built around SQLite's db call functions so getting just a
simple open and close to work helps me in the future. This may just be a
miss-understanding on how to pass a pointer to a function.
The errors generated after code run:
Return code: 0 |Error code: 0 |Error message: not an error |Message: Database open success
New message -->Return code: 0 |Message: Database close success
Old message -->Return code: 21 |Error code: 21 |Error message: bad parameter or other API misuse |Message: Database close failed
My code:
#include <iostream>
#include <string>
#include <sqlite3.h>
using namespace std;
// Function prototypes
int openDB(sqlite3**, string); // Mod - Added additional *
int closeDB(sqlite3**); // Mod - Added additional *
int main()
{
**// Open database**
sqlite3 *db;
string errmsg;
int rc;
string dbStr = "/home/steven/sparks-robotics/data/myDB.db";
const char* database = dbStr.c_str();
rc = openDB(&db,database); // Mod - Added &
if (rc != EXIT_SUCCESS) {return EXIT_FAILURE;}
**// Close database**
rc = closeDB(&db); // Mod - Added &
if (rc != EXIT_SUCCESS) {return EXIT_FAILURE;}
return 0;
};
int openDB(sqlite3 **db, string dbStr) { // Mod - Added *
int rc; // SQLite return code
const char* em; // SQLite error message
int ec; // SQLite error code
string errmsg;
const char* database = dbStr.c_str();
rc = sqlite3_open_v2(database, &*db, SQLITE_OPEN_READONLY, NULL); // Mod - Added *
errmsg = "Database open success";
ec = sqlite3_errcode(*db); // Mod - Added *
em = sqlite3_errmsg(*db); // Mod - Added *
if(rc != SQLITE_OK) {errmsg = "Database open failed";}
cout << "Return code: " << rc <<" |Error code: " << ec << " |Error message: " << em << " |Message: " errmsg << endl;
return rc;
};
int closeDB(sqlite3 **db) { // Mod - Added *
int rc; // SQLite return code
//const char* em; // SQLite error message // Mod - Deleted
//int ec; // SQLite error code // Mod - Deleted
string errmsg;
rc = sqlite3_close(*db); // Mod - Added *
errmsg = "Database close success";
//ec = sqlite3_errcode(*db); // Mod - deleted, db already closed
//em = sqlite3_errmsg(*db); // Mod - deleted, db already closed
if(rc != SQLITE_OK) {errmsg = "Database close failed";}
//cout << "Return code: " << rc <<" |Error code: " << ec << " |Error message: " << em << " |Message: " errmsg << endl;
cout << "Return code: " << rc << " |Message: " errmsg << endl;
return rc;
};
CodePudding user response:
As I wrote in my comment, changes to db
in openDB
do not show up in the variable db
in main
. There are two important things to understand:
- Pointer variables have an address like any other variable, but their value is also an address.
- C defaults to "pass by value"
I will explain the problem by interpreting your code myself:
- Before the call to
openDB
, thedb
inmain
(henceforthmain_db
) has address=0xMAIN_DB and value=GARBAGE (because you failed to initialize it) - At the start of
openDB
,openDB_db
has address=0xOPENDB_DB (different frommain_db
) and value=GARBAGE (because C is pass by value) - You call
sqlite3_open
with&openDB_db
, so it dutifully writes a new value to address 0xOPENDB_DB. 0xMAIN_DB is untouched.
By contrast, if you change the signature of openDB
to take a sqlite3 *&
, openDB_db
is a reference to main_db
, which means that openDB_db
will have the same address as main_db
: 0xMAIN_DB. When you now pass &openDB_db
to sqlite3_open
, it will effectively write a pointer value into 0xMAIN_DB
, which means that main_db
also has that pointer value.