unable to update or insert a row in a table - ios

I want to update a row in my iPhone app. Below is the code. It shows in my log that query is executed and row has been updated, but when I excess that table, it seems to be empty. And also it always updates a row even if I am trying to enter a row with new id, it should insert instead of updating in this case.
//create local database
NSString *docsDir = NULL;
NSArray *dirPaths = NULL;
sqlite3 *localDB = NULL;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"localscentsy1.db"]];
NSLog(#"%#",databasePath);
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement = NULL;
if (sqlite3_open(dbpath, &localDB) == SQLITE_OK)
{
NSString *updateSQL = [NSString stringWithFormat:#"UPDATE Ratings set rating = '%d' WHERE perfume_id = ?",
(int)rating];
const char *update_stmt = [updateSQL UTF8String];
if(sqlite3_prepare_v2(localDB, update_stmt, -1, &statement, NULL ) ==SQLITE_OK){
sqlite3_bind_int(statement, 1, tappedItem.perfumeId);
}
char* errmsg;
sqlite3_exec(localDB, "COMMIT", NULL, NULL, &errmsg);
if(SQLITE_DONE != sqlite3_step(statement)){
NSLog(#"Error while updating. %s", sqlite3_errmsg(localDB));
NSLog(#"query failed: %s", sqlite3_errmsg(localDB));
NSLog(#"%#",#"update unsuccessfull");
NSLog(#"New data, Insert Please");
sqlite3_stmt *statement2 = NULL;
NSString *insertSQL = [NSString stringWithFormat:
#"INSERT INTO Ratings (perfume_id,rating) VALUES (\"%d\",\"%d\")",
tappedItem.perfumeId,
(int)rating];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(localDB, insert_stmt, -1, &statement2, NULL);
if (sqlite3_step(statement2) == SQLITE_DONE)
{
NSLog(#"New data, Inserted");
}
sqlite3_finalize(statement2);
}
else{
NSLog(#"%#",#"update successfull");
sqlite3_finalize(statement);
}
sqlite3_close(localDB);
}
Any help will be appreciated. I am new at ios development and this code is taking so much of my time. Here is my log which always says "update successful"
CyberGenies/Library/Application Support/iPhone Simulator/7.0/Applications/24D2FEE2- DBE6-441A-AC79-1F2D57F96C88/Documents/localscentsy1.db
2014-07-27 01:03:26.612 Scentsy Squirrel[19008:a0b] update successfull

Have you seen if the db really has the structure? Some times when you start doing queries in an empty db (I mean not even tables) the query itself build the structure you are giving it on the query. You can check by compiling on the simulator and look for the db in the Mac finder.

Related

Issues when reading from a database in an iPhone app

I am making an iPhone app for a school project that reads and writes to a database. I have managed to get my code to write to it but it won't read. Below is the code I'm using to read:
NSString * paths=[self getWritableDBPath];
const char *dbpath = [paths UTF8String];
sqlite3_stmt *statement;
static sqlite3 *database = nil;
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"SELECT questionright, totalquestions, FROM results", nil];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
//code...
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
}
Here is getWritableDBPath:
-(NSString *) getWritableDBPath {
NSString *myDB = #"appData.db";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:myDB];
}
The reason it doesn't work is that the sqlite3_prepare_v2 if statement is never satisfied.
When I write to the database I copy it to documents.
I am quite sure the results table exists as I am able to write to it. Here is the original sql statement:
DROP TABLE IF EXISTS "Questions";
CREATE TABLE "Questions" ("QuestionID" INTEGER PRIMARY KEY NOT NULL , "Question" TEXT, "RightAnswer" TEXT, "WrongAnswer1" TEXT, "WrongAnswer2" TEXT, "Done" BOOL, "Catagory" TEXT, "Audio" INTEGER);
DROP TABLE IF EXISTS "Results";
CREATE TABLE "Results" ("ResultID" INTEGER PRIMARY KEY NOT NULL , "QuestionRight" INTEGER, "TotalQuestions" INTEGER, "Catagory" TEXT);
I did find a similar question on here but didn't think the answers were that relevant to me.
Thanks for your help.
If you want my advice, don't use the sqlite c libraries directly if you don't really need that, you can use FMDB library and get rid of all the c headache
https://github.com/ccgus/fmdb
You can simply do it like this
FMDatabase *db = [FMDatabase databaseWithPath:#"your full db path in documents goes here"];
if (![db open]) {
return;
}
FMResultSet *s = [db executeQuery:#"Your query goes here"];
if ([s next]) {
int totalCount = [s intForColumn:#"totalCount"];
}

IOS Sqlite3 Passing Opened database to a method

Using php for an example:
$conn = new mysqli('localhost', 'xxx', '123456', 'xxx');
Just define $conn once, I can pass $conn to all other methods, so that i don't need to repeat the connection again when I run another query, and it's a lot faster.
function example($conn) {
// do some db stuff here
}
Can I do the same thing in IOS sqlite3? Many thanks for helping.
- (void) syncScale {
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the database file
databasePath = [[NSString alloc]
initWithString: [docsDir stringByAppendingPathComponent:#"ALDI.db"]];
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
NSString *postSetting ;
postSetting = [NSString stringWithFormat:#"scaleData={\"scaleDB\":["];
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
NSString *querySQL = #"SELECT * From Table1";
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
// do something here
}
sqlite3_finalize(statement);
} else {
NSLog(#"Steps Data not found");
}
sqlite3_close(contactDB);
}
}
What I usually do, is that keep the opening of database in separate block/function with a boolean return ,rather finalize and rest the sqlite statement; Since the opening of database is made of almost static contents, the function doesn't need any parameters

SQLite3 not updating in iOS application

I have a table called Budgets that stores its settings, values, and a purchases nsarray full of the object purchases.
I am not sure what I am doing wrong in my method right here, but it will not update the database on an existing entry. It saves a new budget just fine.
- (BOOL) saveBudget:(Budget *)budget
{
BOOL success = false;
sqlite3_stmt *statement = NULL;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
if (budget.budgetID > 0) {
NSLog(#"Existing data, Update Please");
NSString *updateSQL = [NSString stringWithFormat:#"UPDATE BUDGETS set name = '%#', budget = '%#', customdate = '%d', customday = '%d', rolloverp = '%d', rollovern = '%d', purchases = ?8 WHERE id = ?", budget.name, budget.budget, budget.customDate, budget.customDay, budget.rolloverP, budget.rolloverN];
const char *update_stmt = [updateSQL UTF8String];
sqlite3_prepare_v2(database, update_stmt, -1, &statement, NULL);
sqlite3_bind_int(statement, 1, budget.budgetID);
sqlite3_bind_blob(statement, 8, [budget.purchases bytes], [budget.purchases length], SQLITE_TRANSIENT);
if (sqlite3_step(statement) == SQLITE_DONE)
{
success = true;
}
}
else
{
NSLog(#"New data, Insert Please");
NSString *insertSQL = [NSString stringWithFormat:#"INSERT INTO BUDGETS (name, budget, customdate, customday, rolloverp, rollovern, purchases) VALUES (\"%#\", \"%#\", \"%d\", \"%d\", \"%d\", \"%d\", ?8)", budget.name, budget.budget, budget.customDate, budget.customDay, budget.rolloverP, budget.rolloverN];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt, -1, &statement, NULL);
sqlite3_bind_blob(statement, 8, [budget.purchases bytes], [budget.purchases length], SQLITE_TRANSIENT);
if (sqlite3_step(statement) == SQLITE_DONE)
{
success = true;
}
}
sqlite3_finalize(statement);
sqlite3_close(database);
NSLog(#"Save Success");
}
return success;
}
I am assuming that the query is incorrect, but I may be wrong.
EDIT:
Here is how I am adding the database. Again, new entries are added and retrieved from the database just fine. Old entries are retrieved but will not update.
- (void) initDatabase
{
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
databasePath = [[NSString alloc] initWithString:
[docsDir stringByAppendingPathComponent:#"budget.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if([filemgr fileExistsAtPath:databasePath] == NO)
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString sql_stmt = #"CREATE TABLE IF NOT EXISTS BUDGETS (";
sql_stmt = [sql_stmt stringByAppendingString:#"id INTEGER PRIMARY KEY AUTOINCREMENT, "];
sql_stmt = [sql_stmt stringByAppendingString:#"name TEXT, "];
sql_stmt = [sql_stmt stringByAppendingString:#"budget DOUBLE, "];
sql_stmt = [sql_stmt stringByAppendingString:#"customdate INTEGER, "];
sql_stmt = [sql_stmt stringByAppendingString:#"customday INTEGER, "];
sql_stmt = [sql_stmt stringByAppendingString:#"rolloverp INTEGER, "];
sql_stmt = [sql_stmt stringByAppendingString:#"rollovern INTEGER, "];
sql_stmt = [sql_stmt stringByAppendingString:#"purchases BLOB)"];
if (sqlite3_exec(database, [sql_stmt UTF8String], NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(#"Failed to create table BUDGETS");
}
else
{
NSLog(#"BUDGETS table created successfully");
}
sqlite3_close(database);
}
else
{
NSLog(#"Failed to open/create database");
}
}
}
ANOTHER QUESTION:
I also have a question on whether I am saving the purchases NSArray correctly or not. I assumed that this would work.
Make sure the Location your pointing to the SQlite data base is right.And before executing the query make sure the table is in open state and ready to the operation. Refer this code:
sqlite3_stmt *statement;
sqlite3 *cPDB;
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Data base path
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"cPDB.db"]];
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &cPDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"UPDATE USER_SESSION_INFO SET \"%#\" = \"%#\", synState = 'false' WHERE sessionName=\"%#\"",categoryTy,state,sessionName];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(cPDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if((sqlite3_step(statement)) != SQLITE_DONE)
NSLog(#"Not Updated");
else
{
NSLog(#"Succesfully updated row !");
return YES;
}
}
}
Found the problem. There were no single quotes around ?8 in the update statement. Well, its always the small problems. Thanks everyone!

Objective-c sql error - error with statement look like empty result

hi i'm getting stuck with some code. i have a file catalog.db and a class that let me work with it. When i try to retrieve datas from the db it seems like it's empty. With several nslog i can see that it connect and enter the database, i can see it enter in it but then it won't get any value from it.
i tried to see if the query was wrong with an external DB manager software and the query works fine...
this is my class
#import "DBAccess.h"
sqlite3* database;
#implementation DBAccess
-(id)init{
self = [super init];
if (self){
[self initializeDatabase];
}
return self;
}
-(void)initializeDatabase{
NSString *path = [[NSBundle mainBundle]pathForResource:#"catalog" ofType:#"db"];
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) { NSLog(#"Opening Database"); }
else {
sqlite3_close(database);
NSAssert1(0, #"FAILED to open database '%s'", sqlite3_errmsg(database));
}
}
-(void)closeDatabase{
if (sqlite3_close(database) != SQLITE_OK){
NSAssert1(0, #"ERROR to close databse: '%s'", sqlite3_errmsg(database));
}
}
-(NSMutableArray *)getAllProduct{
NSMutableArray *products = [[NSMutableArray alloc]init];
const char *sql = "SELECT product.ID,product.Name, Manufacturer.name, product.details,product.price, product.quantityOnHand,country.country,product.image FROM product,manufacturer,country WHERE manufacturer.manufacturerID = product.manufacturerID and product.countryOfOriginID = country.countryID";
sqlite3_stmt *statement;
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
NSLog(#"sqlResult: %d", sqlResult);
if (sqlResult == SQLITE_OK){
NSLog(#"sql step statement: %d",sqlite3_step(statement));
NSLog(#"QUERY DONE");
while (sqlite3_step(statement) == SQLITE_ROW){
NSLog(#"TEST");
Product *product = [[Product alloc]init];
char *name = (char *)sqlite3_column_text(statement, 1);
NSLog(#"n %s",name);
char *manufacturer = (char *)sqlite3_column_text(statement, 2);
NSLog(#"m %s", manufacturer);
char *details = (char *)sqlite3_column_text(statement, 3);
NSLog(#"d %s", details);
char *countryoforigin = (char *)sqlite3_column_text(statement, 6);
NSLog(#"%s", countryoforigin);
char *image = (char *)sqlite3_column_text(statement, 7);
NSLog(#"%s", image);
product.ID = sqlite3_column_text(statement, 0);
product.name = (name)?[NSString stringWithUTF8String:name]:#"";
product.manufacturer = (manufacturer)?[NSString stringWithUTF8String:manufacturer]:#"";
product.details = (details)?[NSString stringWithUTF8String:details]:#"";
product.price = sqlite3_column_double (statement, 4);
product.quantity = sqlite3_column_int(statement, 5);
product.countryOfOrigin = (countryoforigin)?[NSString stringWithUTF8String:countryoforigin]:#"";
product.image = (image)?[NSString stringWithUTF8String:image]:#"";
[products addObject:product];
}
sqlite3_finalize(statement);
}
else {
NSLog(#"Problem with database %d",sqlResult);
}
return products;
}
#end
this is what i get in my console
2013-08-14 12:38:58.505 Catalog[1642:c07] Opening Database
2013-08-14 12:38:58.508 Catalog[1642:c07] sqlResult: 0
2013-08-14 12:38:58.509 Catalog[1642:c07] sql step statement: 101
2013-08-14 12:38:58.509 Catalog[1642:c07] QUERY DONE
2013-08-14 12:38:58.510 Catalog[1642:c07] ()
what can be my problem? thanks
Here
NSLog(#"sql step statement: %d",sqlite3_step(statement));
you fetch already the first row (without using the result).
1)Copy the database to your documents directory...
-(void) checkAndCreateDatabase{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:#"test.sqlite"];
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:databasePath];
// If the database already exists then return without doing anything
if(success) return;
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"test.sqlite"];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
2)Then talk to database in this way.
-(void)sqliteTransaction
{
sqlite3 *database;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:#"test.sqlite"];
// Init the animals Array
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "select * from me";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSLog(#"%#",aName);
// Create a new animal object with the data from the database
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
Try like this, before going to SELECT make sure the table is properly connected for selection with the open query like this
sqlite3_open(dbpath, &ProDB)
After that execute your selection. See this below sample code. Hope it will help
ex:
NSMutableArray *sessionDetails = [NSMutableArray array];
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"cPro.db"]];
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &ProDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"SELECT * FROM USER_SESSION_INFO"];
NSLog(#"query: %#",querySQL);
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(ProDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
// Your functionality.
}
}
}
i tried the method you guys suggested but i still get the same problem.
i think i found out what's causing it.
i changed my query with this:
const char *sql = "SELECT product.ID,product.Name, product.details,product.price, product.quantityOnHand,product.image FROM Product";
and this way it works... so it looks like i have trouble reading other tables...
the moment i add another table it stop working. but that's weird cause with external db manager software the query works just fine

How to iterate through sqlite_step result

Could someone be so kind as to fill in the few missing pieces of code below. I am struggling with executing an sqlite statement using sqlite3_step, iterating through each row of results and putting the data into a useable format.
Here is the code that creates the database (Database is only two colums)
// Check if database is setup, if not create it
NSString *documents_directory;
NSArray *directory_path;
// Get the documents directory
directory_path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documents_directory = [directory_path objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString: [documents_directory stringByAppendingPathComponent: #"weights.db"]];
NSFileManager *file_manager = [NSFileManager defaultManager];
// Create database if it doesn't already exist
if([file_manager fileExistsAtPath: databasePath ] == NO){
const char *database_path = [databasePath UTF8String];
if(sqlite3_open(database_path, &contactDB) == SQLITE_OK){
char *error_message;
const char *sql_statement = "CREATE TABLE IF NOT EXISTS RECORDED_WEIGHTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, WEIGHT TEXT, TIME TEXT)";
if(sqlite3_exec(contactDB, sql_statement, NULL, NULL, &error_message) != SQLITE_OK){
status.text = #"Failed to create table";
}
sqlite3_close(contactDB);
}else{
status.text = #"Failed to open/create database";
}
}
And here is the code I am trying to complete;
// Get info from database and load it.
const char *database_path = [databasePath UTF8String];
sqlite3_stmt *statement;
if(sqlite3_open(database_path, &contactDB) == SQLITE_OK){
NSString *SQLquery = [NSString stringWithFormat:#"SELECT * FROM RECORDED_WEIGHTS ORDER BY TIME DESC"];
const char *query_statement = [SQLquery UTF8String];
if(sqlite3_prepare_v2(contactDB, query_statement, -1, &statement, NULL) == SQLITE_OK){
// Please help me execute statement and get results into useable format here.
}
sqlite3_finalize(statement);
}
sqlite3_close(contactDB);
Thanks in advance.
You want to do something like this:
while(sqlite3_step(statement) == SQLITE_ROW)
{
// int value
int intValue = sqlite3_column_int(statement,fieldIndex);
// string value
NSString* stringValue;
if (sqlite3_column_type(dbps, fieldIndex) != SQLITE_NULL)
{
const char *c = (const char *)sqlite3_column_text(dbps, fieldIndex);
if (c)
{
stringValue = #(c);
}
}
... etc...
}
Look at the documents for the different column types. You can also look at different objective-c wrappers out there to get an idea of how to access the database.

Resources