I'm using sqlite3 with C++ . But the problem is that when I debugged the code I realised that it does not, I mean sqlite3_prepare_v2 does not extract the data from the database.
When I printed the value it extracted, it printed some garbage value. At the same time, I noticed the following warning:
Warning 4 warning LNK4248: unresolved typeref token (01000028) for
'sqlite3_stmt'; image may not run .
I'm working on MS visual studio 2010 windows forms application.
Can anyone help?
I think the linker complaint is ok. See http://social.msdn.microsoft.com/Forums/en-US/8376b2f0-cc36-48c8-9021-f30bda41f410/linker-warning-lnk4248-possible-problem
The following does not take into account that you're programming in MS managed C++, however, I hope it still provides some guidance.
sqlite3_prepare_v2 prepares the statement but does not execute anything.
You need to call sqlite3_step to execute (or partly execute) the SQL.
For an SQL statement that returns nothing (e.g. UPDATE, DELETE, INSERT) you call sqlite3_step once and it should return SQLITE_DONE if it worked.
For a statement that can return multiple rows you call sqlite3_step repeatedly. Each time the return code is SQLITE_ROW you have been returned a row of data that you can access with the
sqlite3_column_* set of statements. When all data has been returned sqlite3_step returns SQLITE_DONE.
Code might look something like this
sqlite3* db;
int rc = sqlite3_open(databasePath.c_str(), &db);
std::string sql = "SELECT Id, Url FROM Url WHERE Page_Download_Reqd <> 0;";
sqlite3_stmt* statementPtr;
const char* tailPtr;
int rc = sqlite3_prepare_v2(db, sql.c_str(), sql.size(), &statementPtr, &tailPtr);
bool finished = false;
do {
int rc = sqlite3_step(statementPtr);
switch (rc) {
case SQLITE_ROW: {
__int64 id = sqlite3_column_int(statementPtr, 0);
std::string url = reinterpret_cast<const char*>(sqlite3_column_text(statementPtr, 1));
// Do something with your data
}
break;
case SQLITE_DONE:
finished = true;
break;
default:
assert(false);
}
} while (!finished);
If you have variables in you SQL, e.g.
SELECT Id, Url FROM Url WHERE Count <> :count;
then you need to use one of the sqlite3_bind_* functions between the sqlite3_prepare_v2 and sqlite3_step functions. For example
__int count = 6;
std::string bindVarName = ":count";
rc = sqlite3_bind_int(
statementPtr,
sqlite3_bind_parameter_index(statementPtr, bindVarName.c_str()),
count);
Related
I use sqlite on a c++ project, but I have a problem when i use WHERE on a column with TEXT values
I created a sqlite database:
CREATE TABLE User( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(24))
When i try to get the value of the column with VARCHAR values, it doesn't work, and return me a STATUS_CODE 101 just after the sqlite3_step :
int res = 0;
sqlite3_stmt *request;
char *sqlSelection = (char *)"SELECT * FROM User WHERE name='bob' ";
int id = 0;
res = sqlite3_prepare_v2(db, sqlSelection, strlen(sqlSelection), &request, NULL);
if (!res){
while (res == SQLITE_OK || res == SQLITE_ROW){
res = sqlite3_step(request);
if (res == SQLITE_OK || res == SQLITE_ROW ){
id = sqlite3_column_int(request, 0);
printf("User exist %i \n",id);
}
}
sqlite3_finalize(request);
I also tried with LIKE but it also doesn't work
SELECT * FROM User WHERE name LIKE '%bob%'
But when I execute the same code but for an INTERGER value
SELECT * FROM User WHERE id=1
It work fine.
In DB Browser for SQLite all requests work fine.
To solve the problem I searched what status code 101 means.
Here is what they said.
(101) SQLITE_DONE
The SQLITE_DONE result code indicates that an operation has completed.
The SQLITE_DONE result code is most commonly seen as a return value
from sqlite3_step() indicating that the SQL statement has run to
completion. But SQLITE_DONE can also be returned by other multi-step
interfaces such as sqlite3_backup_step().
https://sqlite.org/rescode.html
So, you're getting 101 because there is no more result from SELECT SQL.
The solution was to replace the VARCHAR fields by TEXT.
SQLite for c++ seems to don't manage VARCHAR fields when they are used after the WHERE
I have a C++ application which loops through a SQLite3 database. Each row contains an ID which is checked against a vector. If the ID in the DB is not present in the vector, it should be deleted with a prepared statement. I use the following code, however the ID's won't get deleted. I Neither can get an error message from the sqlite3_step(stmt2) function.
//SETTINGS["Reference"] CONTAINS THE REFERENCE FOR THE ID's (IT's 1 FOR UNDERNEATH EXAMPLE)
vector<int> IDs; //THIS VECTOR CONTAINS THE ID's IN MY APPLICATION
rc = sqlite3_prepare_v2(db, "SELECT ID FROM Files WHERE Reference=?", -1, &stmt, 0);
sqlite3_bind_text(stmt, 1, Settings["Reference"].c_str(), Settings["Reference"].length(), 0);
CheckDBError(rc);
rc = sqlite3_step(stmt);
sqlite3_stmt* stmt2;
int rc2 = sqlite3_prepare_v2(db, "DELETE FROM Files WHERE ID=? AND Reference=?", -1, &stmt2, 0);
CheckDBError(rc2);
while(rc == SQLITE_ROW) {
string IDToCheck = NumberToString(sqlite3_column_int64(stmt, 0));
if (std::find(IDs.begin(), IDs.end(), IDToCheck) == IDs.end()) { //VERIFY AGAINST VECTOR WORKS AS EXPECTED
//I GET HERE WITH ALL MY ID's I HAVE CHECKED THAT ALREADY :)
sqlite3_bind_text(stmt2, 1, IDToCheck.c_str(), IDToCheck.length(), 0);
sqlite3_bind_text(stmt2, 2, Settings["Reference"].c_str(), Settings["Reference"].length(), 0);
rc2 = sqlite3_step(stmt2);
//CAN'T GET ANY ERROR MESSAGE (SO QUERY IS FINE, WHICH SEEMS LIKE IT?)
}
rc = sqlite3_step(stmt);
}
sqlite3_finalize(stmt);
sqlite3_finalize(stmt2);
You must not call the finalize function before the while block, because that way you finalize your statement before using it. As per SQLite documentation (emphasis mine):
It is a grievous error for the application to try to use a prepared
statement after it has been finalized. Any use of a prepared statement
after it has been finalized can result in undefined and undesirable
behavior such as segfaults and heap corruption.
here is my second post in the community, excuse me if I'm forget to add something, just let me know:
I am trying to do a program in c++ able to save text (i want to save code) in a database using sqlite3. Currently I've made a wxWidget program that call some functions from a DLL and this ones interactuate with the database.
The database that I want to make is really simple, it has 3 columns in one table (id,name, ref). My problem comes when I want to save big amount of text that also contains simblos that can conflict with the sql queries (I would like to save files inside the database, for example in the "ref" column ).
I'm using mostly the sqlite3_exec function, because the functions sqlite3_prepare_v2, sqlite_bind, sqlite3_step crash me the DLL where I'm working.
My doubt: Can I directly save any text as big as I want, without taking care about if it has simbols or not? and how can I do it?.
More info: I am working in c++ with code:block(13.12) making a DLL of sqlite3 functions and using MinGW toolchain. (windows 7).
This is an example of an insert function that I'm using:
int DLL_EXPORT add_item(sqlite3* db, string tbname,string col,string item)
{
char* db_err = 0;
if (tbname==std::string()||col==std::string()||item==std::string())
throw std::invalid_argument( "stoi: invalid argument table name");
char buf[200];
sprintf(buf,"insert into %s (%s) values ('%s');", tbname.c_str(), col.c_str(),item.c_str());
int n = sqlite3_exec(db, buf, NULL, 0, &db_err);
dsperr(&db_err);
if( n != SQLITE_OK )
{
//throw something
}
return 0;
}
Thank you in advance.
Thank to CL. for the up commentary
// Add one text to a table
// The column must be specify
//
int DLL_EXPORT add_text(sqlite3* db, string tbname,string col,string id,string item)
{
char* db_err = 0;
if (tbname==std::string()||col==std::string()||item==std::string())
throw std::invalid_argument( "stoi: invalid argument table name");
char *zSQL = sqlite3_mprintf("UPDATE %q SET %q=(%Q) WHERE id=%q", tbname.c_str(),col.c_str() ,item.c_str(),id.c_str());
int n = sqlite3_exec(db, zSQL, NULL, 0, &db_err);
dsperr(&db_err);
sqlite3_free(zSQL);
if( n != SQLITE_OK )
{
// throw something
}
return 0;
}
I have this C++ function which works to check if a given name exists. But every time it returns false even when a given name already exists. Where do I do wrong?
bool Database::hasRepository(std::string repoName)
{
string sql = "SELECT * FROM repository WHERE NAME='";
sql += repoName + "'";
sqlite3_stmt* selectStmt = nullptr;
sqlite3_prepare_v2(connection, sql.c_str(), sql.size(), &selectStmt, NULL);
int results = sqlite3_step(selectStmt);
sqlite3_finalize(selectStmt);
if(results == SQLITE_ROW)
return true;
else
return false;
}
You should check the return value of all functions which might return an error indication. For example, sqlite3_prepare_v2 will return an error code if the statement has a syntax error.
That might have told you that the statement you supplied is incorrect (if it is).
You can use sqlite3_errmsg and sqlite3_errstr to produce more readable error messages. It is never a good idea to just throw away the specific information about the error, for example by just returning false, particularly during debugging.
I am trying to call a function which is declared in PostgreSQL with PL/pgSQL. For that I write the code below. My function is working but after that I am taking a "PGRES_FATAL_ERROR". Also when I changed "select removestopwords()" with an sql query like "DELETE * FROM TABLE1" it's working successfully.
I am considering, that error can cause some big problem in future even if now working. How can I call a PL/pgSQL function without taking error?
void removeStopWordsDB(PGconn* conn) {
PGresult *res = PQexec(conn, "select removestopwords()");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
printf("removestopwords failed");
cout<<PQresultStatus(res);
PQclear(res);
exit_nicely(conn);
}
printf("removestopwords - OK\n");
PQclear(res);
}
If you get PGRES_FATAL_ERROR from PQresultStatus you should use PQresultErrorField to get all the error data from the result set to provide a useful error message. This will allow you to determine what the actual error is here (quite likely an error being sent over from the server).
Consider creating a class to hold PostgreSQL error details that can be constructed from q PQresult pointer, e.g.:
PgError(const PGresult *rs)
{
severity = GetErrorField(rs, PG_DIAG_SEVERITY);
sqlstate = GetErrorField(rs, PG_DIAG_SQLSTATE);
primary = GetErrorField(rs, PG_DIAG_MESSAGE_PRIMARY);
// ...
}
static std::string GetErrorField(const PGresult *rs, int fieldCode)
{
const char *message = PQresultErrorField(rs, fieldCode);
if (message == NULL) return "";
return std::string(message);
}
Then you can, for example, encapsulate dumping out the error to a stream in this object to provide details just like psql and friends do (although strictly speaking, you'd need the input SQL as well for all of that)
PostgreSQL API doesn't support some flag like "ignore all errors". If you would to ignore result, then just don't check result in host environment. But it is bad strategy.