How to Check existing column in sqlite - objective-c

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.

Related

Can't insert " character into Sqlite DB [Objective-C]

I'm inserting some data on a sqlite db, It works fine but what I noticed is that I can't insert words that contains the character ", is it a common issue? should I change parse the text and edit every " character I find?
This is the code i'm using in order to insert data into my DB:
UICollectionViewCell *cell = (UICollectionViewCell *)button.superview.superview;
NSIndexPath *indexPath = [self.customCollectionView indexPathForCell:cell];
FolderProducts *item = _feedItems[indexPath.item];
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &Carrello) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO CarrelloMese (titolo, codice, prezzo, urlImg) VALUES (\"%#\", \"%#\", \"%#\", \"%#\")",item.nomeProdotto, item.codice, item.prezzo, item.urlImg];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(Carrello, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
} else {
}
sqlite3_finalize(statement);
sqlite3_close(Carrello);
}
You need to bind your SQLite statements using the sqlite3_bind_xxx() function. Basically, you remove all variables from your statement (in your case the %#) and replace them with '?'. SQLite then knows that where an ? is HAS to be a variable, and therefore doesn't get it mixed up with a command.
For example, say you wanted to bind the word "INSERT". Using ? SQLite won't read this as a command and then flag an error.
Read the docs (link above) for full information on how to use the bind function.
Here's what your code might look like with binding (UNTESTED):
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &Carrello) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO CarrelloMese (titolo, codice, prezzo, urlImg) VALUES (?,?,?,?)"];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(Carrello, insert_stmt, -1, &statement, NULL);
if (sqlite3_bind_text(statement, 0, item.nomeProdotto.UTF8String, item.nomeProdotto.length, SQLITE_STATIC) != SQLITE_OK) {
NSLog(#"An error occurred");
}
// Etc etc
// SQLite bind works like this: sqlite_bind_text/int/e.t.c(sqlite3_stmt,index_of_variable, value);
// there are optionally parameters for text length and copy type SQLITE_STATIC and SQLITE_TRANSIENT.
if (sqlite3_step(statement) == SQLITE_DONE)
{
} else {
}
sqlite3_finalize(statement);
sqlite3_close(Carrello);
}

SQLite Case Sensitive and Case Insensitive Search

I have NSMutableArray with NSMutableDictionary that carries a SQLite search result. I need to make a difference between case-sensitive and case-insensitive search. If I read some topics here, they say SQLite by default returns a case-sensitive result. And they suggest that you use COLLATE nocase to make a case-insensitive search. Actually, with the following code, I get the same result with or without COLLATE nocase. What am I doing wrong?
const char *sql;
if (checkButtonR5.state == 1) { // checkButtonR5 is a checkbox button. If it's on, it tells a search will be case-sensitive.
sql = "Select address,date,name,age,ID From data1a WHERE request LIKE ?";
} else {
sql = "Select address,date,name,age,ID From data1a WHERE request LIKE ? COLLATE nocase";
}
sqlite3_stmt *statement; // outputFile is a file path
if (sqlite3_open([outputFile UTF8String], &connection) == SQLITE_OK){
if(sqlite3_prepare_v2(connection, sql, -1, &statement, NULL) != SQLITE_OK) {
//NSLog(#"It cannot connect the database file.");
}
NSString *bindParam = [NSString stringWithFormat:#"%%%#%%",rqt];
if(sqlite3_bind_text(statement, 1, [bindParam UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK){
//NSLog(#"Problem binding search text param.");
} else {
while (sqlite3_step(statement) == SQLITE_ROW) {
char *field0 = (char *) sqlite3_column_text(statement, 0); // address
NSString *field1Str0 = [[NSString alloc]initWithUTF8String:field0];
NSString *str0 = [[NSString alloc]initWithFormat:#"%#", field1Str0];
...
...
}
sqlite3_finalize(statement);
sqlite3_close(connection);
}
}
Thank you for your help.

Sqlite_binding methods

How can I write this query without using stringWithFormat. How can I pass parameters to the SQLite Query. Now my code is this:
NSString *querySQL = [NSString stringWithFormat:#"SELECT name, char_code, sound, status From Tmy_table Where ID=\"%d\"", i];
Thanks in advance
You should use sqlite3 host parameters and sqlite3_bind() to bind variables to them. This would like something like this in your example.
NSString* query = #"SELECT name, char_code, sound, status From Tmy_table Where ID=?";
sqlite3_stmt* myStatement = NULL;
sqlite3_prepare_v2(myDBConnection, [query UTF8String], -1, &myStatement, NULL);
sqlite3_bind_int(myStatement, 1, i);
Points to note:
The two sqlite3 functions return error codes that you must check. I've left that out for clarity.
The second parameter in sqlite3_bind_int() tells you which question mar to replace with the third parameter. The index starts at 1, not 0.
See also docs about binding.
NSString sql = #"SELECT name, char_code, sound, status From Tmy_table Where ID=?";
sqlite3_stmt *stmt = NULL;
if (sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt, SQLITE_STATIC) == SQLITE_OK)
{
// If 'i' was text:
// if (sqlite3_bind_text(stmt, 1, i, -1, SQLITE_STATIC) == SQLITE_OK)
if (sqlite3_bind_int(stmt, 1, i) == SQLITE_OK) // Note: 1-based column when binding!!!!
{
while (sqlite3_step(stmt) == SQLITE_ROW)
{
const char *name = sqlite3_column_text(stmt, 0); // Note: 0-based column when fetching!!!
const char *sound = sqlite3_column_text(stmt, 1);
const char *status = sqlite3_column_text(stmt, 2);
// ... print the values or whatever
}
}
else
{
NSLog(#"Failed to bind int: %s", sqlite3_errmsg(database));
}
sqlite3_finalize(stmt);
}
else
{
NSLog(#"Failed to prepare statement '%#': %s", sql, sqlite3_errmsg(database));
}
EDIT Changed the bind to sqlite3_bind_text() as i appears to be text...

inserting into SQLite

I have a problem with the inserting and retrieving code
There is no run time error but inserting data is not working and the retrieving code only retrieves the last record from the DB.
Is it better to use NSString or NSMutableString?
NSLog(#"test");
NSString *sql1 = [NSString stringWithFormat:#"INSERT INTO User Values (2,'%#','','F','123','','','','','A','B','123','123',2)",name.text];
char *err;
sqlite3_exec(database, [sql1 UTF8String], NULL, NULL, &err)!= SQLITE_OK ;
const char *sql = "select * from User";
sqlite3_stmt *searchStatement;
if (sqlite3_prepare_v2(database, sql, -1, &searchStatement, NULL) == SQLITE_OK)
{
while (sqlite3_step(searchStatement) == SQLITE_ROW)
{
char * try = (char*)sqlite3_column_text(searchStatement, 1);
if (try){
item = [NSMutableString stringWithUTF8String:try];
}
else{
item = #"";
}
The issue seems to be in your retrieval code. The sqlite3_column_type methods use zero-based indexing, but it looks like you are starting from position 1. Thus each time you step through, you aren't pulling out the information you need. I'm not sure why you are getting the last item, but try going from position 0 and see if that helps.

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.