I am trying to insert a value to a SQLite db, but everytime I try my program simply crashes with no error message at all.
Here is my code:
- (void) insertToDatabase:(NSString *) refName {
// The Database is stoed in the application bundle
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"staticdata.sqlite"];
if(sqlite3_open([path UTF8String], &database) == SQLITE_OK){
const char *sql = "Insert into usersDates(dateDescription) VALUES (?)";
sqlite3_stmt *init_statement;
sqlite3_bind_text(init_statement, 1, [refName UTF8String], -1, SQLITE_TRANSIENT);
if(!sqlite3_prepare_v2(database, sql, -1, &init_statement, NULL) == SQLITE_OK){
NSAssert1(0, #"Failed to insert to database file with message '%s'.", sqlite3_errmsg(database));
}
if(sqlite3_step(init_statement) != SQLITE_DONE ) {
NSLog( #"Error: %s", sqlite3_errmsg(database) );
} else {
NSLog( #"Insert into row id = %d", sqlite3_last_insert_rowid(database));
}
sqlite3_finalize(init_statement);
} else {
sqlite3_close(database);
NSAssert1(0, #"Failed to open database file with message '%s'.", sqlite3_errmsg(database));
}
}
The error seems to occur on the bind statement. I have confirmed the database is actually being opened, and refname is correctly being passed to my method.
Can anyone help? I would normally use core data, however this is a bug fix to an existing project, and I simply do not have the time to allocate to making the move to core data.
The order of your statements is incorrect. bind_() is used after prepare()
SQLite bind() documentation
The first argument to the sqlite3_bind_*() routines is always a pointer to the sqlite3_stmt object returned from sqlite3_prepare_v2() or its variants.
const char *sql = "Insert into usersDates(dateDescription) VALUES (?)";
sqlite3_stmt *init_statement;
if(!sqlite3_prepare_v2(database, sql, -1, &init_statement, NULL) == SQLITE_OK){
NSAssert1(0, #"Failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
sqlite3_bind_text(init_statement, 1, [refName UTF8String], -1, SQLITE_TRANSIENT);
sqlite_step(init_statement);
Related
I am developing one application. In that iam facing the problem at inserting the data into database. First insert and update will be performed very well. After updating if i want to perform insert operation then app will be crashed. My code for inserting and updating were like below
+(BOOL)update:(CalendarInfo*)clInfo
{
NSString *query = [NSString stringWithFormat:#"UPDATE ABC set A = '%#' where B =%d and C=%d",clInfo.a,clInfo.b,clInfo.c];
sqlite3_stmt *stStatement;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &stStatement, nil)==SQLITE_OK)
{
if(SQLITE_DONE == sqlite3_step(stStatement))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
else
NSLog(#"updation Successful");
}
return 0;
}
+(BOOL)insert:(CalendarInfo*)clInfo{
sqlite3_stmt *addStmt = nil;
sqlite3 *contactDB;
NSArray *docPathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *destPath = [NSString stringWithFormat:#"%#/example.sqlite",[docPathArr objectAtIndex:0]];
if (sqlite3_open([destPath UTF8String], &contactDB)==SQLITE_OK) {
NSString *query2 = [NSString stringWithFormat:#"INSERT INTO ABC(C,B,A) VALUES(%d,%d,'%#')",clInfo.c,clInfo.b, clInfo.a];
if(sqlite3_prepare_v2(database, [query2 UTF8String], -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
if(SQLITE_DONE != sqlite3_step(addStmt))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
else
NSLog(#"Insertion Successful");
sqlite3_reset(addStmt);
return 0;
}
So please tell me how to solve my problem.
From the limited code you've posted, I think the answer has to do with that you have two different sqlite3 instances here. Was this intentional?
You call sqlite3_open([destPath UTF8String], &contactDB);
and then attempt to get an error result off another sqlite instance:
sqlite3_errmsg(database)
Either use database or contactDB and you should be all set.
I am trying to insert a set of values in an sqlite table using a for loop. It is inserting only one set of value. I am posting here my code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:#"myDatabase.sql"];
for(int i=0;i<[arr count];i++)
{
sqlite3 *database;
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(#"\n inserting data \n");
sqlite3_exec(database, [[NSString stringWithFormat:#"INSERT INTO AnswerConnect VALUES('%#')",[arr objectAtindex:i] ] UTF8String], NULL, NULL, NULL);
//sqlite3_finalize(compiledStatement);
sqlite3_close(database);
}
}
Thanks in advance.
You have to first prepare a sqlite statement to insert data in table.Try this :
sqlite3_stmt *statement = nil
const char *sql = "insert into tablename (col1,col2) Values( ?, ?)";
if(sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK)
{
NSLog(#"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
for(int i=0;i<[arr count];i++)
{
sqlite3_bind_text(statement, 1,[[arr objectAtindex:i] UTF8String] , -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(add_statement))
{
NSLog(#"Error while inserting result data. '%s'", sqlite3_errmsg(database));
}
//Reset the add statement.
sqlite3_reset(statement);
}
Don't do like that! Don't open/close SQLite connection in loop like that! Open handle to database outside from loop and than just use pointer on it. In this kind of request it's unsafe to insert format, because SQL statement may be compiled with some kind of injection code. Use sqlite3_stmt instead and bind values to it. Also if you compile only one instance of sqlite3_stmt and reuse it, this will give you better performance than compiling new statements all the time.
How many columns in each data set? Does it insert only one value from single data set like string?
I have an application that needs a database. The application is running fine in the simulator. But when i try to deploy it onto the iphone then it gives me the error that 'no such table animal'. Where is the problem? I am providing the code for better understanding
(void)viewDidLoad
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"AnimalDatabase.sql"];
sqlite3 *database;
if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK)
{
const char *sqlStatement = "insert into animal (id, name) VALUES (?, ?)";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK)
{
//NSLog(filePath);
sqlite3_bind_int(compiledStatement, 1, 12);
//NSLog(#"A");
sqlite3_bind_text( compiledStatement, 2, [#"abc" UTF8String], -1, SQLITE_TRANSIENT);
//NSLog(#"B");
if(sqlite3_step(compiledStatement) != SQLITE_DONE )
{
//NSLog(#"C");
NSLog( #"Error: %s", sqlite3_errmsg(database) );
}
else
{
//NSLog(#"D");
NSLog( #"Insert into row id = %d", sqlite3_last_insert_rowid(database));
}
}
else
{
NSAssert1(0, #"Error while creating insert statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_finalize(compiledStatement);
}
else
{
NSLog(#"Error Occured");
}
sqlite3_close(database);
[super viewDidLoad];
}
I think you need to look at what is being transfered to your iPhone. I had issues with this, there are some strange issues around how the database is created or not created on the actual iPhone. I think what is happening in your case is that no database is being transfered, and then your call to
sqlite3_open
is actually creating the database so you don't receive an error until you call a select statement.
Check your documentation on where to place the db in your resources to ensure it is copied to your iPhone when building.
The most likely reason is that the AnimalDatabase.sql file doesn't exist so there is no Animal table to insert into.
I have a really frustrating error that I've spent hours looking at and cannot fix. I can get data from my db no problem with this code, but inserting or updating gives me these errors:
*** Assertion failure in +[Functions db_insert_answer:question_type:score:], /Volumes/Xcode/Kanji/Classes/Functions.m:129
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error inserting: db_insert_answer:question_type:score:'
Here is the code I'm using:
[Functions db_insert_answer:[[dict_question objectForKey:#"JISDec"] intValue] question_type:#"kanji_meaning" score:arc4random() % 100];
//update EF, Next_question, n here
[Functions db_update_EF:[dict_question objectForKey:#"question"] EF:EF];
To call these functions:
+(sqlite3_stmt *)db_query:(NSString *)queryText{
sqlite3 *database = [self get_db];
sqlite3_stmt *statement;
NSLog(queryText);
if (sqlite3_prepare_v2(database, [queryText UTF8String], -1, &statement, nil) == SQLITE_OK) {
} else {
NSLog(#"HMM, COULDNT RUN QUERY: %s\n", sqlite3_errmsg(database));
}
sqlite3_close(database);
return statement;
}
+(void)db_insert_answer:(int)obj_id question_type:(NSString *)question_type score:(int)score{
sqlite3 *database = [self get_db];
sqlite3_stmt *statement;
char *errorMsg;
char *update = "INSERT INTO Answers (obj_id, question_type, score, date) VALUES (?, ?, ?, DATE())";
if (sqlite3_prepare_v2(database, update, -1, &statement, nil) == SQLITE_OK) {
sqlite3_bind_int(statement, 1, obj_id);
sqlite3_bind_text(statement, 2, [question_type UTF8String], -1, NULL);
sqlite3_bind_int(statement, 3, score);
}
if (sqlite3_step(statement) != SQLITE_DONE){
NSAssert1(0, #"Error inserting: %s", errorMsg);
}
sqlite3_finalize(statement);
sqlite3_close(database);
NSLog(#"Answer saved");
}
+(void)db_update_EF:(NSString *)kanji EF:(int)EF{
sqlite3 *database = [self get_db];
sqlite3_stmt *statement;
//NSLog(queryText);
char *errorMsg;
char *update = "UPDATE Kanji SET EF = ? WHERE Kanji = '?'";
if (sqlite3_prepare_v2(database, update, -1, &statement, nil) == SQLITE_OK) {
sqlite3_bind_int(statement, 1, EF);
sqlite3_bind_text(statement, 2, [kanji UTF8String], -1, NULL);
} else {
NSLog(#"HMM, COULDNT RUN QUERY: %s\n", sqlite3_errmsg(database));
}
if (sqlite3_step(statement) != SQLITE_DONE){
NSAssert1(0, #"Error updating: %s", errorMsg);
}
sqlite3_finalize(statement);
sqlite3_close(database);
NSLog(#"Update saved");
}
+(sqlite3 *)get_db{
sqlite3 *database;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *copyFrom = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"/kanji_training.sqlite"];
if([fileManager fileExistsAtPath:[self dataFilePath]]) {
//NSLog(#"DB FILE ALREADY EXISTS");
} else {
[fileManager copyItemAtPath:copyFrom toPath:[self dataFilePath] error:nil];
NSLog(#"COPIED DB TO DOCUMENTS BECAUSE IT DIDNT EXIST: NEW INSTALL");
}
if (sqlite3_open([[self dataFilePath] UTF8String], &database) != SQLITE_OK) {
sqlite3_close(database); NSAssert(0, #"Failed to open database");
NSLog(#"FAILED TO OPEN DB");
} else {
if([fileManager fileExistsAtPath:[self dataFilePath]]) {
//NSLog(#"DB PATH:");
//NSLog([self dataFilePath]);
}
}
return database;
}
+ (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"kanji_training.sqlite"];
}
I really can't work it out! Can anyone help me?
Many thanks.
in db_insert_answer, you prepare your statement
if the prepare is SQLITE_OK, you bind your variables
however, regardless of preparation OK or not, you run the statement (which could be invalid)
you also do the same thing in db_update_EF
start there
char *update = "UPDATE Kanji SET EF = ? WHERE Kanji = '?'";
Replace it with
char *update = "UPDATE Kanji SET EF = ? WHERE Kanji = ?";
It's already a string. You don't need single quotes around that question mark.
I have a problem with my app it opens this database and selects rows from it ok,
Then when I want to add new rows using the following code and I always get the following problem at the execution of the prepare_V2.
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error while creating add statement. 'out of memory''
code is .....
static sqlite3 *database = nil;
static sqlite3_stmt *addStmt = nil;
- (BOOL)addUserprofile {
addStmt = nil; // set to force open for testing
database = nil; // set to force creation of addstmt for testing
if (database == nil) { // first time then open database
NSString *databaseName = #"UserProfile.db";
// Use editable database paths
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSLog(#"path = %#",databasePath);
NSLog(#"opening Database");
sqlite3 *database;
// Open the database from the users filessytem
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(#"Database Open");
}
else {
NSLog(#"Database did not open");
}
}
if(addStmt == nil) {
NSLog(#"Creating add stmt");
const char *sql = "INSERT INTO Profile (ProfileName) VALUES(?)";
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK) {
NSAssert1(0, #"** Error while creating add statement. '%s'", sqlite3_errmsg(database));
success = NO;
return success;
}
}
sqlite3_bind_text(addStmt, 1, [ProfileName UTF8String], -1, SQLITE_TRANSIENT);
Sometime, your database is being SQLITE_BUSY or SQLITE_LOCKED.
You can refer this framework to know how to do:
https://github.com/ccgus/fmdb
Good luck!:)