I have a method intended to insert in my sqlite database from a custom object:
- (void)insertCustomEntity:(CustomEntity *)customEntity
{
NSString *filePath = [FileMngr copyDatabaseToDocuments];
sqlite3 *database;
if (sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "INSERT OR REPLACE INTO Entities (id, type, timestamp, result) VALUES (?, ?, ?, ?)";
sqlite3_stmt *compiledStatement;
NSLog(#"Could not prepare statement: %s\n", sqlite3_errmsg(database));
if (sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_int(compiledStatement, 1, customEntity.id);
sqlite3_bind_int(compiledStatement, 2, customEntity.type);
sqlite3_bind_int64(compiledStatement, 3, customEntity.timestamp);
sqlite3_bind_int(compiledStatement, 4, customEntity.result);
}
if(sqlite3_step(compiledStatement) == SQLITE_DONE) {
}
else {
NSLog(#"Step: %d\n", sqlite3_step(compiledStatement));
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
I've been doing tests for a while and data was being inserted, but suddenly it stopped to do and I'm now getting a 5 step code at my second NSLog. Why does this happen, if it was working previously? I tried several options I found in some posts, like placing the sqlite3_step(compiledStatement) inside the sqlite3_prepare_v2 but I keep being unable to insert. What I'm doing wrong?
Thanks in advance
I am not sure but it looks like some of your braces are mis-matched? Anyways, error code 5 indicates that your database is locked.
http://www.sqlite.org/c3ref/c_abort.html
Check if something else is accessing your database ( or your database is not getting closed in some situation in which case your code needs to change). Try the following solution to resolve it :-
sqlite3 database is getting locked
Related
This question already has an answer here:
Delete multiple tables from a single query by separating from semicolon
(1 answer)
Closed 7 years ago.
I am trying to insert the values in two different tables in a single statement, first insert query in working second query is not working.
sqlite3_stmt * statement= NULL;
const char *dbpath =[databasePath UTF8String];
if (sqlite3_open(dbpath, &mySqliteDB)== SQLITE_OK)
{
for (PostObject * post in in_PostObject)
{
**query**
NSString * postSql =[NSString stringWithFormat:#"insert or ignore into %#_post (postid,data,active) values (\"%#\",?,\"%d\");",tblPrefix,post.post_ID,post.active];
/*Appending First query with second query*/
NSString * insertSQl =[postSql stringByAppendingString:[NSString stringWithFormat:#" insert into %#_forumuser (uid,utype,name) values (1,'parent','javid');",tblPrefix]];
NSLog(#"%#",insertSQl);
const char * insert_stmt=[insertSQl UTF8String];
sqlite3_prepare_v2(mySqliteDB, insert_stmt, -1, &statement, NULL);
sqlite3_bind_text(statement, 1, [post.jsonData UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(statement)==SQLITE_DONE)
{
success =TRUE;
}
else
{
NSLog(#"DB Error: %s", sqlite3_errmsg(mySqliteDB));
}
}
}
sqlite3_finalize(statement);
sqlite3_close(mySqliteDB);
You need to check the return code from the sqlite3_prepare_v2 to make sure there aren't any problems.
Also you shouldn't need to open and close the database for each statement you want to execute, there you could process them as 2 statements
if(sqlite3_prepare_v2(mySqliteDB, insert_stmt,-1, &statement, NULL) != SQLITE_OK) {
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(db), sqlite3_errcode(db));
}
I have my code below. My values _emailVaue _passwordValue and _nameValue are taken from UITextFields in my app. I was under the impression that passing these values into parameters in my SQLite code would allow me to have special characters in those values such as double quotation marks ( " ), however, if I put them in, the SQLite crashes. Is there something I'm doing wrong?
I'm aware that it's probably best to use something like FMDB, but I was hoping that there might be a quicker fix to get me through an upcoming demo.
I'd appreciate any help, thanks!
if (sqlite3_open(dbpath, &_contactDB) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat:
#"INSERT INTO CONTACTS (email, password, name) VALUES (\"%#\", \"%#\", \"%#\")",
_emailValue, _passwordValue, _nameValue];
NSLog(insertSQL);
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(_contactDB, insert_stmt,
-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
} else {
}
sqlite3_finalize(statement);
sqlite3_close(_contactDB);
}
I hope it's OK to answer my own question if it seems to work. Hopefully someone will find it useful. Would appreciate any feedback on where I might be going wrong.
sqlite3_stmt *statement;
const char *dbpath = [_databasePath UTF8String];
const char *insertSQL;
if (sqlite3_open(dbpath, &_contactDB) == SQLITE_OK)
{
insertSQL = "INSERT INTO CONTACTS (email, password, name) VALUES (?, ?, ?)";
if(sqlite3_prepare_v2(_contactDB, insertSQL, -1, &statement, NULL) == SQLITE_OK)
{
sqlite3_bind_text(statement, 1, [_emailValue UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [_passwordValue UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [_nameValue UTF8String], -1, SQLITE_TRANSIENT);
}
if (sqlite3_step(statement) == SQLITE_DONE)
{
//worked
} else {
//didn't work
}
sqlite3_finalize(statement);
sqlite3_close(_contactDB);
}
I'll try to explain what happened with your code and how it could be improved so that the crash would not occur. I totally agree with the usage of bound arguments, this answer is posted only as it represents an answer to how your crash can be fixed, and might help people that don't have the time to switch to bound statements.
Here's what happened:
sqlite3_prepare_v2() failed as your query string was invalid due to the fact that your strings contained the " characted
due to the above, statement was either NULL or contained a garbage value
sqlite3_step() crashed as an invalid pointer was passed as argument.
Here's the fix:
escape all your strings, by replacing " by \", this will generate a valid query; if you were using ' in your query, then you would have to replace ''s by \'
Example for email:
NSString *escapedEmail = [_emailValue stringByReplacingOccurrencesOfString:#"\"" withString:#"\\\""];
even if you're sure the query is correct, is still mandatory to check the result of sqlite3_prepare_v2() before using the statement in any other sqlite calls.
As a general note, you need to code very defensively when dealing with C API's as C doesn't forgive you if you forget to check for NULL pointers. Objective-C is more soft, as it allows you to send messages to nil objects.
In the following code everything seems right but the notated lines always return an error code of null no matter what data I feed them. I've researched and changed all the parameters I can think of. The first sqlite3_bind_text line is successful and the next three fail every time. I can't figure it out. Help?
-(void)fillSqliteDb
{
sqlite3 *database;
if (sqlite3_open([[self sqliteFilePath] UTF8String], &database) != SQLITE_OK) {
sqlite3_close(database);
NSAssert(0, #"Failed to open database");
}
NSString *createSQL = #"CREATE TABLE IF NOT EXISTS FUNCTIONS (nouns TEXT, verbs TEXT, adverbs TEXT, adjectives TEXT);";
char *errorMsg;
if (sqlite3_exec (database, [createSQL UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) {
sqlite3_close(database);
NSAssert(0, #"Error creating table: %s", errorMsg);
}
sqlite3_stmt *stmt;
for (int i=0; i<260; i++) {
NSString * pln = self.pluralNouns[i]; // pre-filled array of 260 words
NSString * vrb = self.verb[i]; // pre-filled array of 260 words
NSString * adv = self.adverb[i]; // pre-filled array of 260 words
NSString * adj = self.adjective[i]; // pre-filled array of 260 words
char *update = "INSERT INTO FUNCTIONS (nouns, verbs, adverbs, adjectives) VALUES (?, ?, ?, ?);";
if (sqlite3_prepare_v2(database, update, -1, &stmt, nil) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, [pln UTF8String], -1, NULL);
if (sqlite3_step(stmt) != SQLITE_DONE) // Works, word ends up in database
NSLog(#"Error updating table: %s", errorMsg);
sqlite3_bind_text(stmt, 2, [vrb UTF8String], -1, NULL);
if (sqlite3_step(stmt) != SQLITE_DONE) // ALWAYS RETURNS Error: NULL
NSLog(#"Error updating table: %s", errorMsg);
sqlite3_bind_text(stmt, 3, [adv UTF8String], -1, NULL);
if (sqlite3_step(stmt) != SQLITE_DONE) // ALWAYS RETURNS Error: NULL
NSLog(#"Error updating table: %s", errorMsg);
sqlite3_bind_text(stmt, 4,[adj UTF8String], -1, NULL);
if (sqlite3_step(stmt) != SQLITE_DONE) // ALWAYS RETURNS Error: NULL
NSLog(#"Error updating table: %s", errorMsg);
}
}
}
There are several things wrong with this code.
Only call sqlite3_prepare_v2 once. Do it before the for loop.
You need to call sqlite3_bind_xxx once for each variable, all before calling sqlite3_step.
Only call sqlite2_step once per loop. Do this at the end of the loop.
After calling sqlite3_step at the end of the loop, you need to call sqlite3_reset.
After the loop you need to call sqlite3_finalize on the prepared statement.
Since you opened the database connection at the start of the method, you need to close it at the end of the method.
Your use of errorMsg for all of the logs after checking the result of each sqlite3_step call is wrong. errorMsg is only set from the call to sqlite3_exec. To get the error message of the other calls you need to use sqlite3_errmsg.
Updated code:
- (void)fillSqliteDb {
sqlite3 *database;
if (sqlite3_open([[self sqliteFilePath] UTF8String], &database) != SQLITE_OK) {
sqlite3_close(database);
NSAssert(0, #"Failed to open database");
}
NSString *createSQL = #"CREATE TABLE IF NOT EXISTS FUNCTIONS (nouns TEXT, verbs TEXT, adverbs TEXT, adjectives TEXT);";
char *errorMsg;
if (sqlite3_exec (database, [createSQL UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) {
sqlite3_close(database);
NSAssert(0, #"Error creating table: %s", errorMsg);
}
sqlite3_stmt *stmt;
char *update = "INSERT INTO FUNCTIONS (nouns, verbs, adverbs, adjectives) VALUES (?, ?, ?, ?);";
if (sqlite3_prepare_v2(database, update, -1, &stmt, nil) == SQLITE_OK) {
for (int i=0; i<260; i++) {
NSString * pln = self.pluralNouns[i]; // pre-filled array of 260 words
NSString * vrb = self.verb[i]; // pre-filled array of 260 words
NSString * adv = self.adverb[i]; // pre-filled array of 260 words
NSString * adj = self.adjective[i]; // pre-filled array of 260 words
sqlite3_bind_text(stmt, 1, [pln UTF8String], -1, NULL);
sqlite3_bind_text(stmt, 2, [vrb UTF8String], -1, NULL);
sqlite3_bind_text(stmt, 3, [adv UTF8String], -1, NULL);
sqlite3_bind_text(stmt, 4, [adj UTF8String], -1, NULL);
if (sqlite3_step(stmt) != SQLITE_DONE) // ALWAYS RETURNS Error: NULL
NSLog(#"Error updating table: %s", sqlite3_errmsg(database));
sqlite3_reset(stmt);
}
sqlite3_finalize(stmt);
}
sqlite3_close(database);
}
I'm trying to insert a user note into a sqliteDB through this method but for some reason, its not passing this if statement...
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK){}
I'm not sure but I think my SQLStatement is getting rejected or some reason.
(void) insertQuickNoteInDataBase:(NSString *)name :(NSString *)note{
sqlite3 * database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "insert into detail(QuickNote) values (?), where name = ?";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_text(compiledStatement, 8, [note UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(compiledStatement, 2, [name UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(compiledStatement))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
You need to log the error using sqlite3_errmsg. But the problem is most likely the comma in the query as well as the where clause. Insert statements should not have a where clause. Perhaps you mean to use an update:
"UPDATE detail SET QuickNote = ? WHERE name = ?"
Also, your calls to sqlite3_bind_xxx need to have the proper indexes. The bind indexes start at 1 and go up. You are using 8 then 2. You want 1 then 2.
I am new to the iPhone programming and was hoping that someone would be able to help me out with a problem that I've been trying to fix for a few days now. I have created a database and a table. In my program, it contain 5 fields and I am setting two of the fields to zero. And later I am updating these fields to one for a purpose. But the problem is I am not able to set the field value to one. I will paste the code below :
NSString *querySQL = [NSString stringWithFormat: #"UPDATE TODOLIST_03 SET DELETEROW ='1' WHERE TASK=\"%#\"", cellText1];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(TODOLIST_03_DB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
.........
}
}
Can anyone please tell me what is the error in the query?
try following :
const char *sqlQuery="UPDATE TODOLIST_03 SET DELETEROW ='1' WHERE TASK= ?";
if(sqlite3_prepare_v2(database, sqlQuery,-1, &queryStatement, NULL) == SQLITE_OK)
{
sqlite3_bind_text(queryStatement, 1, [cellText UTF8String], -1, NULL);
}
What path did you put database file at? It can not be wrote if you put the database file at the path same as project, you should put it in the sandbox for example NSHomeDocument where it is writeable, and you can modify code like this to track the error:
NSError *err;
if (sqlite3_prepare_v2(TODOLIST_03_DB, query_stmt, -1, &statement, &err) == SQLITE_OK)
{
if(err)
{
// NSLog error or what.
}
}