WHERE column = value, only work with INTEGER value - c++

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

Related

SQLite Update table

Trying to update table by user specified values. But the values are not getting updated.
cout<<"\nEnter Ac No"<<endl;
cin>>ac;
cout<<"\nEnter Amount"<<endl;
cin>>amt;
/* Create merged SQL statement */
sql = "UPDATE RECORDS set BAL = '%d' where ACCOUNT_NO = '%d'",amt, ac;
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
If I replace BAL and ACCOUNT_NO by some integer value instead of place holder then it is working fine.
Your sql string is not being created properly.
If you expect this code
sql = "UPDATE RECORDS set BAL = '%d' where ACCOUNT_NO = '%d'",amt, ac;
to result in
"UPDATE RECORDS set BAL = '1' where ACCOUNT_NO = '2'"
where
amt= 1 and ac = 2 then you need to use a string formatting call like this.
// the buffer where your sql statement will live
char sql[1024];
// write the SQL statment with values into the buffer
_snprintf(sql,sizeof(sql)-1, "UPDATE RECORDS set BAL = '%d' where ACCOUNT_NO = '%d'",amt, ac);
buff[sizeof(sql)-1]='\0';
On your particular platform _snprintf(...) might be snprintf(..) or another similarly named function. Also your compiler may warn about buffer manipulation security vulnerabilities. Choose the appropriate substitute for your needs

Saving text in Sqlite3, c++

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;
}

SQLite UPDATE fails to overwrite existing value

I have the following problem that has me stumped. As a note to keep in mind, I am using a precompiled sqlite3.dll rather than Qt's built-in SQLite support.
Table creation code:
CREATE TABLE STUDY(
Name NOT NULL,
UserName NOT NULL REFERENCES USERS(UserName),
Description DEFAULT NULL,
PathToOsirixDB DEFAULT NULL,
PRIMARY KEY(Name, UserName)
)
The following C++ code fails to update the value in column PathToOsirixDB if it already contains a value.
It fails silently, with no error returned. That would imply that no rows are matched in the UPDATE. However, if I take the same UPDATE with valid entries for user and study to match a row and run it via either the SQLite Manager Firefox plugin, or the command line tool, it works properly.
void CStudyDatabase::SetOsirixDBForStudy(const QString user, const QString study, const QString path)
{
if (mp_db)
{
int before = sqlite3_total_changes(mp_db);
QString insert = QString("UPDATE STUDY SET PathToOsirixDB = '%1' WHERE Name = '%2' AND UserName = '%3'").arg(path, study, user);
if (!InsertData(insert))
{
int after = sqlite3_total_changes(mp_db);
if (after - before >= 1)
{
SetOsirixDB(path.toAscii().data());
emit ReturnOsirixDB(osirix_db);
}
else
{
emit DatabaseError(QString("Failed to update the target path."));
}
}
}
}
And for Insert Data
int CStudyDatabase::InsertData(const QString insert)
{
char *err_msg = 0;
int rc = sqlite3_exec(mp_db,
insert.toStdString().c_str(),
NULL,
this,
&err_msg);
if (rc)
SignalDatabaseError(&err_msg);
return rc;
}
Any insights are appreciated. Thank you.
UPDATE: added the following code to SetOsiriXDBForStudy to see if we actually find a row to update:
osirix_db = QString("");
QString query = QString("SELECT PathToOsirixDB FROM STUDY WHERE Name = '%1' AND UserName = '%2'").arg(study, user);
int rc = 0;
char *err_msg = 0;
rc = sqlite3_exec(mp_db,
query.toStdString().c_str(),
&OsirixDBCallback,
this,
&err_msg);
if (rc)
SignalDatabaseError(&err_msg);
if (!(QString(osirix_db).isEmpty()))
studyrowfound = true;
In this case, it leaves osirix_db as an empty string.
But, if I execute this function:
void CStudyDatabase::QueryOsirixDB(const QString user, const QString study)
{
int rc = 0;
char *err_msg = 0;
// we query the OrisixDB via the callback and then emit the signal if all went well
QString query = QString("SELECT PathToOsirixDB FROM STUDY WHERE Name = '%1' AND UserName = '%2'").arg(study, user);
rc = sqlite3_exec(mp_db,
query.toStdString().c_str(),
&OsirixDBCallback,
this,
&err_msg);
if (rc)
SignalDatabaseError(&err_msg);
if (QString(osirix_db).isEmpty())
emit NeedToSetOsirixDB(user, study, QString());
else
emit ReturnOsirixDB(osirix_db);
}
Then it does correctly retrieve the expected value into osirix_db.
Last update: found the problem. It was leading spaces on user and study. Had been staring at the same debugger statements for too long and glossed over the extra spaces. The failing SELECT was a big clue that there was something wrong in the construction of the SQL.
There were leading spaces on user and study. Had been staring at the same debugger statements for too long and glossed over the extra spaces. The failing SELECT was a big clue that there was something wrong in the construction of the SQL.

SQLite SELECT JOIN and VIEWS in C++

I have a two tables in SQLITE and View where I try to compine these two tables (my idea is to get all the rows from table1 where table1.field1 and table2.field99 have the same value.
Tables and View are Table1,Table2 and View1
View code is "SELECT * FROM Table1 JOIN Table2 ON UPPER(Field1) LIKE UPPER(Table2.Field99)"
If I run
SELECT * FROM View1;
or if I run
SELECT * FROM Table1 JOIN Table2 ON UPPER(Field1) LIKE UPPER(Field99);
from sqlite shell it returns the rows just fine.
But if i try to run those SQL statements in C++ with this code:
if(sqlite3_prepare_v2(database,SQLStr,-1,&stmt,0)==SQLITE_OK){
int cols = sqlite3_column_count(stmt);
printf("Query OK: %s \nColumns: %i\n", SQLStr, cols);
while(1) {
status = sqlite3_step(stmt);
if(status == SQLITE_ROW) {
printf("This is a row!\n");
} else if(status == SQLITE_DONE) {
printf("Rows handled!\n");
break;
} else {
printf("Other status!\n");
break;
}
}
}
It just returns:
Rows handled: SELECT * FROM View1;
Columns: 7
Rows handled!
But it doesn't return any rows like the shell does. (there should be "This is a row!" printed for every row in query. I tried to add table names to queries but no help. I also tried to run for example SELECT * FROM Table1; and then the C++ returns the rows. Is it so that SQLITE in C++ can't handle JOINS or Views?
if u want to collect the rows then use Sqlite3_exec() API or column API.sqlite3_step() only evaluates the prepared statement it does not fetch the results, for that u have to use different api available or u can use sqlite3_exec which is a wrapper.
check the following link
http://www.sqlite.org/c3ref/funclist.html
http://www.sqlite.org/cintro.html
All the best.

mysql returns null when asking for difference between some value and null

in my table i have 3 column
id, somevalue (float), current timestamp
code below searches for the latest value in today's date and subtracts that with the value on monday of the same week. but i dont have any value stored for monday in this week so its NULL at the moment. but result of below code should be some value not null ???? dont understand how is it possible. pls explain.
select(SELECT power FROM newdb.newmeter
where date(dt)=curdate() order by dt desc limit 1)-
(select Power from newdb.newmeter
where date(dt)=(select date(subdate(now(), interval weekday(now()) day))));
as i was reading the similar questions-answers it looks like anything you do with null in mysql is null is it true??
if yes how do i resolve this
update:
i tried this but didnt work
select sum(amount) - coalesce(sum(due),0)
just wanted to add something more to this
i'm calling querydb as following for the mysql in c++
bool Querydb(char *query, double Myarray[1024])
{
//snip//
if (mysql_query(conn, query)) {
fprintf(stderr, "%s\n", mysql_error(conn));
return 0;
}
else {
res = mysql_use_result(conn);
//output table name
//printf("MySQL Tables in mysql database:\n");
//checking for null value in database
while((row = mysql_fetch_row(res))==NULL){
printf("ERROR_____NULL VALUE IN DATABASE ");
return 0;
}
//if not null then ...
while ((row = mysql_fetch_row(res)) != NULL){
printf("rows fetched %s\n", row[0]);
sprintf(buffer,"%s",row[0]);
value1 = atof(buffer);
Myarray[i]=value1;
//printf("Myarray in sql for daybutton = %f\n",Myarray[i]);
i++;
}
i=0;
//for(i=0;i<5;i++){
// printf("mya arr in sqlfunction = %f\n",Myarray[i]);}
return 1;
}
printf("if here then....where??\n");
//close connection
// mysql_free_result(res);
//return 0;
}
the above function works ok with different query when database has null but doesnt work with this query
select(SELECT power FROM newdb.newmeter
where date(dt)=curdate() order by dt desc limit 1)-
(select Power from newdb.newmeter
where date(dt)=(select date(subdate(now(), interval weekday(now()) day))));
it returns 1 even thought the answer is NULL...
Consult the manual on working with NULL values. They are treated specially http://dev.mysql.com/doc/refman/5.0/en/working-with-null.html
What value would you want it to be? This isn't particularly specific to MySQL - operations involving null operands (including comparisons) have null results in most SQL dialects.
You may want to use COALESCE() to provide a "default" value which is used when your real target value is null.
work Around would be
select(SELECT power FROM newdb.newmeter
where date(dt)=curdate() order by dt desc limit 1)-
(select COALESCE(Power,0) from newdb.newmeter
where date(dt)=(select date(subdate(now(), interval weekday(now()) day))));