FMDB Result set contains null iphone - iphone

I am using FMDB for my application to store data in sqlite. Here is my code
from AppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
FMDatabase* db = [FMDatabase databaseWithPath:#"/tmp/sql.sqlite"];
if (![db open]) {
NSLog(#"Could not open db.");
}
NSLog(#"DB opened successfully");
// full code not shown here
}
I have following code in ViewController
-(IBAction)insertButtonClicked:(id)sender
{
NSLog(#"in insertButtonCLicked");
[db beginTransaction];
[db executeUpdate:#"insert into sample (url) values (?)",#"google'"];
[db commit];
}
-(IBAction)displayButtonClicked:(id)sender
{
NSLog(#"in DisplayCLicked");
FMResultSet *rs = [db executeQuery:#"select url from sample"];
NSLog(#"Rs contains => %#",rs);
while( [rs next])
{
NSLog(#"%#",[rs stringForColumn:#"url"]);
}
[rs close];
}
When i run this code i get rs as null as shown in following (this is o/p from console)
2011-03-07 07:30:06.919 InsertDataSample[3092:20b] DB opened successfully
2011-03-07 07:30:13.341 InsertDataSample[3092:20b] in insertButtonCLicked
2011-03-07 07:30:16.860 InsertDataSample[3092:20b] in DisplayCLicked
2011-03-07 07:30:16.860 InsertDataSample[3092:20b] Rs contains => (null)
Plz help me friends. I am working on FMDB from many days but i am unable to use FMDB .
Thanks in advance

Insert this just after your query and FMDB will probably tell you exactly what the problem is.
if ([db hadError]) {
NSLog(#"DB Error %d: %#", [db lastErrorCode], [db lastErrorMessage]);
}
Update:
Running this:
FMDatabase *db = [FMDatabase databaseWithPath:#"/tmp/sql.sqlite"];
[db executeUpdate:#"create table sample (url TEXT);"];
[db executeUpdate:#"insert into sample (url) values(?);", #"google'"];
FMResultSet *rs = [db executeQuery:#"select url from sample;"];
while ([rs next]) {
NSLog(#"%#", [rs stringForColumn:#"url"]);
}
[rs close];
[db close];
produced this output:
2011-03-06 12:38:59.831 test[93163:207] google'

Related

sqlite3 and fmdb nested FMResultSet is possible?

I'm trying to iterator through a master detail sort of tables and I'd like to populate the master/detail structures as I go. Apparently when I nest result sets I get a BAD Access exception:
FMDatabase *db = self.database;
[db open];
db.traceExecution = YES;
db.logsErrors = YES;
FMResultSet *rs = [db executeQuery:#"select group_id, label from main.preference_group order by group_id"];
while ([rs next])
{
PreferenceGroup *pg = [[PreferenceGroup alloc] init];
pg.group_id = [rs intForColumn:#"group_id"];
pg.label = [rs stringForColumn:#"label"];
pg.translatedLabel = NSLocalizedString(pg.label, nil);
NSMutableArray * prefs = [[NSMutableArray alloc] init];
[prefGroups addObject:prefs];
FMResultSet *rs2 = [db executeQuery:#"select pref_id, label, value from main.preference where group_id = ? order by pref_id", pg.group_id, nil];
while ([rs2 next])
{
Preference * pref = [[Preference alloc] init];
pref.group_id = pg.group_id;
pref.pref_id = [rs2 intForColumn:#"pref_id"];
pref.label = [rs2 stringForColumn:#"label"];
pref.value = [rs2 stringForColumn:#"value"];
pref.translatedLabel = NSLocalizedString(pref.value, nil);
[prefs addObject:pref];
}
[rs2 close];
}
[rs close];
[db close];
In the rs2 (second result set) I get the EXEC_BAD_ACCESS within FMDatabase class.
Is this a restriction of sqlite3/fmdb or am I doing something wrong here?
I just found what I did wrong. I was passing a int as part of the second query. I had to convert it to NSNumber:
FMResultSet *rs2 = [db executeQuery:#"select pref_id, label, value from main.preference where group_id = ? order by pref_id", [NSNumber numberWithInt:pg.group_id], nil];
So that means, YES, sqlite3/fmdb does support nested queries! :-)
I'm using FMDB and SQLITE3 as well, and I find nested queries work:
(I'm not claiming the code hint below is good, never mind the format, please)
Both Master and Detail tables have a column called 'id'
FMResultSet *rso = [database executeQuery:#"select * from master order by id"];
while ([rso next])
{
NSInteger masterId = [rso intForColumn:#"id"];
NSString *q3 = [[NSString alloc] initWithFormat:
#"select * from detail where masterid = %d order by id", masterId, nil ];
FMResultSet *rsa = [database executeQuery:q3 ];
while ([rsa next])
{
NSInteger detailId = [rsa intForColumn:#"id"];
//
// here do something with masterId and detailId
}
}
This was a pleasant surprise, actually. I was halfways expecting to have to first query all master records, and then loop through them in App memory to pick up the details from SQlite3.
But the above construct works fine.

Reading from SQLite - FMDB - Beginner

I am trying to read from a database file (performing a simple select all functions).
I am using FMDB.
Here's how i created the DB;
Pro:~ dd$ sqlite3 db.db
SQLite version 3.7.7 2011-06-25 16:35:41
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table cus(id integer primary key, firstname varchar(30));
sqlite> inser into cus(firstname)values('f');
Error: near "inser": syntax error
sqlite> insert into cus(firstname)values('f');
sqlite> select * from cus;
1|f
sqlite>
I copied the file (db.db) to my resource folder in xCode. changed the name of the db file to db.db in the app delegate. Code for my program is exactly yhe same as this tutorial.
Here's the code ;
-(NSMutableArray *) getCustomers
{
NSMutableArray *customers = [[NSMutableArray alloc] init];
NSString * path = [(AppDelegate*)[[UIApplication sharedApplication]delegate]databasePath];
NSLog(#"DB path %# ",path);
FMDatabase *db = [FMDatabase databaseWithPath:path];
[db open];
FMResultSet *results = [db executeQuery:#"SELECT * FROM cus"];
NSLog(#"result %# ",results);
while([results next])
{
NSLog(#"result %# ",results);
Customer *customer = [[Customer alloc] init];
customer.customerId = [results intForColumn:#"id"];
customer.firstName = [results stringForColumn:#"firstname"];
[customers addObject:customer];
}
[db close];
return customers;
}
My problem;
Eventhough there is 1 record in the DB, the result of the Select statement is NULL. Why is this and how can i correct it ?
Assuming that the database was created and imported into the project successfully, try the following:
-(NSMutableArray *) getCustomers
{
NSMutableArray *customers = [[NSMutableArray alloc] init];
NSString * path = [(AppDelegate*)[[UIApplication sharedApplication]delegate]databasePath];
NSLog(#"DB path %# ",path);
FMDatabase *db = [FMDatabase databaseWithPath:path];
if(![db open])
{
NSLog(#"Could not open DB, try again");
return nil;
}
FMResultSet *results = nil;
results = [db executeQuery:#"SELECT * FROM cus"];
NSLog(#"result %# ",results);
while([results next])
{
Customer *customer = [[Customer alloc] init];
customer.customerId = [results intForColumn:#"id"];
customer.firstName = [results stringForColumn:#"firstname"];
NSLog(#"Customer object %#", customer);
[customers addObject:customer];
[customer release];
}
[db close];
return customers;
}
I have had this same problem but was managed to resolve this by setting up the path correctly. So, there could be something wrong in the path specification. Do make sure that your database path is perfect. And as everyone suggests, I recommend you to use error statements to narrow down the issue. Wishes!!

I can't trap FMDB empty resultset

I am having trouble trapping an empty result set from FMDB.
The code is below. I am getting NSLog's from the database opening and closing and NSLog "1" but none of the ones in the If statement!
If I have data in the database its fine, but I want to trap and edit result if the database is empty.
[self openDatabase];
NSNumberFormatter *nfcurrency = [[NSNumberFormatter alloc]init];
[nfcurrency setNumberStyle:NSNumberFormatterCurrencyStyle];
[nfcurrency setLocale:[NSLocale currentLocale]];
FMResultSet *result = [[self getDatabase]executeQuery:#"SELECT BFNeeded FROM tblBets ORDER BY pk DESC LIMIT 1,1;"];
//FMResultSet *result = [[self getDatabase]executeQuery:#"SELECT BFNeeded FROM tblBets ORDER BY pk DESC LIMIT 1,1;"];
NSLog(#"1");
if (result == NULL) {
NSLog(#"Last BFNeeded Result = nil");
} else {
while ([result next]) {
NSLog(#"HERE");
NSString *lastBFNeeded = [nfcurrency stringFromNumber:[NSNumber numberWithDouble:[result doubleForColumn:#"BFNeeded"]]];
NSLog(#"lastBFNeeded=%#",lastBFNeeded);
}
}
NSLog(#"ClosingDB");
[self closeDatabase];
Continuing after getting first reply:
I can't get hasAnotherRow to work as expected.
I have this code:
FMResultSet *result = [[self getDatabase]executeQuery:#"SELECT BFNeeded FROM tblBets ORDER BY pk DESC LIMIT 0,1;"];
if (result == nil) {
NSLog(#"Last BFNeeded Result = nil");
}
else {
NSLog(#"has results1: %#", [result hasAnotherRow] ? #"YES" : #"NO");
while ([result next]) {
NSLog(#"has results2: %#", [result hasAnotherRow] ? #"YES" : #"NO");
}
}
With a database that returns a result, I get result1 NO, result2 YES so I assume the hasAnotherRow must go inside the while ([result next]) loop.
However with an empty database, I get result1 NO and it doesn't even get to result2!
the "result" will never be nil for a query that produces 0 rows.
also, you shouldn't compare object pointers to NULL -- compare to nil. See this question: NULL vs nil in Objective-C
try this:
FMResultSet *result = [[self getDatabase]executeQuery:#"SELECT BFNeeded FROM tblBets ORDER BY pk DESC LIMIT 1,1;"];
NSLog ( #"has results: %#", [result hasAnotherRow] ? #"YES" : #"NO" );
NSInteger count;
query=[NSString stringWithFormat:#"select Count(*) from %# where name = 'brandon' ",dbName];
results = [database executeQuery:query ];
while([results next]) {
count = [results intForColumnIndex:0];
NSLog(#"count:%d",count);
}
will set count equal to zero if there is no entry

SQLite Changes Not Saved

I'm using SQLite in iOS 4 on an iPhone, but the changes made by my update statements aren't saved. At first thought perhaps quitting the app might be deleting the database somehow, but they're not even persisted during the same session. The code to initialize my database is (using FMDB):
-(SQLiteDal*) init {
pool = [[NSAutoreleasePool alloc] init];
self = [super init];
if(self != nil){
// Setup some globals
NSString *databaseName = [self getDbPath];
NSLog([NSString stringWithFormat:#"db path: %#", databaseName]);
db = (FMDatabase *)[FMDatabase databaseWithPath:databaseName];
if (![db open]) {
NSLog(#"Could not open db.");
[pool release];
return 0;
}
}
//[self checkAndCreateDatabase];
return self;
}
#pragma mark DB Maintenance
-(NSString *)getDbPath {
NSString *databaseName = #"myapp.db";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databaseName = [documentsDir stringByAppendingPathComponent:databaseName];
return databaseName;
}
Both of these methods are called to create the database, then to insert to a table I call:
[db executeQuery:#"INSERT INTO MyTable (Name, Description, Area, Price, ID) VALUES (?,?,?,?,?)",
f.Name,
f.description,
f.area,
f.price,
f.id];
The problem is, when I come to read from MyTable using the statement below, I never get anything back:
FMResultSet *rs = [db executeQuery:#"SELECT * FROM MyTable WHERE ID = ?", id];
while ([rs next]) {
//.. this is never called
As far as I can see I'm not missing anything out, and the DB seems to be in a writable location.
When inserting you need to call executeUpdate not executeQuery. Also you should call beginTransaction and then commit, like this:
[_dbPointer beginTransaction];
BOOL isInserted = [_dbPointer executeUpdate:[NSString stringWithFormat:#"INSERT INTO MyTable (Name, Description, Area, Price, ID) VALUES(?,?,?,?,?);", f.Name,
f.description,
f.area,
f.price,
f.id]];
[_dbPointer commit];

crash happens when NSMutableArray is returned?

I have coded like that(that function will be called again and again), but the returned object gives "BAD ACCESS", the NSLog prints correct string, but toReturn sometimes(i called
again and again) gives crashes..any help to alter this code,If i remove the "autorelease" method,it worsks fine
- (NSMutableArray *)getAll:(NSString *)type
{
NSLog(#"Type: %#", type);
NSMutableArray *toReturn = [[[NSMutableArray alloc] initWithCapacity:0] autorelease];
rs = [db executeQuery:Query1];
while ([rs next]) {
[toReturn addObject:[rs stringForColumn:#"Name"]];
NSLog(#"name: %#", [rs stringForColumn:#"Name"]);
}
[rs close];
return toReturn;
}
You need to make sure that your string is not deallocated in the meantime. Try changing
[toReturn addObject:[rs stringForColumn:#"Name"]];
to
[toReturn addObject:[[rs stringForColumn:#"Name"] copy]];