inserting into SQLite - objective-c

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.

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

sqlite3_column_text returning Null

I have a table and I want to print the content of a row here is the table structure:
CREATE TABLE "quotes_type" ("type_id" INTEGER PRIMARY KEY NOT NULL , "content" TEXT)
I can see the type_id with debug and the value is correctly 1 but I can't return the context value with the help of sqlite3_column_text here is the code:
NSString *qry = [NSString stringWithFormat: #"select * from quotes_type"];
const char *count_stmt = [qry UTF8String];
sqlite3_prepare_v2(contactDB, count_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_ERROR) {
NSAssert1(0,#"Error when selecting rows %s",sqlite3_errmsg(contactDB));
} else {
int myid=sqlite3_column_int(statement, 0);
NSLog(#"Context: %s", sqlite3_column_text(statement, 1));
NSLog(#"myid is %d",myid);
sqlite3_finalize(statement);
sqlite3_close(contactDB);
the problem is this line:
NSLog(#"Data: %s", sqlite3_column_text(statement, 1));
the result is Null
I realized that it doesn't update my sqlite file and it is reading from my previous one how can I force it to read from the new one?even I deleted all .sqlite files but still it is reading it from somewhere

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.

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...

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.