SQLite Out of Memory when preparing insert statement - iphone

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!:)

Related

Unable to remove data from database ios

I have database, but when i tried to remove data from the database nothing happens, what should i do to make sure it works? Because when i pressed delete the dta is still in the database
This is the code:
/file path to database
-(NSString*)filePath {
NSArray*paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[paths objectAtIndex:0]stringByAppendingPathComponent:#"bp.sql"];
}
//open database
-(void)openDB {
if(sqlite3_open([[self filePath]UTF8String], &db) !=SQLITE_OK) {
sqlite3_close(db);
NSAssert(0, #"Databese failed to open");
}
else {
NSLog(#"database opemed");
}
}
- (IBAction)del:(id)sender {
NSString*sql = [NSString stringWithFormat:#"DELETE key, theDate, customer, code1, code2 FROM summary WHERE key=\"%#\"",customerName];
const char* query_stmt = [sql UTF8String];
sqlite3_stmt*statement;
sqlite3_prepare_v2(db, query_stmt, -1, & statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
NSAssert(0, #"database object delete failed");
} else {
NSLog(#"No error");
}
sqlite3_finalize(statement);
sqlite3_close(db)
You can't delete specific column values using the DELETE query. It's for removing the entire row.
The problem is with the following query:
NSString*sql = [NSString stringWithFormat:#"DELETE key, theDate, customer, code1, code2 FROM summary WHERE key=\"%#\"",customerName];
Change it to:
NSString*sql = [NSString stringWithFormat:#"DELETE FROM summary WHERE key=\"%#\"",customerName];
If you need to remove particular column value of a row use the UPDATE query.
Please check the sqlite documentation for the details
All the functions that you wrote like checking filepath, opendb should occur in the same function(maybe inside your del function).
This is how I will do it:
-(void)updateStatus:(NSString *)queryString {
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
strDatabasePath = [NSString stringWithString:[docsDir stringByAppendingPathComponent:#"bp.sql"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: strDatabasePath] == YES)
{
const char *dbpath = [strDatabasePath UTF8String];
if (sqlite3_open(dbpath, &sqlDatabase) == SQLITE_OK)
{
const char* beginString = "BEGIN;";
sqlite3_stmt *compiledstatement;
sqlite3_prepare_v2(sqlDatabase, beginString, -1, &compiledstatement, NULL);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else DLog(#"Failed!");
sqlite3_finalize(compiledstatement);
DLog(#"QUERY : %#",queryString);
const char *selectStatement = [queryString UTF8String];
sqlite3_prepare_v2(sqlDatabase, selectStatement, -1, &compiledstatement, NULL);
//sqlite3_bind_text(compiledstatement,1,[statusString UTF8String],-1,SQLITE_TRANSIENT);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else DLog(#"Failed!");
sqlite3_finalize(compiledstatement);
const char* endString="END;";
sqlite3_prepare_v2(sqlDatabase, endString, -1, &compiledstatement, NULL);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else DLog(#"Failed!");
sqlite3_finalize(compiledstatement);
sqlite3_close(sqlDatabase);
}
else DLog(#"Failed to open table");
}
}
NSString *queryString;
queryString = [NSString stringWithFormat:#"DELETE key, theDate, customer, code1, code2 FROM summary WHERE key=\"%#\"",customerName];
[self updateStatus:queryString];
Hope this helps...
-(BOOL)DeleteWishList:(int)rowno
{
NSString *queryString=[NSString stringWithFormat:#"delete from wishtable where _id=%d",rowno];
[self openDB];
char *err;
if (sqlite3_exec(dBObject, [queryString UTF8String], NULL,NULL, &err)!= SQLITE_OK)
{
sqlite3_close(dBObject);
return NO;
}
else
{
return YES;
}
}

SQLite iPhone - Insert Fails

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

Difficulty deploying database with my iphone app

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.

Assertion failure when trying to write (INSERT, UPDATE) to sqlite database on iPhone

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.

iphone sqlite3 object allocation memory up but no leaks

i've been trying to figure out wh. sqy my object allocation keeps rigth up every time i call this function, Instruments reports no leaks but I get a heck of a lot of object coming from
sqlite3_exec --> sqlite3Prepare --> sqlite3Parser --> yy_reduce --> malloc & also a whole bunch from
& from
sqlite3Step --> sqlite3VdbeExec --> sqlite3BtreeInsert --> malloc
I tried solving it by following the suggestions posted here: http://www.iphonedevsdk.com/forum/iphone-sdk-development/7092-sqlite3-database-gobbling-up-memory.html but haven't been able to fix it
ANY HELP is appreciated, my code is below
+(void)getDesignationsInLibrary:(NSString *)library
{
NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init];
NSString *dbName = #"s8.sqlite";
NSArray *documentPaths = \
NSSearchPathForDirectoriesInDomains \
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = \
[documentPaths objectAtIndex:0];
NSString *databasePath = \
[documentsDir stringByAppendingPathComponent:dbName];
[[DT sharedDT].designationsInLibrary removeAllObjects];
NSString *sqlString;
for(int i=0;i<[[DT sharedDT].typesInLibrary count];i++)
{
if(sqlite3_open([databasePath UTF8String], &db)==SQLITE_OK)
{
if (sqlite3_exec(db, "PRAGMA CACHE_SIZE=50;", NULL, NULL, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error: failed to set cache size with message '%s'.", sqlite3_errmsg(db));
}
NSMutableString *lib=[NSMutableString stringWithString:library];
[lib appendString:#"-"];
[lib appendString:[[DT sharedDT].typesInLibrary objectAtIndex:i]];
if([DT sharedDT].sortedBy==#"AISC Default")
{
sqlString = [NSString stringWithFormat:#"select DESIGNATION from \"%#\";",lib];
}
else
{
sqlString = [NSString stringWithFormat:#"select DESIGNATION from \"%#\" order by cast(%# as numeric) %#;",lib, [DT sharedDT].sortedBy, [DT sharedDT].sortAscDesc];
}
const char *sql = [sqlString cStringUsingEncoding:NSASCIIStringEncoding];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(db,sql,-1,&selectstmt, NULL)==SQLITE_OK)
{
while(sqlite3_step(selectstmt)==SQLITE_ROW)
{
[[DT sharedDT].designationsInLibrary addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt,0)]];
}
sqlite3_finalize(selectstmt);
selectstmt=nil;
}
}
}
sqlite3_close(db);
[localPool release];
}
It seems, that you're opening db on every loop cycle, but close only once, before function exit
So try to change:
}
sqlite3_close(db);
[localPool release];
}
to
sqlite3_close(db);
}
[localPool release];
}
Or even better change:
for(int i=0;i [[DT sharedDT].typesInLibrary count];i++)
{
if(sqlite3_open([databasePath UTF8String], &db)==SQLITE_OK)
{
if (sqlite3_exec(db, "PRAGMA CACHE_SIZE=50;", NULL, NULL, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error: failed to set cache size with message '%s'.", sqlite3_errmsg(db));
}
to:
if(sqlite3_open([databasePath UTF8String], &db)==SQLITE_OK)
{
if (sqlite3_exec(db, "PRAGMA CACHE_SIZE=50;", NULL, NULL, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error: failed to set cache size with message '%s'.", sqlite3_errmsg(db));
}
for(int i=0;i [[DT sharedDT].typesInLibrary count];i++)
{
...
because you're always open the same database
Try invoking sqlite3_exec with:
pragma cache_size=1
Sqlite seems to gobble up memory for caching.