Why does the SQLite C interface requires to pass the pointer by the reference when using BOOST_SCOPE_EXIT_ALL, for example?
Suppose that I have the following code:
#include <boost/scope_exit.hpp>
#include <sqlite3.h>
#include <cstdlib>
#include <iostream>
int main()
{
sqlite3* db;
BOOST_SCOPE_EXIT_ALL(db)
{
if (sqlite3_close(db) != SQLITE_OK)
{
std::cerr << sqlite3_errmsg(db) << '\n';
}
};
if (sqlite3_open(":memory:", &db) != SQLITE_OK)
{
std::cerr << sqlite3_errmsg(db) << '\n';
return EXIT_FAILURE;
}
sqlite3_stmt* prepared_stmt = NULL;
BOOST_SCOPE_EXIT_ALL(db, prepared_stmt)
{
if (sqlite3_finalize(prepared_stmt) != SQLITE_OK)
{
std::cerr << sqlite3_errmsg(db) << '\n';
}
};
if (sqlite3_prepare_v2(db, "CREATE TABLE IF NOT EXISTS foo(bar TEXT, baz TEXT)", -1, &prepared_stmt, 0) != SQLITE_OK)
{
std::cerr << sqlite3_errmsg(db) << '\n';
return EXIT_FAILURE;
}
if (sqlite3_step(prepared_stmt) != SQLITE_DONE)
{
std::cerr << sqlite3_errmsg(db) << '\n';
return EXIT_FAILURE;
}
}
It crashes when trying to call sqlite3_close function and doesn't print anything to the stderr. However, if I change
BOOST_SCOPE_EXIT_ALL(db)
to
BOOST_SCOPE_EXIT_ALL(&db)
it states that
unable to close due to unfinalized statements or unfinished backups
when trying to call sqlite3_close function.
If I pass the prepared_stmt by the reference too, it works as expected:
BOOST_SCOPE_EXIT_ALL(db, &prepared_stmt)
Why? I thought that the SQLite library only complains about the addresses that db and prepared_stmt points to.
Thanks in advance.
The first line in main()
sqlite3* db;
is probably why sqlite3_close() is crashing. Your compiler may be reusing a memory location for that declared pointer and may not necessarily be using a location that is null or making it null. Therefore, the call to sqlite3_close() is receiving a bogus pointer.
The docs at https://www.sqlite.org/c3ref/close.html state:
The C parameter to sqlite3_close(C) and sqlite3_close_v2(C) must be
either a NULL pointer or an sqlite3 object pointer obtained from
sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(), and not
previously closed. Calling sqlite3_close() or sqlite3_close_v2() with
a NULL pointer argument is a harmless no-op.
So, according to the above statement, the following code should remove the crash:
sqlite3* db = nullptr;
Of course, all of this would be moot if you just removed this block of unecessary code entirely:
BOOST_SCOPE_EXIT_ALL(db)
{
if (sqlite3_close(db) != SQLITE_OK)
{
std::cerr << sqlite3_errmsg(db) << '\n';
}
};
There is no reason to close a db that has never been opened.
EDIT: Here is a version of your function as I would try it. I'm really out of time right now so I can't test it, but I think it will work. I removed the boost macros since I'm unfamiliar with them, but you could add those back in. Hopefully this helps!
int main()
{
sqlite3* db = nullptr;
if (sqlite3_open(":memory:", &db) != SQLITE_OK)
goto ERROR_OCCURRED;
sqlite3_stmt* prepared_stmt = nullptr;
if (sqlite3_finalize(prepared_stmt) != SQLITE_OK)
std::cerr << sqlite3_errmsg(db) << '\n';
if (sqlite3_prepare_v2(db, "CREATE TABLE IF NOT EXISTS foo(bar TEXT, baz TEXT)", -1, &prepared_stmt, 0) != SQLITE_OK)
goto ERROR_OCCURRED;
if (sqlite3_step(prepared_stmt) != SQLITE_DONE)
goto ERROR_OCCURRED;
if (sqlite3_close(db) != SQLITE_OK)
{
std::cerr << sqlite3_errmsg(db) << '\n';
sqlite3_close(db);
return EXIT_FAILURE;
}
return 0;
ERROR_OCCURRED:
std::cerr << sqlite3_errmsg(db) << '\n';
sqlite3_close(db);
return EXIT_FAILURE;
}
Unfortunately, I'm out-of-time to check your call to sqlite3_finalize() but I also think that it's probably too early in the function. I don't see a reason to finalize a null pointer.
Related
I am working on a school project which involves SQLite3.
I've created a bunch of functions for my DatabaseManager class which all work quite good.
Now, after adding a function with a DELETE statement, sqlite3_step() returns SQLITE_BUSY and the sqlite3_errmsg() says "Database is locked".
Before opening this function I have already called sqlite3_finalize() and sqlite3_close().
int errorcode;
sqlite3 *db;
//sql statement
std::string statement = "DELETE FROM tbl_follower WHERE flw_ID = " + std::to_string(row);
sqlite3_stmt *binStatement;
errorcode = sqlite3_open(m_filePath.c_str(), &db);
if (errorcode != SQLITE_OK)
std::cerr << sqlite3_errmsg(db) << std::endl;
errorcode = sqlite3_prepare_v2(db, statement.c_str(), statement.size(), &binStatement, NULL);
if(errorcode != SQLITE_OK)
std::cerr << sqlite3_errmsg(db) << std::endl;
errorcode = sqlite3_step(binStatement);
if (errorcode == SQLITE_DONE)
{
sqlite3_finalize(binStatement);
sqlite3_close(db);
}
else
{
//error
std::cerr << sqlite3_errmsg(db) << std::endl;
sqlite3_finalize(binStatement);
sqlite3_close(db);
}
I am pretty sure the issue is somewhere in this code because I have already checked all of my other functions for mistakes (which all work without giving an error). My SQL statement is also correct.
"Database is locked" means that there is some other active transaction.
You probably forgot to finalize a statement in some other part of the program.
Hi I am trying to make a directory in windows with this code
header
#include <direct.h>
script
int main() {
string local = "C:/Program Files (x86)/Mail";
try
{
_mkdir (local.c_str ());
cout << "It is made?";
}
catch(invalid_argument& e)
{
cout << e.what () << " " << (char*) EEXIST;
if (e.what () == (char*) EEXIST) {
cout << e.what () << " " << (char*) EEXIST;
}
return;
}
}
The file is clearly not made, but it is also not making the error it should.
_mkdir won't throw an exception. (This is not python or boost, or any smart middleware)
Read the documentation you were referring to: it returns a value. 0 is OK, -1: error, ask why to errno
Don't ignore the return value. You probably have insufficient rights without UAC elevation to create the directory.
So I finally figured errno out, which for errno you need the <errno.h> header. The complete list of errno codes.
If you want to see what errno code something is throwing lets say
if (
_mkdir(((string)"C:/Program Files (x86)/Mail").c_str()) == 0 ||
errno == 17 /* this is the code for - File exists - */
){
// Do stuff
} else {
int errorCode = errno; // You need to save the code before anything else,
// because something else might change its value
cout << errorCode;
}
I have a multi-threaded C++03 application that presently uses popen() to invoke itself (same binary) and ssh (different binary) again in a new process and reads the output, however, when porting to Android NDK this is posing some issues such as not not having permissions to access ssh, so I'm linking in Dropbear ssh to my application to try and avoid that issue. Further, my current popen solution requires that stdout and stderr be merged together into a single FD which is a bit messy and I'd like to stop doing that.
I would think the pipe code could be simplified by using fork() instead but wonder how to drop all of the parent's stack/memory which is not needed in the child of the fork? Here is a snippet of the old working code:
#include <iostream>
#include <stdio.h>
#include <string>
#include <errno.h>
using std::endl;
using std::cerr;
using std::cout;
using std::string;
void
doPipe()
{
// Redirect stderr to stdout with '2>&1' so that we see any error messages
// in the pipe output.
const string selfCmd = "/path/to/self/binary arg1 arg2 arg3 2>&1";
FILE *fPtr = ::popen(selfCmd.c_str(), "r");
const int bufSize = 4096;
char buf[bufSize + 1];
if (fPtr == NULL) {
cerr << "Failed attempt to popen '" << selfCmd << "'." << endl;
} else {
cout << "Result of: '" << selfCmd << "':\n";
while (true) {
if (::fgets(buf, bufSize, fPtr) == NULL) {
if (!::feof(fPtr)) {
cerr << "Failed attempt to fgets '" << selfCmd << "'." << endl;
}
break;
} else {
cout << buf;
}
}
if (pclose(fPtr) == -1) {
if (errno != 10) {
cerr << "Failed attempt to pclose '" << selfCmd << "'." << endl;
}
}
cout << "\n";
}
}
So far, this is loosely what I have done to convert to fork(), but fork needlessly duplicates the entire parent process memory space. Further, it does not quite work, because the parent never sees EOF on the outFD it is reading from the pipe(). Where else do I need to close the FDs for this to work? How can I do something like execlp() without supplying a binary path (not easily available on Android) but instead start over with the same binary and a blank image with new args?
#include <iostream>
#include <stdio.h>
#include <string>
#include <errno.h>
using std::endl;
using std::cerr;
using std::cout;
using std::string;
int
selfAction(int argc, char *argv[], int &outFD, int &errFD)
{
pid_t childPid; // Process id used for current process.
// fd[0] is the read end of the pipe and fd[1] is the write end of the pipe.
int fd[2]; // Pipe for normal communication between parent/child.
int fdErr[2]; // Pipe for error communication between parent/child.
// Create a pipe for IPC between child and parent.
const int pipeResult = pipe(fd);
if (pipeResult) {
cerr << "selfAction normal pipe failed: " << errno << ".\n";
return -1;
}
const int errorPipeResult = pipe(fdErr);
if (errorPipeResult) {
cerr << "selfAction error pipe failed: " << errno << ".\n";
return -1;
}
// Fork - error.
if ((childPid = fork()) < 0) {
cerr << "selfAction fork failed: " << errno << ".\n";
return -1;
} else if (childPid == 0) { // Fork -> child.
// Close read end of pipe.
::close(fd[0]);
::close(fdErr[0]);
// Close stdout and set fd[1] to it, this way any stdout of the child is
// piped to the parent.
::dup2(fd[1], STDOUT_FILENO);
::dup2(fdErr[1], STDERR_FILENO);
// Close write end of pipe.
::close(fd[1]);
::close(fdErr[1]);
// Exit child process.
exit(main(argc, argv));
} else { // Fork -> parent.
// Close write end of pipe.
::close(fd[1]);
::close(fdErr[1]);
// Provide fd's to our caller for stdout and stderr:
outFD = fd[0];
errFD = fdErr[0];
return 0;
}
}
void
doFork()
{
int argc = 4;
char *argv[4] = { "/path/to/self/binary", "arg1", "arg2", "arg3" };
int outFD = -1;
int errFD = -1;
int result = selfAction(argc, argv, outFD, errFD);
if (result) {
cerr << "Failed to execute selfAction." << endl;
return;
}
FILE *outFile = fdopen(outFD, "r");
FILE *errFile = fdopen(errFD, "r");
const int bufSize = 4096;
char buf[bufSize + 1];
if (outFile == NULL) {
cerr << "Failed attempt to open fork file." << endl;
return;
} else {
cout << "Result:\n";
while (true) {
if (::fgets(buf, bufSize, outFile) == NULL) {
if (!::feof(outFile)) {
cerr << "Failed attempt to fgets." << endl;
}
break;
} else {
cout << buf;
}
}
if (::close(outFD) == -1) {
if (errno != 10) {
cerr << "Failed attempt to close." << endl;
}
}
cout << "\n";
}
if (errFile == NULL) {
cerr << "Failed attempt to open fork file err." << endl;
return;
} else {
cerr << "Error result:\n";
while (true) {
if (::fgets(buf, bufSize, errFile) == NULL) {
if (!::feof(errFile)) {
cerr << "Failed attempt to fgets err." << endl;
}
break;
} else {
cerr << buf;
}
}
if (::close(errFD) == -1) {
if (errno != 10) {
cerr << "Failed attempt to close err." << endl;
}
}
cerr << "\n";
}
}
There are two kinds of child processes created in this fashion with different tasks in my application:
SSH to another machine and invoke a server that will communicate back to the parent that is acting as a client.
Compute a signature, delta, or merge file using rsync.
First of all, popen is a very thin wrapper on top of fork() followed by exec() [and some call to pipe and dup and so on to manage the ends of a pipe] .
Second, the memory is only duplicated in form of "copy-on-write" memory - meaning that unless one of the processes writes to some page, the actual physical memory is shared between the two processes.
It does mean, of course, the OS has to create a memory map with 4-8 bytes per 4KB [in typical cases] (probably plus some internal OS data to track how many copies there are of that page and stuff - but as long as the page remains the same one as the parent process, the child page uses the parent processes internal data). Compared to everything else involved in creating a new process and loading an executable file into the new process, it's a pretty small part of the time. Since you are almost immediately doing exec, not much of the parent process' memory will be touched, so very little will happen there.
My advice would be that if popen works, keep using popen. If popen doesn't quite do what you want for some reason, then use fork + exec - but make sure you know what the reason for doing so is.
I wonder any way to handle inner exceptions of I called exe from c++ code?
My sample code:
char *fProg = "..\\ConsoleApp\\EZF\\EncryptZipFtp.exe";
char *fPath = "C:\\Users\\min\\Desktop\\Foto";
char *fPass = "wxRfsdMKH1994wxRMK";
char command[500];
sprintf (command, "%s %s %s", fProg, fPath, fPass);
try
{
system(command);
}
catch(exception &err)
{
}
You need to check the return value from system() (as you need to check the return value from all C functions). Like this:
int status = system(command);
if (status == -1)
std::cerr << "oops, could not launch " << command << std::endl;
int rc = WEXITSTATUS(status);
if (rc != 0)
std::cerr << "error from " << command << ": " << rc << std::endl;
If the child program is at all well-behaved, it will return nonzero to indicate failure when an unhandled exception occurs.
I am trying to create a database in c++ using sqlite3 lib.. I am getting error sqlite3_prepare_v2'
was not declared in this scope as shown in logcat.
log file
..\src\Test.cpp: In function 'int main(int, const char**)':
..\src\Test.cpp:21:85: error: 'sqlite3_prepare_v2' was not declared in this scope
..\src\Test.cpp:30:13: error: variable 'sqlite3 in' has initializer but incomplete type
..\src\Test.cpp:30:30: error: invalid use of incomplete type 'sqlite3 {aka struct sqlite3}'
..\src\/sqlite3.h:73:16: error: forward declaration of 'sqlite3 {aka struct sqlite3}'
Here is my code
#include <iostream>
using namespace std;
#include "sqlite3.h"
int main (int argc, const char * argv[]) {
sqlite3 *db;
sqlite3_open("test.db", & db);
string createQuery = "CREATE TABLE IF NOT EXISTS items (busid INTEGER PRIMARY KEY, ipaddr TEXT, time TEXT NOT NULL DEFAULT (NOW()));";
sqlite3_stmt *createStmt;
cout << "Creating Table Statement" << endl;
sqlite3_prepare_v2(db, createQuery.c_str(), createQuery.size(), &createStmt, NULL);
cout << "Stepping Table Statement" << endl;
if (sqlite3_step(createStmt) != SQLITE_DONE) cout << "Didn't Create Table!" << endl;
string insertQuery = "INSERT INTO items (time, ipaddr) VALUES ('test', '192.168.1.1');"; // WORKS!
sqlite3_stmt *insertStmt;
cout << "Creating Insert Statement" << endl;
sqlite3_prepare(db, insertQuery.c_str(), insertQuery.size(), &insertStmt, NULL);
cout << "Stepping Insert Statement" << endl;
if (sqlite3_step(insertStmt) != SQLITE_DONE) cout << "Didn't Insert Item!" << endl;
cout << "Success!" << endl;
return 0;
}
please help me out. thanks.....
#include <sqlite3.h>
should contain sqlite3_prepare_v2 and struct sqlite3. Make sure you're including the right sqlite3.h file.
Also in sqlite3_prepare_v2 the 3rd arg can be (and should be in your case) -1 so the sql is read to the first null terminator.
Working bare-metal sample using sqlite 3.7.11:
#include <sqlite3.h>
int test()
{
sqlite3* pDb = NULL;
sqlite3_stmt* query = NULL;
int ret = 0;
do // avoid nested if's
{
// initialize engine
if (SQLITE_OK != (ret = sqlite3_initialize()))
{
printf("Failed to initialize library: %d\n", ret);
break;
}
// open connection to a DB
if (SQLITE_OK != (ret = sqlite3_open_v2("test.db", &pDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)))
{
printf("Failed to open conn: %d\n", ret);
break;
}
// prepare the statement
if (SQLITE_OK != (ret = sqlite3_prepare_v2(pDb, "SELECT 2012", -1, &query, NULL)))
{
printf("Failed to prepare insert: %d, %s\n", ret, sqlite3_errmsg(pDb));
break;
}
// step to 1st row of data
if (SQLITE_ROW != (ret = sqlite3_step(query))) // see documentation, this can return more values as success
{
printf("Failed to step: %d, %s\n", ret, sqlite3_errmsg(pDb));
break;
}
// ... and print the value of column 0 (expect 2012 here)
printf("Value from sqlite: %s", sqlite3_column_text(query, 0));
} while (false);
// cleanup
if (NULL != query) sqlite3_finalize(query);
if (NULL != pDb) sqlite3_close(pDb);
sqlite3_shutdown();
return ret;
}
Hope this helps
Guys , creating database using sqlite3 in c/c++, here I'm using follwing steps...
1) Firstly you include MinGw file .
2) Add header file sqlite3.h, sqlite3.c in your src folder.
3) Add libr folder , in libr here include these file
mysqlite.h, shell.c, sqlite3.c, sqlite3.h, sqlite3ext.h
After then start your coding...
#include <iostream>
using namespace std;
#include "sqlite3.h"
int main (int argc, const char * argv[]) {
sqlite3 *db;
sqlite3_open("test1.db", & db);
string createQuery = "CREATE TABLE IF NOT EXISTS items (userid INTEGER PRIMARY KEY, ipaddr
TEXT,username TEXT,useradd TEXT,userphone INTEGER,age INTEGER, "
"time TEXT NOT NULL DEFAULT
(NOW()));";
sqlite3_stmt *createStmt;
cout << "Creating Table Statement" << endl;
sqlite3_prepare(db, createQuery.c_str(), createQuery.size(), &createStmt, NULL);
cout << "Stepping Table Statement" << endl;
if (sqlite3_step(createStmt) != SQLITE_DONE) cout << "Didn't Create Table!" << endl;
string insertQuery = "INSERT INTO items (time, ipaddr,username,useradd,userphone,age)
VALUES ('7:30', '192.187.27.55','vivekanand','kolkatta','04456823948',74);"; // WORKS!
sqlite3_stmt *insertStmt;
cout << "Creating Insert Statement" << endl;
sqlite3_prepare(db, insertQuery.c_str(), insertQuery.size(), &insertStmt, NULL);
cout << "Stepping Insert Statement" << endl;
if (sqlite3_step(insertStmt) != SQLITE_DONE) cout << "Didn't Insert Item!" << endl;
return 0;
}
go through this link. I am not sure. It might help you out.
I think their is no sqlite3_prepare_v2 in sqlite3.h lib, so try this.. sqlite3_prepare_v2 can be replaced by sqlite3_prepare, but more care is needed, because it changes the semantics of subsequent calls slightly.