i've got a Problem when i try to get data from the Database after inserting some data. I can't select any row from the database.
There are entries in the database but i can not get any result.
I comment out this line in AppDelegate::application:didFinishWithOptions
[dbAccess importWithDelegate:result];
and everything works just fine. But i can't find a solution to this problem.
I hope you can help me.
DatabaseAccess-Class.
#import "KejithDatabaseAccess.h"
#import "KejithEntryQueryDelegate.h"
#interface KejithDatabaseAccess (){
sqlite3 *db;
NSString *writableDatabase;
sqlite3_stmt *statement;
}
#end
#implementation KejithDatabaseAccess
-(id)init
{
if((self = [super init]))
{
// initialize database and store in _db
}
return self;
}
-(void)initializeDatabase
{
[self createEditableDatabase];
// open the database connection
if(sqlite3_open([writableDatabase UTF8String], &db) == SQLITE_OK){
NSLog(#"Database: Connection was opened successfully");
} else {
// if something went wrong clean everything up
sqlite3_close(db);
NSAssert1(0, #"Database: Failed to open database connection. Error: '%s'", sqlite3_errmsg(db));
}
}
-(void)closeDatabase
{
if(sqlite3_close(db) != SQLITE_OK){
NSAssert1(0, #"Database: Failed to close database connection. Error: '%s'", sqlite3_errmsg(db));
}
}
-(void)createEditableDatabase
{
BOOL success;
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
// create writable database and store path for later use
writableDatabase = [documentsDir stringByAppendingPathComponent:#"main-rw.db"];
success = [fileManager fileExistsAtPath: writableDatabase];
// if writable database already exists return
if(success) return;
// the editable database does not exist
// copy the default DB to the application
// documents directory
NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"main.db"];
success = [fileManager copyItemAtPath:defaultPath toPath:writableDatabase error:&error];
if(!success){
NSAssert1(0, #"Database: Failed to create writable database file: '%#'.", [error localizedDescription]);
}
}
-(NSMutableArray *)queryWithDelegate
{
[self initializeDatabase];
// do we have an delegate?
if(![self delegate])
return nil;
NSMutableArray *result = [[self delegate] query:db];
[self closeDatabase];
return result;
}
-(void)importWithDelegate:(NSMutableArray *)collection
{
[self initializeDatabase];
[[self delegate] import:collection into:db];
sqlite3_finalize(statement);
[self closeDatabase];
}
-(sqlite3 *)getWritableDatabase
{
return db;
}
#end
Database Delegate-Class
#import "KejithEntryQueryDelegate.h"
#import "KejithEntry.h"
#interface KejithEntryQueryDelegate ()
#property sqlite3 *database;
#end
#implementation KejithEntryQueryDelegate
#synthesize sql;
#synthesize statement;
-(id)init
{
if((self = [super init])){
[self initSQL];
}
return self;
}
-(void)initSQL
{
sql = "SELECT _id, entry_title, entry_description, entry_phone, entry_fax, entry_email, entry_website FROM entry";
}
-(NSMutableArray *)query:(sqlite3 *)database
{
// store database
[self setDatabase:database];
// initialize array to store found objects
NSMutableArray *entries = [[NSMutableArray alloc] init];
// prepare sql statement
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
if(sqlResult == SQLITE_OK){
while(sqlite3_step(statement) == SQLITE_ROW){
// allocate object to store row
KejithEntry *entry = [[KejithEntry alloc] init];
// get data from columns
NSMutableString *title = [NSMutableString stringWithString:
[NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 1)]];
NSMutableString *description = [NSMutableString stringWithString:
[NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 2)]];
NSMutableString *phone = [NSMutableString stringWithString:
[NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 3)]];
NSMutableString *fax = [NSMutableString stringWithString:
[NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 4)]];
NSMutableString *email = [NSMutableString stringWithString:
[NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 5)]];
NSMutableString *website = [NSMutableString stringWithString:
[NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 5)]];
// set data in object
[entry setId:[NSNumber numberWithInt: sqlite3_column_int(statement, 0)]];
[entry setTitle:title];
[entry setDescription:description];
[entry setPhone:phone];
[entry setFax:fax];
[entry setEmail:email];
[entry setWebsite:website];
// put object into array
[entries addObject:entry];
}
// finalize the statement to release its resources
sqlite3_finalize(statement);
} else {
// log errors
NSLog(#"Database: Problem Occured in KejithEntryQueryDelegate.m");
NSLog(#"Database: Result Code: %d", sqlResult);
NSLog(#"Database: SQL-Error: %s", sqlite3_errmsg(database));
}
return entries;
}
-(void)import:(NSMutableArray *)collection into:(sqlite3 *)database
{
if([collection count] == 0)
return;
for(KejithEntry *entry in collection){
[self importEntry:entry into:database];
}
}
-(void)importEntry:(KejithEntry *)entry into:(sqlite3 *)database
{
sql = "INSERT INTO entry (entry_id, entry_title, entry_description, entry_phone, entry_fax, entry_email, entry_website, enty_latitude, entry_longitude, entry_category_id) \
VALUES \
(0,?,?,?,?,?,?,0,0,0);";
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
sqlite3_bind_text(statement, 1, [[entry title] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 2, [[entry getDescription] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 3, [[entry phone] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 4, [[entry fax] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 5, [[entry email] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 6, [[entry website] UTF8String], -1, SQLITE_STATIC);
if(sqlite3_step(statement) != SQLITE_DONE){
NSLog(#">> Database: Failed to insert into Database");
NSLog(#"SQL Error Message: %s", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
}
#end
AppDelegate::application:didFinishWithLaunchingOptions
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
// create delegate for entry xml parsing
id delegate = [[KejithEntryXmlDelegate alloc] init];
KejithXmlParser *parser = [[KejithXmlParser alloc] initWithUrl:[[NSURL alloc] initWithString:entryXmlUrl]];
KejithDatabaseAccess *dbAccess = [[KejithDatabaseAccess alloc] init];
KejithEntryQueryDelegate *dbEntryDelegate = [[KejithEntryQueryDelegate alloc] init];
// set delegate to parse xml file
[parser setDelegate:delegate];
// set delegate to query data to/from database
[dbAccess setDelegate:dbEntryDelegate];
// get results of xml parsing
NSMutableArray *result = [parser parse];
NSLog(#"Count of ParseResult: %d", [result count]);
[dbAccess importWithDelegate:result];
NSLog(#"Count of DatabaseResult: %d", [[dbAccess queryWithDelegate] count]);
return YES;
}
Console-Output without [dbAccess importWithDelegate:result] commented out:
2013-12-08 15:59:44.035 staedteApp[30202:70b] Database: Connection was opened successfully
2013-12-08 15:59:44.048 staedteApp[30202:70b] Database: Connection was opened successfully
2013-12-08 15:59:44.049 staedteApp[30202:70b] Count of DatabaseResult: 0
Console-Output with [dbAccess importWithDelegate:result] commented out:
2013-12-08 16:17:18.084 staedteApp[30267:70b] Database: Connection was opened successfully
2013-12-08 16:17:18.091 staedteApp[30267:70b] Count of DatabaseResult: 50
EDIT #1 -----
Updated KejithEntryQueryDelegate::importEntry:into
-(void)importEntry:(KejithEntry *)entry into:(sqlite3 *)database
{
sql = "INSERT INTO entry (entry_id, entry_title, entry_description, entry_phone, entry_fax, entry_email, entry_website, enty_latitude, entry_longitude, entry_category_id) \
VALUES \
(0,?,?,?,?,?,?,0,0,0);";
int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
if(sqlResult != SQLITE_DONE){
sqlite3_bind_text(statement, 1, [[entry title] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 2, [[entry getDescription] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 3, [[entry phone] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 4, [[entry fax] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 5, [[entry email] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 6, [[entry website] UTF8String], -1, SQLITE_STATIC);
int sqlStepResult;
if((sqlStepResult = sqlite3_step(statement)) != SQLITE_DONE){
NSLog(#">> Database: Failed to insert into Database");
NSLog(#"SQL Error Message: %s", sqlite3_errmsg(database));
NSLog(#"SQL Step Result: %d", sqlStepResult);
}
} else {
NSLog(#"Database: Problem Occured in KejithEntryQueryDelegate.m step");
NSLog(#"Database: Result Code: %d", sqlResult);
NSLog(#"Database: SQL-Error: %s", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
}
The issue is that you're using an instance variable for sql, setting it to the SELECT statement when you create KejithEntryQueryDelegate, changing it to an INSERT statement in the importEntry:into: method, but when you call query:, even though the code clearly assumes it should be SELECT statement, the sql is still the INSERT statement.
By looking at the result code of sqlite3_step (point 3, below) one can quickly identify the issue. Since sqlResult != DONE, you want to log the issue and it reports "entry.entry_title may not be NULL" (which doesn't make sense in a SELECT statement, which made me realize that the old INSERT statement was still in the sql variable).
My original answer, based upon a glance at the code is below. Point #3 is the critical observation.
Just looking at the code, I don't see anything that would obviously cause the behavior you describe. If I follow you correctly, you're saying that if you do not import data, 50 records are found, but if you do attempt to import the data, not only do you not see new data, but suddenly nothing is found (including the records that were already there). Is that really what you're saying? That's curious behavior. If this is, in fact, the issue, that would lead me to suspect that the attempt to import is causing the subsequent attempt to read to fail.
The only obvious SQLite issue here is that importWithDelegate should not be calling sqlite3_finalize. I don't even see why KejithDatabaseAccess has a sqlite3_stmt, as you don't prepare any statements in that class. Perhaps calling sqlite3_finalize with some invalid sqlite3_stmt causes problems?
There are a few minor things here:
The importEntry:into: should presumably check the result of sqlite3_prepare_v2 statement. Elsewhere, you confirm that the prepare succeeded before proceeding, but not here.
The query method is storing the email address into the web site property.
I'd also save the result of sqlite3_step in the query method so that you could check for errors, e.g.:
while((sqlResult = sqlite3_step(statement)) == SQLITE_ROW) {
// do all of your updating of entries here
}
if (sqlResult != SQLITE_DONE) {
NSLog(#"Database: Problem Occured in KejithEntryQueryDelegate.m step");
NSLog(#"Database: Result Code: %d", sqlResult);
NSLog(#"Database: SQL-Error: %s", sqlite3_errmsg(database));
}
Right now, if your sqlite3_step method failed, you'd never know.
I have Sequence of Queries that need to be performed with database..
Most of time its working fine.. but some time it failed to insert query.
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
for (int i=0;i<[queries count]; i++)
{
NSString *query = [queries objectAtIndex:i];
const char *Insert_query = [query UTF8String];
sqlite3_prepare(contactDB, Insert_query, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
//NSLog(#" \n\n\n\n %# done query",query);
}
else {
NSLog(#" \n\n\n\n %# not done query",query);
}
}
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
Above is code which i have implemented to perform insert operation...
Can any one help me to find if it fails then for what reason it failed to insert to database so i can handle error..
Use this method to execute query on sqlite
//-----------------------------------------------------------------------------------------------------//
#pragma mark - Helper methods
//-----------------------------------------------------------------------------------------------------//
-(BOOL)dbOpenedSuccessfully
{
if(sqlite3_open([[self dbPath] UTF8String], &_database) == SQLITE_OK)
{
return YES;
}
else
{
[[[UIAlertView alloc]initWithTitle:#"Error"
message:#"Error on opening the DB"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil]show];
return NO;
}
}
//-----------------------------------------------------------------------------------------------------//
#pragma mark - Query
//-----------------------------------------------------------------------------------------------------//
- (void) executeQuery:(NSString *)strQuery
{
char *error = NULL;
if([self dbOpenedSuccessfully])
{
NSLog(#"%#",strQuery);
sqlite3_exec(_database, [strQuery UTF8String], NULL, NULL,&error);
if (error!=nil) {
NSLog(#"%s",error);
}
sqlite3_close(_database);
}
}
Also If insert not works properly the reason may be the file is not in the documents directory and if it is there in bundle it will fetch tha data but cannot update or insert value if db is in bundle ,Copy it to the documents directory and then try using it
-(void) checkAndCreateDatabase
{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
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:_databaseName];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:_databasePath error:nil];
}
For more info see this
You can try printing the error in the following way, Based on the error you can make decision.
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
for (int i=0;i<[queries count]; i++)
{
NSString *query = [queries objectAtIndex:i];
const char *Insert_query = [query UTF8String];
sqlite3_prepare(contactDB, Insert_query, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
//NSLog(#" \n\n\n\n %# done query",query);
}
else {
NSLog(#"sqlite3_step error: '%s'", sqlite3_errcode(contactDB));
NSLog(#" \n\n\n\n %# not done query",query);
}
}
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
Additionally,
SQLITE_DONE means that the statement has finished executing
successfully. sqlite3_step() should not be called again on this
virtual machine without first calling sqlite3_reset() to reset the
virtual machine back to its initial state.
You can use, SQLITE_OK instead of SQLITE_DONE.
I've written a simple app that uses Sqlite database. It works great on iPhone simulator but doesn't work on my iPhone.
-(NSString *) getFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,YES);
NSString *documentsDir=[paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"database.sql"];
}
-(void)openDatabase
{
//Open
if (sqlite3_open([[self getFilePath] UTF8String], &db) != SQLITE_OK ) {
sqlite3_close(db);
NSAssert(0, #"Database failed to open.");
}
}
Output on Xcode after launching app:
2013-03-07 02:12:16.525 SqliteWorkApp[464:907] *** Assertion failure in -[SqliteWorkAppViewController insertRecord], /Users/cmltkt/Objective-C Apps/SqliteWorkApp/SqliteWorkApp/SqliteWorkAppViewController.m:77
2013-03-07 02:12:16.529 SqliteWorkApp[464:907] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error updating table.'
*** First throw call stack:
(0x3398e2a3 0x3b82797f 0x3398e15d 0x34263ab7 0x19b3b 0x195bd 0x357b5595 0x357f5d79 0x357f1aed 0x358331e9 0x357f683f 0x357ee84b 0x35796c39 0x357966cd 0x3579611b 0x374885a3 0x374881d3 0x33963173 0x33963117 0x33961f99 0x338d4ebd 0x338d4d49 0x357ed485 0x357ea301 0x19147 0x3bc5eb20)
libc++abi.dylib: terminate called throwing an exception
insertRecord function:
-(void)insertRecord
{
NSString *sql = [NSString stringWithFormat:#"INSERT OR REPLACE INTO 'countries' ('name', 'flag') " "VALUES ('Sample Data','Sample Data')"];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err)
!= SQLITE_OK) {
sqlite3_close(db);
NSAssert(0, #"Error updating table.");
}
}
I had same problem,
I used SQLite Db portable file in app and It was working on simulator very well but not on real device.
So after digging a lot, I found, when I dragged sqlite db file into my project, Xcode did not add it to bundle resources.
Please! go this way
select your project go to "Build Phases"
add your database.sqlite (it should be. sqlite as i know) file to Bundle resources.
and For handling all SQLite stuff, my database helper class code is
#import "ASCODBHelper.h"
#import <sqlite3.h>
#implementation ASCODBHelper
static ASCODBHelper *db;
+(ASCODBHelper *)database{
if (db == nil) {
db = [[ASCODBHelper alloc] init];
}
return db;
}
- (id)init{
self = [super init];
if (self) {
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:#"IOSMeeting" ofType:#"sqlite"];
if (sqlite3_open([sqLiteDb UTF8String], &db) != SQLITE_OK) {
NSLog(#"Failed to open database!");
}
}
return self;
}
-(void)getPresentationDeatilById:(NSString *)presentationid andSessionId:(NSString *)sessionid{
NSInteger pId = [presentationid integerValue];
NSInteger sId = [sessionid integerValue];
NSString *queryString = [[NSString alloc] initWithFormat:#"SELECT distinct mediaID,mediaURL,meetingName,trackName FROM Media WHERE presentationID='%d' and sessionID ='%d'",pId,sId];
NSLog(#"query is : %#",queryString);
sqlite3_stmt *selectStatement;
if (sqlite3_prepare_v2(db, [queryString UTF8String], -1, &selectStatement, nil) == SQLITE_OK) {
while (sqlite3_step(selectStatement) == SQLITE_ROW) {
char *mediaid = (char *) sqlite3_column_text(selectStatement, 0);
char *mediaurl = (char *) sqlite3_column_text(selectStatement, 1);
char *meetingname = (char *) sqlite3_column_text(selectStatement, 2);
char *topicname = (char *) sqlite3_column_text(selectStatement, 3);
NSString *mediaID = [[NSString alloc] initWithUTF8String:mediaid];
NSString *mediaURL = [[NSString alloc] initWithUTF8String:mediaurl];
NSString *topicName = [[NSString alloc] initWithUTF8String:topicname];
NSString *meetingName = [[NSString alloc] initWithUTF8String:meetingname];
//you can log here results
}
sqlite3_finalize(selectStatement);
}
}
#end
and Here is the code how I am using this.
Just import
#import "ASCODBHelper.h"
and call our db helper method this way
[[ASCODBHelper database] getPresentationDeatilById:presentationId andSessionId:sessionId];
Let me know if need help in this.
a noob here asking for help after a day of head-banging....
I am working on an app with sqlite3 database with one database and two tables. I have now come to a step where I want to select from the table with an argument. The code is here:
-(NSMutableArray*) getGroupsPeopleWhoseGroupName:(NSString*)gn;{
NSMutableArray *groupedPeopleArray = [[NSMutableArray alloc] init];
const char *sql = "SELECT * FROM Contacts WHERE groupName='?'";
#try {
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *docsDir = [paths objectAtIndex:0];
NSString *theDBPath = [docsDir stringByAppendingPathComponent:#"ContactBook.sqlite"];
if (!(sqlite3_open([theDBPath UTF8String], &database) == SQLITE_OK))
{ NSLog(#"An error opening database."); }
sqlite3_stmt *st;
NSLog(#"debug004 - sqlite3_stmt success.");
if (sqlite3_prepare_v2(database, sql, -1, &st, NULL) != SQLITE_OK)
{ NSLog(#"Error, failed to prepare statement."); }
//DB is ready for accessing, now start getting all the info.
while (sqlite3_step(st) == SQLITE_ROW)
{
MyContacts * aContact = [[MyContacts alloc] init];
//get contactID from DB.
aContact.contactID = sqlite3_column_int(st, 0);
if (sqlite3_column_text(st, 1) != NULL)
{ aContact.firstName = [NSString stringWithUTF8String:(char *) sqlite3_column_text(st, 1)]; }
else { aContact.firstName = #""; }
// here retrieve other columns data ....
//store these info retrieved into the newly created array.
[groupedPeopleArray addObject:aContact];
[aContact release];
}
if(sqlite3_finalize(st) != SQLITE_OK)
{ NSLog(#"Failed to finalize data statement."); }
if (sqlite3_close(database) != SQLITE_OK)
{ NSLog(#"Failed to close database."); }
}
#catch (NSException *e) {
NSLog(#"An exception occurred: %#", [e reason]);
return nil; }
return groupedPeopleArray;}
MyContacts is the class where I put up all the record variables.
My problem is sqlite3_step(st) always return SQLITE_DONE, so that it i can never get myContacts. (i verified this by checking the return value).
What am I doing wrong here?
Many thanks in advance!
I think you are not binding the value, if not use this
sqlite3_bind_text(stmt, 1, [groupName UTF8String], -1, SQLITE_STATIC);
You're not binding any value to your statement.
You're literally executing SELECT * FROM Contacts WHERE groupName='?' as is.
And that likely returns an empty set, which is why sqlite3_step returns SQLITE_DONE, there's nothing to read in the set, you're done.
This page has an example of binding parameters to a statement..
EDIT: Also, you don't need the quotes around ?
SELECT * FROM Contacts WHERE
groupName=?
then use sqlite3_bind_text
I was successfully accessing my database to get a list of cities on the App launch. I tried running a second query against it right afterward to get the list of States but all that happens is that my app blows up with no usable error in the console (simply says "Program received signal: EXEC_BAD_ACCESS" and nothing more).
Here is the code, I was hoping someone could potentially explain to me what I'm doing wrong:
-(void) initializeDatabase{
// The database is stored in the application bundle
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"mydatabase.sqlite"];
// Open the database. The database was prepared outside the application.
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK){
[self initializeCities:database];
[self initializeStates:database];
} else {
// Even though the open failed, call close to properly clean up resources.
sqlite3_close(database);
NSAssert1(0, #"Failed to open database with message '%s'.", sqlite3_errmsg(database));
// Additional error handling, as appropriate...
}
}
-(void) initializeCities:(sqlite3 *)db {
NSMutableArray *cityArray = [[NSMutableArray alloc] init];
self.cities = cityArray;
[cityArray release];
// Get the primary key for all cities.
const char *sql = "SELECT id FROM my_table ORDER BY state";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, sql, -1, &statement, NULL) == SQLITE_OK){
while (sqlite3_step(statement) == SQLITE_ROW){
int primaryKey = sqlite3_column_int(statement, 0);
City *city = [[City alloc] initWithPrimaryKey:primaryKey database:db];
[cities addObject:city];
[city release];
}
}
// "Finalize" the statement - releases the resources associated with the statement.
sqlite3_finalize(statement);
}
-(void) initializeStates:(sqlite3 *)db {
NSMutableArray *statesArray = [[NSMutableArray alloc] init];
self.states = statesArray;
[statesArray release];
// Get the primary key for all cities.
const char *sql = "SELECT DISTINCT state FROM my_table ORDER BY state";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, sql, -1, &statement, NULL) == SQLITE_OK){
// We "step" through the results - once for each row
while (sqlite3_step(statement) == SQLITE_ROW){
NSString *state;
state = (NSString *)sqlite3_column_text(statement, 0);
[states addObject:state];
[state release];
}
}
// "Finalize" the statement - releases the resources associated with the statement.
sqlite3_finalize(statement);
}
I can't debug this code as the debugger never hits my breakpoints at all.
If I remove the initializeStates method the app works as expected (albiet without a list of states).
You are releasing "state" without having allocated it. Try something like this:
while (sqlite3_step(statement) == SQLITE_ROW){
NSString *state = [[NSString alloc] initWithCString:(char*)sqlite3_column_text(statement, 0) encoding:NSASCIIStringEncoding];
//state = (NSString *)sqlite3_column_text(statement, 0);
[states addObject:state];
[state release];
}
Update: add cast above to fix compiler warning
Your problem is this:
NSString *state = (NSString *)sqlite3_column_text(statement, 0);
According to the documentation, sqlite3_column_text() returns a char*, not an NSString*.
Edit: You wouldn't have had this problem if you'd have used a wrapper ;)