Can't get data - sqlite3 - objective-c

I use sqlite for my simple iOS app. The problem is that I can't get the result from the query. I will skip the code which is responsible for opening the database. It works.
NSString *query = #"SELECT * FROM tickets LIMIT 0,1";
if(sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) == SQLITE_OK)
{
NSString *strResult = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
NSLog(#"%#", strResult);
sqlite3_finalize(statement);
}
Here the app crash with a message:
NSInvalidArgumentException', reason: '*** +[NSString stringWithUTF8String:]: NULL cString'
I'm 100% sure that the query
SELECT * FROM tickets LIMIT 0,1
return result which is not NULL. I have tested the query above with sqlite client and it works fine.
What is wrong here ?

You didn't evaluate your statement. You should use:
int sqlite3_step(sqlite3_stmt*);
after sqlite3_prepare_v2.

Related

How to Check existing column in sqlite

HI friends i learnt sqlite recently. i am using below code for name is exist or not in sqlite but i am not getting result. please help me.
BOOL columnExists = NO;
sqlite3_stmt *selectStmt;
NSString *upperString = [[NSString alloc] initWithFormat:exptypeFld.text];
NSString* changeString = [upperString uppercaseString];
NSLog(#"changeString %#",changeString);
[upperString release];
const char *sqlStatement = [[NSString stringWithFormat:#"SELECT expensetype from expensetypes where upper(expensetype) = '%#'",changeString] UTF8String];
NSLog(#"char is %s",sqlStatement);
if(sqlite3_prepare_v2(db, sqlStatement, -1, &selectStmt, NULL) == SQLITE_OK)
{
NSLog(#"Same........");
columnExists = YES;
}
You don't call sqlite3_step to actually execute the query. Also, is the database connection open at this point? You should also finalize the statement when you are done with it. And you shouldn't use string formats to bind values to a query. You should use sqlite3_bind_xxx.
NSString *upperString = exptypeFld.text; // no need for the string format
NSString* changeString = [upperString uppercaseString];
NSLog(#"changeString %#",changeString);
const char *sqlStatement = "SELECT expensetype from expensetypes where upper(expensetype) = ?";
NSLog(#"char is %s",sqlStatement);
sqlite3_stmt *selectStmt;
if(sqlite3_prepare_v2(db, sqlStatement, -1, &selectStmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(sqlStatement, 1, [changeString UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_step(sqlStatement); // you should check the result of this too
}
sqlite3_finalize(sqlStatement);
This code assumes the database has already been opened.
You may prefer to use existing classes to access SQLite databases. You can find an example I wrote here: https://github.com/AaronBratcher/ABSQLite
It has wrapper classes for accessing SQLite in a more traditional database way that I feel makes things easier.

Objective c : How to fetch data from sqlite table as per primary key?

Say I am having 1 table called ABC with fields ABCid,ABCname,ABCImagePath,ABCSequence. Now this table contains more than 40 rows inside the same.
Now I have an array of numbers say 1,4,5,7,8 and I want to compare these numbers with ABCid and fetch all the data from table ABC as per these IDs.
+ (void) getSelectedData : (int)ABCId
{
NSString *dbPath = [self getDBPath];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
NSString *query =[NSString stringWithFormat:#"select * from [ABC] where ABCId=%d",ABCId];
const char *sql = [query cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK)
{
[self getInitialDataToDisplay:dbPath];
ABC *DataObj = [[ABC alloc] initWithPrimaryKey:ABCId];
DataObj.ABCName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
ABCImagePath = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)];
DataObj.ABCSequence = sqlite3_column_int(selectstmt,8);
[appDelegate.arrGetData addObject:DataObj]; }
else
{
NSAssert1(0,#"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
NSLog(#"%d",[appDelegate.DataArrayTrans count]);
}
else
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
But app gets crashed in the if condition. Also note that I use below lines from the pageController to call the above function from ABC Object file.
for(int i=0;i<[arrRId count];i++)
{
[ABC getSelectedData:[[arrRId objectAtIndex:i]integerValue]];
[arr576576 addObject:[appDelegate.arrGetData valueForKey:#"ABCId"]];
}
Please guide me where I am making mistake. Thank you.
your query should be like this select * from ABC where ABCId IN (1,4,5,7,8)
that's it.

EXC_BAD_ACCESS SQL DATABASE

I got this exc_bad_access problem in AppDelegate.m
What I did and want is to have multiple sql query. To avoid complexity, I did two blocks (it will have more) and both are querying different table from sql.
-(void)readDataFromDatabase {
// Setup the database object
sqlite3 *database;
// Initialize the budgetobjects Array
Part1Array = [[NSMutableArray alloc] init];
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "select * from part1TBL";
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
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
// You can add more rows based on your object
NSString *Part1_Name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *Part1_Description = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
// Create a new Restaurant with the data from the database
Part1 *newPart1 = [[Part1 alloc] initWithName:Part1_Name description:Part1_Description];
// Add the budgetobject to BudgetObjectsrantArray
[Part1Array addObject:newPart1];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
// Setup the database object
sqlite3 *database2;
// Initialize the budgetobjects Array
Part2Array = [[NSMutableArray alloc] init];
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "select * from part2TBL";
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
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
// You can add more rows based on your object
NSString *Part2_Name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *Part2_Description = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
// Create a new Restaurant with the data from the database
Part2 *newPart2 = [[Part2 alloc] initWithName:Part2_Name description:Part2_Description];
// Add the budgetobject to BudgetObjectsrantArray
[Part2Array addObject:newPart2];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database2);
}
#end
The exc_bad_access highlighted at the end where
sqlite3_close(database2);
I'm not familiar with sqlite, but it looks like the issue with your code is that you're never opening 'database2'. Instead, you open 'database' twice, which looks like a typo.
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
....
sqlite3_close(database);
...
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// <--- This should be &database2
...
sqlite3_close(database2);
EDIT: Please note Mat's answer as well - there's several places where you're using database when you meant to use database2, and you might want to consider just reusing database, or extracting this functionality into a shared function if applicable.

Retrieving records based on latest entry from sqlite DB and displaying in UITableView

I am working with Sqlite DB for storing and retrieving the data and displaying it in the tableview. My question is how to display the data based on latest record entered in the DB.
Let me explain what I am doing.
Users will enter there data (fields like date,gender,country) and once clicked on save button the data gets stored in sqlite DB.
After saving immediately I will show only the dates in the tableview(next page) that I will be pulling it from the sqlite DB. But when I am displaying the dates in tableview the dates are displayed in ascending order (based on numbers).
But I want to display as per latest record entered by the user. below is the what I am doing in coding.
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
NSString *selectSQL;
if(sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
if ([set_user isEqualToString:#"Anonymous"] && [set_pass isEqualToString:#"Anonymous"])
{
selectSQL = [NSString stringWithFormat: #"SELECT * from Guest where username = '%#' and password = '%#'", set_user,set_pass];
}
else
{
selectSQL = [NSString stringWithFormat: #"SELECT * from Vitals where username = '%#' and password = '%#'", set_user,set_pass ];
}
const char *select_stmt = [selectSQL UTF8String];
if(sqlite3_prepare_v2(contactDB, select_stmt, -1, &statement, NULL) == SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
sq_date = [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 1)];
sq_gender = [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 2)];
sq_ethnicity = [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 12)];
[date_array addObject:sq_date];
[gender_array addObject:sq_gender];
[ethnicity addObject:sq_ethnicity];
/*if (![date_array containsObject:sq_date])
{
[date_array addObject:sq_date];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"" ascending:NO];
[date_array sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
}*/
}
sqlite3_finalize(statement);
}
}
What you can do is when inserting the data (entered by the user) into sqlite DB, have another column called timestamp & insert the current timestamp (maybe epoch time). This could be done for each row.
When retrieving you can order by timestamp rather than the ids which is what you want.

What do I need after an INSERT statement?

I have an INSERT statement, followed by a SQLITE3_EXEC, followed by a SELECT statement and another SQLITE3_EXEC. I'm getting an SQLERROR 21 (SQLITE_MISUSE) on the EXEC for the SELECT statement.
Am I missing something between the two EXECs? like a COMMIT, or?
Is it possible that the 21 refers to trying to insert a record that already exists?
NSString *insertCommand = [NSString stringWithFormat:#"INSERT INTO CardData (CARD_ID, CARD_NAME, CODE_VAL) VALUES ('/%#', '/%#', '/%#')",
symbol.data, #"Test Card", symbol.typeName];
sqlite3_exec(db, [insertCommand UTF8String], NULL, NULL, &errmsg);
if(errmsg != NULL)
NSLog(#"insert error: /%#", &errmsg); // DEBUGGING ONLY!
// now, pull it back out of the d/b and display the data
const char *sqlStatement = #"select CARD_ID, CARD_NAME, CODE_VAL from CardData";
sqlite3_stmt *compiledStatement;
int err = sqlite3_prepare_v2(db, [sqlStatement UTF8String], -1, &compiledStatement, NULL); // Setup the SQL Statement and compile it for faster access
if(err != SQLITE_OK)
NSLog(#"prepare error: /%#", err);
else {
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
resultText.text = [NSString stringWithFormat:#"\nDatabase: \n%# \n%# \n%#", resultText.text,
[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)],
[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)],
[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)]];
}
sqlite3_finalize(compiledStatement); // release it...
sqlite3_close(db);
}
According to documentation, (1.4 Error Codes->SQLITE_MISUSE) it says that you can get this error if you try to access closed database or calling sqlite_exec with same database pointer from two different threads. Just check out for these 2 possibilities in your case.
Hope it helps.
I have decided to use FMDB... thanks everybody for the suggestions, I appreciate your time.