Here is the code I am using to insert a record into the table... all I need is this function to capture and return back the inserted id of the record... is this possible? This code is working fine and returns YES for successful insert and NO for failures... but now im trying to return an integer insert id... but cant seem to figure out a way...
-(BOOL)insertEvent:(Event *)objEvent { Utils *objUtils = [[Utils alloc] init];
sqlite3_stmt *insertStmt = nil;
sqlite3 *aDatabase = nil;
int ret = sqlite3_enable_shared_cache(1);
if (sqlite3_open([databasePath UTF8String], &aDatabase) == SQLITE_OK)
{
if(insertStmt == nil)
{
NSString *aString = [NSString stringWithFormat:#"INSERT INTO tblEvent ('eventstartdate','eventdescription') VALUES ('%#','%#')",objEvent.eventstartdate, objEvent.eventdescription];
const char *sql = [aString UTF8String];
if(sqlite3_prepare_v2(aDatabase, sql, -1, &insertStmt, NULL) != SQLITE_OK)
{
NSAssert1(0, #"Error while creating insertTip add statement. '%s'", sqlite3_errmsg(aDatabase));
return NO;
}
[objUtils release];
}
if(SQLITE_DONE != sqlite3_step(insertStmt)) {
NSAssert1(0, #"Error while inserting into TipsTracker. '%s'", sqlite3_errmsg(aDatabase));
return NO;
}
sqlite3_reset(insertStmt);
if (insertStmt)
{
sqlite3_finalize(insertStmt);
insertStmt = nil;
}
}
sqlite3_close(aDatabase);
aDatabase = nil;
return YES;}
try this function sqlite3_last_insert_rowid(database);
Related
my app crashed when I try to delete a data from my SqlLite db.
This is the error: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error while deleting. 'database is locked'
This is all my code on database:
#import "Database.h"
static sqlite3 *database = nil;
static sqlite3_stmt *deleteStmt = nil;
static sqlite3_stmt *addStmt = nil;
#implementation Database
#synthesize id_poi, pathDb, arrPoi;
- (id) initWithData:(NSDictionary *) data {
[super init];
NSLog(#"%#",[data objectForKey:#"pathDb"]);
NSLog(#"id_poi = %#",[data objectForKey:#"id_poi"]);
//setto l'id nello stato dell'oggetto
id_poi = [data objectForKey:#"id_poi"];
pathDb = [data objectForKey:#"pathDb"];
return self;
}
- (void) deletePoi {
if (sqlite3_open([pathDb UTF8String], &database) == SQLITE_OK) {
const char *sql = "delete from Poi where id_poi = ?";
sqlite3_stmt *deleteStmt;
if(sqlite3_prepare_v2(database, sql, -1, &deleteStmt, NULL) == SQLITE_OK) {
//When binding parameters, index starts from 1 and not zero.
sqlite3_bind_int(deleteStmt, 1, [id_poi integerValue]);
if (SQLITE_DONE != sqlite3_step(deleteStmt)) {
NSAssert1(0, #"Error while deleting. '%s'", sqlite3_errmsg(database));
[[WPActivityIndicator sharedActivityIndicator] hide];
return;
}
} else {
NSAssert1(0, #"Error while creating delete statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_finalize(deleteStmt);
} else {
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
[[WPActivityIndicator sharedActivityIndicator] hide];
}
- (BOOL) checkIdPoi {
// lista temporanea
NSMutableArray *listaTemp = [[NSMutableArray alloc] init];
// Oggetto che contiene i vari elementi
NSMutableDictionary *dictionary;
NSMutableString *str_id_poi;//id della persona
if (sqlite3_open([pathDb UTF8String], &database) == SQLITE_OK) {
// query che ricava i valori
const char *sql = "select id_poi from Poi where id_poi = ?";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
sqlite3_bind_int(selectstmt, 1 , [id_poi integerValue]);
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
// ricaviamo i valori letti dalla query
str_id_poi = [NSMutableString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 0)];
// inseriamo tutti i valori letti in un unico oggetto
dictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:str_id_poi, #"id_poi", nil];
//NSLog(#"str_id_poi = %#",str_id_poi);
[listaTemp addObject:dictionary];
[dictionary release];
return TRUE;
}
} else {
NSAssert1(0, #"Error while read data. '%s'", sqlite3_errmsg(database));
return FALSE;
}
}
else {
sqlite3_close(database);
return FALSE;
}
return FALSE;
}
- (void) addPoi {
//NSLog(#"%#",pathDb);
if (sqlite3_open([pathDb UTF8String], &database) == SQLITE_OK) {
const char *sql = "insert into Poi(id_poi) Values(?)";
sqlite3_stmt *addStmt;
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) == SQLITE_OK) {
NSString *str_id_poi = [[NSString alloc] initWithFormat:#"%d", [id_poi integerValue]];
sqlite3_bind_text(addStmt, 1, [str_id_poi UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(addStmt)) {
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
[[WPActivityIndicator sharedActivityIndicator] hide];
return;
} else {
//SQLite provides a method to get the last primary key inserted by using sqlite3_last_insert_rowid
//id_poi = sqlite3_last_insert_rowid(database);
}
//Reset the add statement.
sqlite3_reset(addStmt);
} else {
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_finalize(addStmt);
} else {
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
sqlite3_close(database);
[[WPActivityIndicator sharedActivityIndicator] hide];
}
// Carica i valori dal database passato come parametro
-(NSMutableArray*)getIdPOI {
// lista temporanea
NSMutableArray *listaTemp = [[NSMutableArray alloc] init];
// Oggetto che contiene i vari elementi
NSMutableDictionary *dictionary;
NSMutableString *str_id_poi;//id della persona
if (sqlite3_open([pathDb UTF8String], &database) == SQLITE_OK) {
// query che ricava i valori
const char *sql = "select id_poi from Poi";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
// ricaviamo i valori letti dalla query
str_id_poi = [NSMutableString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 0)];
// inseriamo tutti i valori letti in un unico oggetto
dictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:str_id_poi, #"id_poi", nil];
//NSLog(#"str_id_poi = %#",str_id_poi);
[listaTemp addObject:dictionary];
[dictionary release];
}
//Reset the add statement.
sqlite3_reset(selectstmt);
} else {
NSAssert1(0, #"Error while read data. '%s'", sqlite3_errmsg(database));
}
//ADD THIS LINE TO YOUR CODE
sqlite3_finalize(selectstmt);
}
else
sqlite3_close(database);
sqlite3_close(database);
return listaTemp;
}
+ (void) finalizeStatements {
if(database) sqlite3_close(database);
if(deleteStmt) sqlite3_finalize(deleteStmt);
if(addStmt) sqlite3_finalize(addStmt);
}
-(void)dealloc {
[pathDb release];
[arrPoi release];
[super dealloc];
}
#end
Any suggest?
This type of error can occur when more then one query is fired for sqlite db. When you are executing any query, you need to synchronize all calls to the database.
Wrap all your database code in a #synchronized block like so:
#synchronized(self)
{
// database query code goes here
}
NB. this example assumes all database queries are executed from inside the 1 class. If not, you should replace 'self' with a common object instance that is shared by all classes that interface with the database. Alternatively, you can run all database statements on the main thread.
This usually happens when the database was opened and then not closed properly. It could be because you have the same instance of database opened from somewhere else.(Like a different class or SQLite manager).
It is usually advisable to create a singleton instance which communicates with your database rather opening and closing the database again and again.. hoping this helps.
I'm very confused why the SELECT statement doesn't work correctly. It doesn't give me any errors, just returns null. I know it is writing the string correctly and the right string is there, it's just not reading it correctly. Everything as far as I know is correct because I use the same SQLstmt "method" for many other methods/functions similar to this. This one just doesn't make sense on why it shouldn't work.
- (NSString *)returnNote {
selStmt=nil;
NSLog(#"Reading note");
NSString *SQLstmt = [NSString stringWithFormat:#"SELECT 'Notes' FROM '%#' WHERE Exercises = '%#';", currentRoutine, currentExercise];
// Build select statements
const char *sql = [SQLstmt UTF8String];
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK) {
selStmt = nil;
}
// Building select statement failed
if (!selStmt) {
NSAssert1(0, #"Can't build SQL to read Exercises [%s]", sqlite3_errmsg(database));
}
NSString *note = [NSString stringWithFormat:#"%s", sqlite3_column_text(selStmt, 0)];
sqlite3_reset(selStmt); // reset (unbind) statement
return note;
}
You're not calling sqlite3_step. The statement is never executed.
NSString *querySQLS1 = [NSString stringWithFormat: #"SELECT Notes FROM \"%#\" where Exercises=\"%#\"", currentRoutine, currentExercise];
sqlite3_stmt *statements;
const char *query_stmts1 = [querySQLS1 UTF8String];
if(sqlite3_prepare_v2(UsersDB, query_stmts1, -1, &statement, NULL) == SQLITE_OK)
{
NSLog(#"in prepare");
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"Query executed");
}
else {
NSLog(#"in else");
}
sqlite3_finalize(statement);
}
hii every one
i am using following method to insert data into data base , but it will save the first entered value only all the time
the following method is in the insertUpdateDelete class
- (void) InsertRecord {
if(addStmt == nil) {
NSString *nsql = [NSString stringWithFormat:#"insert into tbl_Users(FirstName,MiddleName) Values('%#','%#')",strFirstName,strMiddleName];
const char *sql = [nsql UTF8String];
if(sqlite3_prepare_v2(database, sql, -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
//SQLite provides a method to get the last primary key inserted by using sqlite3_last_insert_rowid
intID = sqlite3_last_insert_rowid(database);
//Reset the add statement.
sqlite3_reset(addStmt);
}
through following code i am calling this method, tfText[0] & tfText[1] are text field variable , problem is,, on every click of save after entering some data in text field, it will save only the first entered value into the data base
- (void) save_Clicked
{
iICS_testAppDelegate *appDelegate = (iICS_testAppDelegate *)[[UIApplication sharedApplication] delegate];
//Create a Items Object.
insertUpdateDelete *objInsertUpdateDelete = [[insertUpdateDelete alloc] init];
objInsertUpdateDelete.strFirstName = tfText[0].text;
objInsertUpdateDelete.strMiddleName = tfText[1].text;
[appDelegate InsertRecord:objInsertUpdateDelete];
}
can any one help me,,,,thanx in advance
const char *addRecord = "insert into Test(taskname, desc) values(?, ?)";
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(database, addRecord, -1, &statement, NULL) != SQLITE_OK)
{
NSLog(#"Error while Inserting Record :- '%s'", sqlite3_errmsg(database));
sqlite3_finalize(statement);
return -1;
}
sqlite3_bind_text(statement, 1, [Ttitle UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [Tdesc UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(statement))
{
NSLog(#"Error1 while Inserting Record :- '%s'", sqlite3_errmsg(database));
sqlite3_finalize(statement);
return -1;
}
else
{
NSLog(#"Record Inserted Successfully.");
sqlite3_finalize(statement);
return sqlite3_last_insert_rowid(database);
}
I'm using two methods to r/w sqlite table:
+ (NSString *) getWeatherData:(int)rowID:(int)columnID {
NSString *savedWeatherData = [[NSString alloc] init];
if (sqlite3_open([[DBController getDBPath] UTF8String], &database) == SQLITE_OK) {
const char *sql = "select * from TABLE where id=?";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
sqlite3_bind_int(selectstmt, 1, rowID);
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
Weather *weatherObj = [[Weather alloc] initWithPrimaryKey:primaryKey];
weatherObj.weatherData = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, columnID)];
savedWeatherData = weatherObj.weatherData;
[weatherObj release];
}
}
}
return [savedWeatherData autorelease];
}
And to save some data:
+ (void) saveDataToDataBase:(NSString *)columnToUpdate:(int)rowID:(NSString *)value {
if (sqlite3_open([[DBController getDBPath] UTF8String], &database) == SQLITE_OK) {
updateStmt = nil;
NSString *sqlString = [[#"update TABLE set " stringByAppendingString:columnToUpdate] stringByAppendingString:#"=? where id=?"];
const char *sql = [sqlString UTF8String];
if(sqlite3_prepare_v2(database, sql, -1, &updateStmt, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error while creating update statement. '%s'", sqlite3_errmsg(database));
} else { // select statement ok
sqlite3_bind_text(updateStmt, 1, [value UTF8String], -1, SQLITE_TRANSIENT); // replace first ? with value
sqlite3_bind_int(updateStmt, 2, rowID); // replace second ? with rowID
if(SQLITE_DONE != sqlite3_step(updateStmt)) {
NSAssert1(0, #"Error while updating. '%s'", sqlite3_errmsg(database));
} else {
// NSLog(#"Update completed !!!");
}
sqlite3_reset(updateStmt);
}
sqlite3_finalize(updateStmt);
}
else
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
With the Instruments, I see pretty big memory consumption for sqlite.
Info: during app startup, cca 100 different kind of data is stored in DB - for each data, this saveDataToDataBase method is called. (In case of no internet connection - getWeatherData would be used - and again cca 100 different kind of data would be read)
Please, can you instruct me - is it possible to optimize memory consumption.
Thanks a lot!
Kind regards!
I am creating an iPhone application which makes use of sqlite database. I have one table in my database. Initially there are no rows in my table. I want that when I insert a new record via my iPhone simulator that record should be automatically updated to my database. How Could this be possible. Please anybody help me in solving this problem.
+ (void) getInitialDataToDisplay:(NSString *)dbPath
{
SQLAppDelegate *appDelegate = (SQLAppDelegate *)[[UIApplication sharedApplication] delegate];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
const char *sql = "select coffeeID, coffeeName from coffee";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
Coffee *coffeeObj = [[Coffee alloc] initWithPrimaryKey:primaryKey];
coffeeObj.coffeeName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
coffeeObj.isDirty = NO;
[appDelegate.coffeeArray addObject:coffeeObj];
[coffeeObj release];
}
}
}
else
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
+ (void) finalizeStatements
{
if (database) sqlite3_close(database);
if (deleteStmt) sqlite3_finalize(deleteStmt);
if (addStmt) sqlite3_finalize(addStmt);
if (detailStmt) sqlite3_finalize(detailStmt);
if (updateStmt) sqlite3_finalize(updateStmt);
}
- (id) initWithPrimaryKey:(NSInteger) pk
{
[super init];
coffeeID = pk;
coffeeImage = [[UIImage alloc] init];
isDetailViewHydrated = NO;
return self;
}
- (void) deleteCoffee
{
if(deleteStmt == nil) {
const char *sql = "delete from Coffee where coffeeID = ?";
if(sqlite3_prepare_v2(database, sql, -1, &deleteStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating delete statement. '%s'", sqlite3_errmsg(database));
}
//When binding parameters, index starts from 1 and not zero.
sqlite3_bind_int(deleteStmt, 1, coffeeID);
if (SQLITE_DONE != sqlite3_step(deleteStmt))
NSAssert1(0, #"Error while deleting. '%s'", sqlite3_errmsg(database));
sqlite3_reset(deleteStmt);
}
- (void) addCoffee
{
if(addStmt == nil) {
const char *sql = "insert into Coffee(CoffeeName, Price) Values(?, ?)";
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_bind_text(addStmt, 1, [coffeeName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_double(addStmt, 2, [price doubleValue]);
if(SQLITE_DONE != sqlite3_step(addStmt))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
else
//SQLite provides a method to get the last primary key inserted by using sqlite3_last_insert_rowid
coffeeID = sqlite3_last_insert_rowid(database);
//Reset the add statement.
sqlite3_reset(addStmt);
}
- (void) hydrateDetailViewData
{
//If the detail view is hydrated then do not get it from the database.
if(isDetailViewHydrated) return;
if(detailStmt == nil) {
const char *sql = "Select price, CoffeeImage from Coffee Where CoffeeID = ?";
if(sqlite3_prepare_v2(database, sql, -1, &detailStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating detail view statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_bind_int(detailStmt, 1, coffeeID);
if(SQLITE_DONE != sqlite3_step(detailStmt)) {
//Get the price in a temporary variable.
NSDecimalNumber *priceDN = [[NSDecimalNumber alloc] initWithDouble:sqlite3_column_double(detailStmt, 0)];
//Assign the price. The price value will be copied, since the property is declared with "copy" attribute.
self.price = priceDN;
NSData *data = [[NSData alloc] initWithBytes:sqlite3_column_blob(detailStmt, 1) length:sqlite3_column_bytes(detailStmt, 1)];
if(data == nil)
NSLog(#"No image found.");
else
self.coffeeImage = [UIImage imageWithData:data];
//Release the temporary variable. Since we created it using alloc, we have own it.
[priceDN release];
}
else
NSAssert1(0, #"Error while getting the price of coffee. '%s'", sqlite3_errmsg(database));
//Reset the detail statement.
sqlite3_reset(detailStmt);
//Set isDetailViewHydrated as YES, so we do not get it again from the database.
isDetailViewHydrated = YES;
}
- (void) saveAllData
{
if(isDirty)
{
if(updateStmt == nil)
{
const char *sql = "update Coffee Set CoffeeName = ?, Price = ?, CoffeeImage = ? Where CoffeeID = ?";
if(sqlite3_prepare_v2(database, sql, -1, &updateStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating update statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_bind_text(updateStmt, 1, [coffeeName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_double(updateStmt, 2, [price doubleValue]);
NSData *imgData = UIImagePNGRepresentation(self.coffeeImage);
int returnValue = -1;
if(self.coffeeImage != nil)
returnValue = sqlite3_bind_blob(updateStmt, 3, [imgData bytes], [imgData length], NULL);
else
returnValue = sqlite3_bind_blob(updateStmt, 3, nil, -1, NULL);
sqlite3_bind_int(updateStmt, 4, coffeeID);
if(returnValue != SQLITE_OK)
NSLog(#"Not OK!!!");
if(SQLITE_DONE != sqlite3_step(updateStmt))
NSAssert1(0, #"Error while updating. '%s'", sqlite3_errmsg(database));
sqlite3_reset(updateStmt);
isDirty = NO;
}
//Reclaim all memory here.
[coffeeName release];
coffeeName = nil;
[price release];
price = nil;
isDetailViewHydrated = NO;
}
- (void)setCoffeeName:(NSString *)newValue
{
self.isDirty = YES;
[coffeeName release];
coffeeName = [newValue copy];
}
- (void)setPrice:(NSDecimalNumber *)newNumber
{
self.isDirty = YES;
[price release];
price = [newNumber copy];
}
- (void)setCoffeeImage:(UIImage *)theCoffeeImage
{
self.isDirty = YES;
[coffeeImage release];
coffeeImage = [theCoffeeImage retain];
}
Well, as I see you have this function +(void) finalizeStatements; where you close your DB and finalize your prepared queries.
First of all, you don't call this function from anywhere. Anyway if you are somehow calling this function, the code from is not correct, because you should first finalize all statements and only after that close the connection.
Read the documentation of sqlite3_close and sqlite3_finalize. What the documentation says about sqlite3_close:
Applications must [sqlite3_finalize | finalize] all [prepared statements] and [sqlite3_blob_close | close] all [BLOB handles] associated with the [sqlite3] object prior to attempting to close the object.
If that won't help you, try to finalize statements at the end of each method you prepare it.
Hope this helps you.
I'm not sure the database variable you've opened in getInitialDataToDisplay is still available when you try to addCoffee. Why don't you close that connection, and open a new one at the beginning of addCoffee (and close that when it completes)