Strange Problem anyone please solve it
While loop is not executing, in my read database code.
Here is my code
NSString * query=#"select usernote from savenote where recipename like ? ";
const char * sqlStatement=[query UTF8String];
sqlite3_stmt *compiledStatement;
sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL);
if (sqlite3_prepare_v2 (database, sqlStatement,-1,&compiledStatement,NULL)==SQLITE_OK)
{
sqlite3_bind_text(compiledStatement,1,[selString UTF8String],-1,SQLITE_STATIC);
NSLog(#"selected:%#",selString);
while (sqlite3_step(compiledStatement)== SQLITE_ROW)
{
NSString * notz=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement,0)];
[Notes addObject:notz];
NSLog(#"n:%#",Notes);
txt.text=[Notes objectAtIndex:0];
}
}
}
In the above code all works fine except the while loop is never being executed.
Thanks for reading my post.
I guess the problem is in the query. Add single-quotes(') in the like clause.
"select usernote from savenote where recipename like '?'";
You can follow this link
In your case Code will look like,
const char * sqlStatement = "select usernote from savenote where recipename like ?001 ";
sqlite3_bind_text(compiledStatement,1,[selString UTF8String],-1,SQLITE_TRANSIENT);
Related
I'm having trouble with QSqlQuery: it's not updating my SQLite database.
I initialize the database like this (which works fine):
myDB = QSqlDatabase::addDatabase("QSQLITE");
myDB.setDatabaseName(QDir::homePath() + QDir::separator() + "file.db");
myDB.open();
if(!myDB.tables().contains("presets")) {
myDB.exec("CREATE TABLE presets (id INTEGER PRIMARY KEY ASC, path TEXT);");
for (int i=0; i<10; i++)
myDB.exec("INSERT INTO presets (path) VALUES ('n/a')");
}
I have a QString array of values that I want to update into there.
QString presets[10];
preset[0] = "foo";
preset[1] = "bar";
...
I try to update the database with a for loop like this:
QSqlQuery qPreset(myDB);
qPreset.prepare("UPDATE presets SET path=':path' WHERE id=':id';");
for (int i=0; i<10; i++){
qPreset.bindValue(":path", presets[i]);
qPreset.bindValue(":id", i+1);
qPreset.exec();
}
But nothing happens in the database and I don't get any error messages either. Any ideas why?
Edit:
This (ugly as it is) works perfectly fine though, so it's not the connection:
for (int i=0; i<10; i++)
myDB.exec("UPDATE presets SET path='" + presets[i] + "' WHERE id='" + QString::number(i+1) + "';");
Based on the question from #Nejat I have figured out the answer: I had to remove all the single quotes. I failed to notice that QSqlQuery::bindValue() takes care of all the quoting that's necessary.
Working snippet:
qPreset.prepare("UPDATE presets SET path=:path WHERE id=:id;");
Thanks for the hint.
with gwan server, is it possible to get the request string... ie. the arguments.
given http://myserver.com/main.cpp?arg1=one&arg2=two
im looking to obtain a char string arg1=one&arg2=two
according to docs, it should be
REQ_ENTITY, // char *ENTITY // "arg=x&arg=y..."
but doing this gives me an empty string (using args on the above url)
char * req = (char*) get_env(argv, REQ_ENTITY);
xbuf_cat(get_reply(argv), req);;
aha. i should add that get_arg( "arg1" ...) works no problem on that exact same url string (suggesting that its in there somewhere. perhaps the raw query string
a hint or pointer to an example might be all thats needed. also it would be nice to have that work with a mapping/redirect at some point.
http://myserver.com/main/arg1=one&arg2=two
regards
A quick note about REQ_ENTITY.
Your sample above doesn't have a REQ_ENTITY since you are only doing a GET request. If a request have an Entity Body (Like POST) you can get the Entity Body using REQ_ENTITY but usually you don't need to since you can access it using your sample (stepping through argv) or by using get_arg().
get_arg() sample
This nice snippet of code works for my purpose. found in the docs.
Just concat them. so love working in c on the server.
int i = 0;
while(i < argc)
{
xbuf_xcat(get_reply(argv), "argv[%u] '%s' <br>", i, argv[i]);
i++;
}
and adapted it to the following:
string concatArgs(void) {
stringstream ss;
int i = 0;
while(i < argc) {
ss << argv[i++];
}
return ss.str();
}
I am trying to fetch data from SQLite database(NSArray of strings) and populate the contents in table view cells. I tried to execute the query in command prompt and it works fine. But in code, it returns an empty array.
NSString *temp = [[NSString alloc]initWithFormat:#"select img.image from images img,illness i,illness_images ii where img.img_id=ii.img_id and i.i_id=ii.i_id and i.i_id = '%d'",illid];
const char *sqlStatement = [temp UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
// Loop through the results and add them to the array
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
// Read the data from the result row
NSString *imgname = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
[imglist addObject:imgname];
sqlite3_finalize(compiledStatement);
}
}
else{
NSAssert1(0,#"Error retrieving image names '%s'",sqlite3_errmsg(database));
}
I tried to debug and when it reaches while(sqlite3_step(compiledStatement) == SQLITE_ROW) , it does not enter the loop.
Not sure whats the mistake I am doing.
Thanks!
Try NSLog after assigning the string query to temp variable.
and check if the variable illid is giving you the correct value and run that query on the database directly.
NSString *temp = [NSString stringWithFormat:#"select img.image from images img,illness i,illness_images ii where img.img_id=ii.img_id and i.i_id=ii.i_id and i.i_id = %d",illid];
and you better release the allocated object or use class methods setting value, for memory management.
HTH.
I have a lots of data and I want to insert to DB in the least time. I did some tests. I created a table (using the below script) in PostgreSQL:
CREATE TABLE test_table
(
id serial NOT NULL,
item integer NOT NULL,
count integer NOT NULL,
CONSTRAINT test_table_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE test_table OWNER TO postgres;
I wrote test code, created 1000 random values and insert to test_table in two different ways. First, using QSqlQuery::exec()
int insert() {
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
db.setHostName("127.0.0.1");
db.setDatabaseName("TestDB");
db.setUserName("postgres");
db.setPassword("1234");
if (!db.open()) {
qDebug() << "can not open DB";
return -1;
}
QString queryString = QString("INSERT INTO test_table (item, count)"
" VALUES (:item, :count)");
QSqlQuery query;
query.prepare(queryString);
QDateTime start = QDateTime::currentDateTime();
for (int i = 0; i < 1000; i++) {
query.bindValue(":item", qrand());
query.bindValue(":count", qrand());
if (!query.exec()) {
qDebug() << query.lastQuery();
qDebug() << query.lastError();
}
} //end of for i
QDateTime end = QDateTime::currentDateTime();
int diff = start.msecsTo(end);
return diff;
}
Second using QSqlQuery::execBatch:
int batchInsert() {
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
db.setHostName("127.0.0.1");
db.setDatabaseName("TestDB");
db.setUserName("postgres");
db.setPassword("1234");
if (!db.open()) {
qDebug() << "can not open DB";
return -1;
}
QString queryString = QString("INSERT INTO test_table (item, count)"
" VALUES (:item, :count)");
QSqlQuery query;
query.prepare(queryString);
QVariantList itemList;
QVariantList CountList;
QDateTime start = QDateTime::currentDateTime();
for (int i = 0; i < 1000; i++) {
itemList.append(qrand());
CountList.append(qrand());
} //end of for i
query.addBindValue(itemList);
query.addBindValue(CountList);
if (!query.execBatch())
qDebug() << query.lastError();
QDateTime end = QDateTime::currentDateTime();
int diff = start.msecsTo(end);
return diff;
}
I found that there is no difference between them:
int main() {
qDebug() << insert() << batchInsert();
return 1;}
Result:
14270 14663 (milliseconds)
How can I improve it?
In http://doc.qt.io/qt-5/qsqlquery.html#execBatch has been cited:
If the database doesn't support batch executions, the driver will
simulate it using conventional exec() calls.
I'm not sure my DBMS support batch executions or not?
How can I test it?
In not sure what the qt driver does, but PostgreSQL can support running multiple statements in one transaction. Just do it manually instead of trying to use the built in feature of the driver.
Try changing your SQL statement to
BEGIN TRANSACTION;
For every iteration of loop run an insert statement.
INSERT HERE;
Once end of loop happens for all 1000 records issue this. On your same connection.
COMMIT TRANSACTION;
Also 1000 rows is not much to test with, you might want to try 100,000 or more to make sure the qt batch really wasn't helping.
By issuing 1000 insert statements, you have 1000 round trips to the database. This takes quite some time (network and scheduling latency). So try to reduce the number of insert statements!
Let's say you want to:
insert into test_table(item, count) values (1000, 10);
insert into test_table(item, count) values (1001, 20);
insert into test_table(item, count) values (1002, 30);
Transform it into a single query and the query will need less than half of the time:
insert into test_table(item, count) values (1000, 10), (1001, 20), (1002, 30);
In PostgreSQL, there is another way to write it:
insert into test_table(item, count) values (
unnest(array[1000, 1001, 1002])
unnest(array[10, 20, 30]));
My reason for presenting the second way is that you can pass all the content of a big array in a single parameter (tested with in C# with the database driver "Npgsql"):
insert into test_table(item, count) values (unnest(:items), unnest(:counts));
items is a query parameter with the value int[]{100, 1001, 1002}
counts is a query parameter with the value int[]{10, 20, 30}
Today, I have cut down the running time of 10,000 inserts in C# from 80s to 550ms with this technique. It's easy. Furthermore, there is not any hassle with transactions, as a single statement is never split into multiple transactions.
I hope this works with the Qt PostgreSQL driver, too. On the server side, you need PostgreSQL >= 8.4., as older versions do not provide unnest (but there may be work arounds).
You can use QSqlDriver::hasFeature with argument QSqlDriver::BatchOperations
In the 4.8 sources, I found that only oci (oracle) support the BatchOperations. Don't know why not use the COPY statement for postgresql in the psql driver.
I'm working on the development of a C++ API which uses custom-designed plugins
to interface with different database engines using their APIs and specific SQL
syntax.
Currently, I'm attempting to find a way of inserting BLOBs, but since NULL is
the terminating character in C/C++, the BLOB becomes truncated when constructing
the INSERT INTO query string. So far, I've worked with
//...
char* sql;
void* blob;
int len;
//...
blob = some_blob_already_in_memory;
len = length_of_blob_already_known;
sql = sqlite3_malloc(2*len+1);
sql = sqlite3_mprintf("INSERT INTO table VALUES (%Q)", (char*)blob);
//...
I expect that, if it is at all possible to do it in the SQLite3 interactive console, it should be possible to construct the query string with properly escaped NULL characters. Maybe there's a way to do this with standard SQL which is also supported by SQLite SQL syntax?
Surely someone must have faced the same situation before. I've googled and found some answers but were in other programming languages (Python).
Thank you in advance for your feedback.
Thank you all again for your feedback. This time I'm reporting how I solved the problem with the help of the indications provided here. Hopefully this will help others in the future.
As suggested by the first three posters, I did use prepared statements — additionally because I was also interested in getting the columns' data types, and a simple sqlite3_get_table() wouldn't do.
After preparing the SQL statement in the form of the following constant string:
INSERT INTO table VALUES(?,?,?,?);
it remains the binding of the corresponding values. This is done by issuing as many sqlite3_bind_blob() calls as the columns. (I also resorted to sqlite3_bind_text() for other "simple" data types because the API I'm working on can translate integers/doubles/etc into a string). So:
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>
/* ... */
void* blobvalue[4] = { NULL, NULL, NULL, NULL };
int blobsize[4] = { 0, 0, 0, 0 };
const char* tail = NULL;
const char* sql = "INSERT INTO tabl VALUES(?,?,?,?)";
sqlite3_stmt* stmt = NULL;
sqlite3* db = NULL;
/* ... */
sqlite3_open("sqlite.db", &db);
sqlite3_prepare_v2(db,
sql, strlen(sql) + 1,
&stmt, &tail);
for(unsigned int i = 0; i < 4; i++) {
sqlite3_bind_blob(stmt,
i + 1, blobvalue[i], blobsize[i],
SQLITE_TRANSIENT);
}
if(sqlite3_step(stmt) != SQLITE_DONE) {
printf("Error message: %s\n", sqlite3_errmsg(db));
}
sqlite3_finalize(stmt);
sqlite3_close(db);
Note also that some functions (sqlite3_open_v2(), sqlite3_prepare_v2()) appear on the later SQLite versions (I suppose 3.5.x and later).
The SQLite table tabl in file sqlite.db can be created with (for example)
CREATE TABLE tabl(a TEXT PRIMARY KEY, b TEXT, c TEXT, d TEXT);
You'll want to use this function with a prepared statement.
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
In C/C++, the standard way of dealing with NULLs in strings is to either store the beginning of the string and a length, or store a pointer to the beginning of a string and one to the end of the string.
You want to precompile the statement sqlite_prepare_v2(), and then bind the blob in using sqlite3_bind_blob(). Note that the statement you bind in will be INSERT INTO table VALUES (?).