sqlite3 create table problems - objective-c

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

Related

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.

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

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.

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)

Sqlite3 INSERT INTO Question × 377

I am creating an exercise app that will record the weight used and the number of "reps" the user did in 4 "Sets" per day over a period of 7 days so the user may view their progress.
I have built the database table named FIELDS with 2 columns ROW and FIELD_DATA and I can use the code below to load the data into the db. But the code has a sql statement that says,
INSERT OR REPLACE INTO FIELDS (ROW, FIELD_DATA)VALUES (%d, '%#');
When I change the statment to:
INSERT INTO FIELDS (ROW, FIELD_DATA)VALUES (%d, '%#');
Nothing happens. That is no data is recorded in the db.
Below is the code:
#define kFilname #"StData.sqlite3"
- (NSString *)dataFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilname];
}
-(IBAction)saveData:(id)sender;
{
for (int i = 1; i <= 8; i++)
{
NSString *fieldName = [[NSString alloc]initWithFormat:#"field%d", i];
UITextField *field = [self valueForKey:fieldName];
[fieldName release];
NSString *insert = [[NSString alloc] initWithFormat:
#"INSERT OR REPLACE INTO FIELDS (ROW, FIELD_DATA)
VALUES (%d, '%#');",i, field.text];
// sqlite3_stmt *stmt;
char *errorMsg;
if (sqlite3_exec (database, [insert UTF8String],
NULL, NULL, &errorMsg) != SQLITE_OK)
{
// NSAssert1(0, #"Error updating table: %s", errorMsg);
sqlite3_free(errorMsg);
}
}
sqlite3_close(database);
}
So how do I modify the code to do what I want? It seemed like a simple sql statement change at first but obviously there must be more. I am new to Objective-C and iPhone programming.
I am not new to using sql statements as I have been creating web apps in ASP for a number of years.
Any help will be greatly appreciated, this is driving me nuts!
Suggestions:
write an insert statement with hardcoded values to see if the insert works
your filename has no path. does it assume the current directory when executed? what directory is it running from?
write a message to the screen if possible to see what the values you're getting are. Are they correct?

Encoding problem in sqlite and objective-c

I have a file with contents something like this:
INSERT INTO table VALUES (NULL,'° F','Degrees Fahrenheit');
INSERT INTO table VALUES (NULL,'° C','Degrees Celsius');
Now, to parse this, I have something like this:
NSString *sql = [NSString stringWithContentsOfFile:filename];
Printing this string to the console looks correct. Then, I want to make an actual insert statement out of it:
const char *sqlString = [query UTF8String];
const char *endOfString;
if (sqlite3_prepare_v2(db, sqlString + nextStatementStart, -1, &stmt, &endOfString) != SQLITE_OK) {
return NO;
}
At this point, checking the query still returns the correct result. That is, sqlite_sql(stmt) returns INSERT INTO table VALUES (NULL,'° F','Degrees Fahrenheit');
So then I run it with sqlite3_step(stmt);
At this point, viewing the database reveals this:
1|° F|Degrees Fahrenheit
I'm not using any _16 functions anywhere (like sqlite_open16).
Where is the encoding issue? How do I fix this?
stringWithContentsOfFile: is deprecated as of OSX 10.4 (not sure about iPhone), but you want to specify the encoding here using stringWithContentsOfFile:encoding:error
file contains:
CREATE TABLE myvalues (foo TEXT, bar TEXT, baz TEXT);
INSERT INTO myvalues VALUES (NULL,'° F','Degrees Fahrenheit');
test.m contains (no error handling provided):
int main(int argc, char** argv)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSString* s = [NSString stringWithContentsOfFile:#"file"
encoding:NSUTF8StringEncoding
error:nil];
NSLog(#"s: %#", s);
sqlite3* handle;
sqlite3_open("file.db", &handle);
sqlite3_exec(handle, [s UTF8String], NULL, NULL, NULL);
sqlite3_close(handle);
[pool release];
}
Then dumping:
% sqlite3 file.db
SQLite version 3.6.12
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .dump
BEGIN TRANSACTION;
CREATE TABLE myvalues (foo TEXT, bar TEXT, baz TEXT);
INSERT INTO "myvalues" VALUES(NULL,'° F','Degrees Fahrenheit');
COMMIT;