XCode sqlite3 - SELECT always return SQLITE_DONE - iphone

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

Related

iOS sqlite will return NULL when using SELECT statement

I'm very confused why the SELECT statement doesn't work correctly. It doesn't give me any errors, just returns null. I know it is writing the string correctly and the right string is there, it's just not reading it correctly. Everything as far as I know is correct because I use the same SQLstmt "method" for many other methods/functions similar to this. This one just doesn't make sense on why it shouldn't work.
- (NSString *)returnNote {
selStmt=nil;
NSLog(#"Reading note");
NSString *SQLstmt = [NSString stringWithFormat:#"SELECT 'Notes' FROM '%#' WHERE Exercises = '%#';", currentRoutine, currentExercise];
// Build select statements
const char *sql = [SQLstmt UTF8String];
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK) {
selStmt = nil;
}
// Building select statement failed
if (!selStmt) {
NSAssert1(0, #"Can't build SQL to read Exercises [%s]", sqlite3_errmsg(database));
}
NSString *note = [NSString stringWithFormat:#"%s", sqlite3_column_text(selStmt, 0)];
sqlite3_reset(selStmt); // reset (unbind) statement
return note;
}
You're not calling sqlite3_step. The statement is never executed.
NSString *querySQLS1 = [NSString stringWithFormat: #"SELECT Notes FROM \"%#\" where Exercises=\"%#\"", currentRoutine, currentExercise];
sqlite3_stmt *statements;
const char *query_stmts1 = [querySQLS1 UTF8String];
if(sqlite3_prepare_v2(UsersDB, query_stmts1, -1, &statement, NULL) == SQLITE_OK)
{
NSLog(#"in prepare");
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"Query executed");
}
else {
NSLog(#"in else");
}
sqlite3_finalize(statement);
}

Getting error while executing SQLite command from application

I have this simple function in my application :
-(NSMutableArray *)SelectProductID:(NSMutableArray *)arr
{
NSLog(#"----------------");
sqlite3_stmt *statement;
NSMutableArray *arrPordID = [[NSMutableArray alloc]init];
#try
{
//Get productID
for(NSString *strSubProductID in arr)
{
NSString *s = [NSString stringWithFormat:#"SELECT ProductID FROM SubProducttable where SubProductID=%#",strSubProductID];
const char *sql = [s cStringUsingEncoding:NSASCIIStringEncoding];
if (sqlite3_prepare_v2(database, [s cStringUsingEncoding:NSUTF8StringEncoding], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW){
char *dbString;
dbString = (char *)sqlite3_column_text(statement, 0);
NSString *pID = (dbString) ? [NSString stringWithUTF8String:dbString] : #"";
[arrPordID addObject:pID];
}
}
}
}
#catch (NSException *exception) {
#throw exception;
}
#finally {
sqlite3_finalize(statement);
}
return arrPordID;
}
I am encountering a strange problem here. When application reaches while (sqlite3_step(statement) == SQLITE_ROW){, loop is never entered. I don't know why. I executed the same query in SQLite manager (when application is not running). And I get result as a single one. The result I get is 2. But here I am getting nothing.
And yes, I always close the database in SQLite manager whenever I run my application. I have also cleaned the application, restarted XCode, and removed the application from simulator. But no success.
Also I saw a strange thing during debugging. While debugging, sqlite3_stmt *statement is always skipped. Is this the reason I am not getting any result?
Have you tried subproductId in single quotes?
NSString *s = [NSString stringWithFormat:#"SELECT ProductID FROM SubProducttable where SubProductID='%#'",strSubProductID];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlQuery = #"SELECT ProductID FROM SubProducttable where SubProductID=%#",strSubProductID;
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(database, statement, -1, &sqlQuery, NULL) == SQLITE_OK) {
while(sqlite3_step(sqlQuery ) == SQLITE_ROW) {
// Read the data and add to your array object
}
}
// Release the compiled statement from memory
sqlite3_finalize(statement);
}
sqlite3_close(database)

implement tableview to show the data of database

I am making a small iPhone application in which I have implemented the database concept which is used to store name, contact no, email id. I Want that whenever I user save any contact It get displayed on table view. In -(IBAction)retriveall:(id)sender action I am retriving all the data from database and storing it into array. Now I want to display all the data in tableview.
How can I do this? Please help me.
-(IBAction)retriveall:(id)sender
{
[self retrive2];
for (int i =0; i< [namearray count]; i++)
{
NSLog(#"Name is:%#",[namearray objectAtIndex:i]);
NSLog(#"Password is:%#",[passarray objectAtIndex:i]);
}
}
-(IBAction)retrive:(id)sender
{
[self retrive1];
two.text = databasecolorvalue;
UIAlertView *favAlert=[[UIAlertView alloc] initWithTitle:#"" message:#"Retrived" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[favAlert show];
[favAlert release];
}
-(void)retrive1
{
databaseName = #"med.sqlite";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
#try {
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement="select pswd from Login where username = ? ";
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
// Create a new animal object with the data from the database
sqlite3_bind_text(compiledStatement, 1, [one.text UTF8String], -1, SQLITE_TRANSIENT);
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
databasecolorvalue =[NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement,0)];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
#catch (NSException * ex) {
#throw ex;
}
#finally {
}
}
You should declare an mutable array as an instance variable something like,
NSMutableArray * colors;
Initialize it in the viewDidLoad method and later alter your retrive1 method to add to the colors array.
-(void)retrive1
{
/* Clearing existing values for newer ones */
[colors removeAllObjects]
/* Get database path */
#try {
[..]
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
[colors addObject:[NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement,0)]];
}
[..]
}
#catch (NSException * ex) { #throw ex; }
#finally { }
}
And you'll have to implement the rest of the table view methods in the usual manner using the array as the source.
You have to create object with all data and implementation of UITableViewDataSource protocol for table view and set it in TableView property dataSource. After you havecall UITableView method
-(void)reloadData;

BAD_ACCESS on SQLITE selection

I am getting EXC_BAD_ACCESS when I attempt to do anything with the value I'm selecting from the local SQLITE database on an iPhone development. The code for my function is
-(void) updateFromDB {
// Setup the database object
sqlite3 *database;
// Open DB
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSString *query = [NSString stringWithFormat:#"SELECT MOD_ID FROM MODULE;"];
//NSLog(#"QUERY: %#",query);
// Prepare statement
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) {
// Execute SQL
while (sqlite3_step(statement) == SQLITE_ROW) {
// Get MOD_IDs
NSInteger MOD_ID = sqlite3_column_int(statement, 0);
NSString *ID = [NSString stringWithFormat:#"%#",MOD_ID];
//=======================
// Get Notice Module Data
//=======================
if (MOD_ID == 1) {
self.noticeModule = [[ModuleSetting alloc] initWithID:ID];
}
}
} else {
NSAssert1(0,#"Error: failed to prepare statement. '%s'", sqlite3_errmsg(database));
}
// Release the compiled statement from memory
sqlite3_finalize(statement);
} else {
sqlite3_close(database);
NSAssert1(0,#"Failed to open database. '%s'",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
The bad access occurs on the line
NSString *ID = [NSString stringWithFormat:#"%#",MOD_ID];
Thanks for any help you can offer!
%# denotes objects. But MOD_ID seems to be an integer. So your format should be %d,
NSString *ID = [NSString stringWithFormat:#"%d", MOD_ID];
You can't use %# in format strings for integers, only for Obj-C objects. For integers, use %d (or for NSInteger, I think it is recommended to use %ld).
Have a look at the String Format Specifiers guide.
MOD_ID is not a pointer, so %# isn't correct.
Use below
NSInteger MOD_ID = sqlite3_column_int(statement, 0);
NSString *ID = [NSString stringWithFormat:#"%d",MOD_ID];

Accessing an SQLite DB for two separate queries on iPhone App Initialization

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