sqlite3 COUNT in iOS (specifically ON the iPhone/iPad) - objective-c

I know that the simulator and the actual iOS hardware are not EXACTLY the same, but I'm starting to pull my hair out over this one. I have this code:
sqlite3 *database;
sqlite3_stmt *statement;
int themeCount;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSString *updateSQL = [NSString stringWithFormat: #"SELECT COUNT(*) FROM Theme"];
const char *update_stmt = [updateSQL UTF8String];
if(sqlite3_prepare_v2(database, update_stmt, -1, &statement, NULL) == SQLITE_OK){
if(sqlite3_step(statement)==SQLITE_ROW)
{
themeCount = sqlite3_column_int(statement, 0);
}
}
sqlite3_finalize(statement);
sqlite3_close(database);
}
With the simulator, it works perfectly fine. Once I push it to my devices, it fails. I've broken it down and came up with the return code where it fails:
if(sqlite3_prepare_v2(database, update_stmt, -1, &statement, NULL) == SQLITE_OK)
If I change that line to capture the code (ie. int x = sqlite3_prepare_v2(...)) it returns 0 with the simulator, 1 with the device. What am I doing wrong here?!?!
Also, for the record, the CREATE statement for the Theme table is:
#"CREATE TABLE Theme (ThemeId INTEGER PRIMARY KEY, ThemeName TEXT, Available BIT);"
(My first thought is that it was case sensitive)

You are not opening the database you think you are opening. The sqlite3_prepare_v2 is the first statement that needs the schema to be present. I suspect your databasePath is incorrect.
You can be more specific with sqlite3_open_v2 by omitting the SQLITE_OPEN_CREATE flag which is the default with sqlite3_open so you don't notice that a new database is being created by the open call. See SQLite3 docs. With the result of
sqlite3_open_v2([databasePath UTF8String], &database, SQLITE_OPEN_READWRITE, NULL)
you will see that the database does not exist.

Related

sqlite3 create table problems

I have an app I'm developing that will store soccer match statistics but I'm having trouble with my sqlite database. My save method is this :
-(void) saveData{
NSString *databasePath;
sqlite3_stmt *statement;
const char *dbpath =[databasePath UTF8String];
char *errMsg;
NSString *games;
games= #"games";
NSString *entree =[NSString stringWithFormat:#"create table if not exists %#(id integer, home text, away text)", games];
if (sqlite3_open(dbpath, &_gameFile)==SQLITE_OK){
if(sqlite3_exec(_gameFile, [entree UTF8String], NULL, NULL, &errMsg) !=SQLITE_OK){
NSLog(#"executing %s", sqlite3_errmsg(_gameFile));
} else {
NSLog(#"table created (%#)", entree);
}
}
sqlite3_close(_gameFile);
if (sqlite3_open(dbpath, &_gameFile)==SQLITE_OK){
NSString *insertSQL = [NSString stringWithFormat:#"INSERT INTO games (id, home, away) VALUES (\"%#\",\"%#\",\"%#\")", dataPoints[0], dataPoints[1], dataPoints[2]];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(_gameFile, insert_stmt, -1, &statement, NULL);
int rc =sqlite3_step(statement);
if(sqlite3_step(statement) == SQLITE_DONE){
NSLog(#"success");
NSLog(#"tried to enter %#" , insertSQL);
} else if(sqlite3_step(statement) == SQLITE_MISUSE){
NSLog(#"%#", insertSQL);
NSLog(#"Error %s while preparing statement", sqlite3_errmsg(_gameFile));
}
sqlite3_finalize(statement);
sqlite3_close(_gameFile);
}
}
This produces the following entries in the log:
2014-12-10 15:25:32.752 Footy Predictor[1718:513765] table created (create table if not exists games(id integer, home text, away text))
2014-12-10 15:25:32.759 Footy Predictor[1718:513765] INSERT INTO games (id, home, away) VALUES ("1446","Den Haag","Excelsior")
2014-12-10 15:25:32.760 Footy Predictor[1718:513765] Error no such table: games while preparing statement
I'm not really sure where I'm going wrong as the log says table created, and then says no such table.
Any help would be greatly appreciated.
I don't have an explicit answer for you because there are quite a few things that can go wrong with sqlite.
The main thing I can see is that you are not initialising databasePath. This needs to be a path to the .db file e.g. ~/Desktop/myDatabase.db.
1) I assume that you only want to process the statement once and you are actually inserting it 3 times. you need to check the value of rc i.e. only call sqlite3_step once and then put rc into the if statements :
int rc =sqlite3_step(statement);
if(rc == SQLITE_DONE){
NSLog(#"success");
NSLog(#"tried to enter %#" , insertSQL);
} else {
NSLog(#"%#", insertSQL);
NSLog(#"Error %s while preparing statement", sqlite3_errmsg(_gameFile));
}
2) Check the return value of sqlite3_prepare_v2 for success.
3) You neeeeed to normalise your statements (documentation for sqlite3_bind), otherwise you will run into problems when your users enter wildcard characters e.g. "?" or statements like "DROP"
4) Have you considered using Core Data. It is sooo much easier (although not ideal for everyone's needs I know).

Objective C: SQLite where-statement wont work when running another method first

So basically I have an app that will provide tasks based on selected project. Both projects and tasks are stored in a SQLite database.
To get the current project id I compare the selected project (_selectedProject) to my database, to get the ID. This is done in my getSelectedProjectId method. However, when running this method in the getTasks method, the Where-statement wont work at all. If I don't run the getSelectedProjectId method first, it works just fine. Am I forgetting to release something? Or is it something else? Any ideas?
I'm pretty new to both SQLite and Objective C, so this may not be a complex issue. I have made sure the getSelectedProjectId method returns the correct project ID. I have also made sure the query that is run in the getTasks method is correct, and when running it through my terminal it returns a number of rows. In the app it returns nothing, provided I'm running the getSelectedProjectId somewhere in that method first.
This is the method that fetches the tasks:
- (void)getTasks
{
[self openDB];
sqlite3_stmt *statement;
int projectId = [self getSelectedProjectId];
NSString *query = [NSString stringWithFormat:#"SELECT * FROM tasks WHERE project_id=%i", projectId];
const char *query_statement = [query UTF8String];
sqlite3_prepare_v2(_contactDB, query_statement, -1, &statement, NULL);
while (sqlite3_step(statement) == SQLITE_ROW)
{
// I add the task title to my array of tasks here.
}
sqlite3_finalize(statement);
sqlite3_close(_contactDB);
}
And this is the method that gets the correct project id from the database:
- (int)getSelectedProjectId
{
sqlite3_stmt *statement;
NSString *query = [[NSString alloc]
initWithFormat:#"SELECT id FROM projects WHERE title=\"%#\" LIMIT 0,1",
_selectedProject];
int rowId = 0;
const char *query_statement = [query UTF8String];
[self openDB];
sqlite3_prepare_v2(_contactDB, query_statement, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_ROW)
{
rowId = sqlite3_column_int(statement, 0);
}
sqlite3_finalize(statement);
sqlite3_close(_contactDB);
return rowId;
}
The problem occured because I closed the DB connection in my getSelectedProjectId-method. I'm now leaving my DB open instead, works like a charm.

How to execute this sqlite instruccions from code?

I need to export the information of my database to a csv file. I already know how to do that in sqlite but i need to do it from the code of an ios aplication.
I have to execute this from code.
.separator ,
.mode csv
.output test.csv
select * from tbl1;
.output stdout
I mean those arenĀ“t instructions like inserts or updates or deletes or selects...(well only one)
I tried something like this:
sqlite3_stmt *statement;
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_bdcontact) == SQLITE_OK) {
NSString *querySQLite = #".separator ,";
const char *querySQLite_stmt = [querySQLite UTF8String];
sqlite3_prepare_v2(_bdcontact, querySQLite_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE) {
NSLog(#"Did what i need and just repeat this with the other instructions!");
}
sqlite3_finalize(statement);
sqlite3_close(_bdcontact);
}
I have already done instructions like selects, inserts, updates and deletes in other parts of the application so the problem is when i try to do sqlite pure instructions.
Can You help me Please?

Retrieving an integer value from a sqlite3 db (problem in obj-c)

In a sqlite3 database, I've a table "data" with two fields: type and path. The field type is defined as INTEGER. In this field I insert a NSUInteger value (which will be for example 0 or 1). The problem is that, when I retrieve it, I obtain a "strange" value. I don't know where I'm wronging.
if (init_statement == nil) {
const char *sql = "SELECT type,path FROM data WHERE id=?";
if (sqlite3_prepare_v2(database, sql, -1, &init_statement, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
}
sqlite3_bind_int(init_statement, 1, primaryKey);
if (sqlite3_step(init_statement) == SQLITE_ROW) {
int type = (int)sqlite3_column_text(init_statement, 0);
char *relPath = (char *)sqlite3_column_text(init_statement, 1);
// other stuff
}
// Reset the statement for future reuse.
sqlite3_reset(init_statement);
SQLite allows only 64 bit signed integers. You are assigning it an unsigned integer. Change it to NSInteger instead.

Getting number of rows from SQLite C interface in Objective-C

I am new to objective-C and iphone apps.
I am accessing SQLite and have 3 rows in my table "coffee". I used the following way to grab sth out from the table, however, only then 2nd and 3rd rows are being pulled out {the 1st row is always missed}. Is that due to the logic in my while loop by checking while sqlite3_step(selectstmt) returns SQLITE_ROW is wrong? Here is the code:
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
const char *sql = "select coffeeID, coffeeName from coffee";
sqlite3_stmt *selectstmt;
NSLog(#"sqlite_prepare_v2 returns: %i", sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL));
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
NSLog(#"sqlite3_step returns: %i", sqlite3_step(selectstmt));
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)];
NSLog(#"this is the coffee name: %#", coffeeObj.coffeeName);
coffeeObj.isDirty = NO;
[appDelegate.coffeeArray addObject:coffeeObj];
[coffeeObj release];
}
}
}
On the other hand, is there any convenient way for me to check the number of rows returen in a query directly from the C interface of SQLite?
Many thanks.
You could use the query SELECT COUNT(*) FROM coffee to tell you how many rows there are.
And also, save yourself some headaches and use a SQLite wrapper.
Are the 2 sqlite3_step() calls meant to be executed here?
NSLog(#"sqlite3_step returns: %i", sqlite3_step(selectstmt));
while(sqlite3_step(selectstmt) == SQLITE_ROW {
BTW: there a parenthesis missing in the while line. Do not rewrite your code for SO. Copy/Paste it to avoid copying errors (pasting errors are much more rare)