sqlite3_prepare_v2 character limit? - iphone

I have data stored in a sqlite3 database and have several places that I read and write data to and from the database. The problem I am running into is that if the SQL statement gets to be very long the sqlite3_prepare_v2 method returns an error.
This code works:
NSString *strSQL = #"UPDATE commandList SET displayName=?, type=?, formula=?, controlButton=?, sort=? WHERE pk=?;";
const char *sql = [strSQL UTF8String];
if (sqlite3_prepare_v2(database, sql, -1, &dehydrate_statment, NULL) != SQLITE_OK) {
NSLog(#"Error: failed to create update statement with message '%#'.", sqlite3_errmsg(database));
}
But this code errors out:
NSString *strSQL = #"UPDATE commandList SET displayName=?, type=?, formula=?, onFormula=?, offFormula=?, controlButton=?, sort=? WHERE pk=?;";
const char *sql = [strSQL UTF8String];
if (sqlite3_prepare_v2(database, sql, -1, &dehydrate_statment, NULL) != SQLITE_OK) {
NSLog(#"Error: failed to create update statement with message '%#'.", sqlite3_errmsg(database));
}
note the only difference is the 1st line.

When you say "the code errors out", you really ought to post the error. This saves us from speculating, or having to write a sample to reproduce the error you are getting.
See: http://www.sqlite.org/limits.html
SQLite does limit the maximum size of an SQL statement. (This prevents undesirable behavior when run in an embedded environment, but doesn't affect the size of values bound to the statement.)
You should't be running into this size limit, based on the code above, but it is hard to say what specifically you are running into because the sample + question doesn't stand alone.

The problem doesn't exist in the iPhone simulator so it must be something else.

Related

sqlite3 : SQL statement to update a table not working

For update a table, I write::update set =\"%#\" WHERE =\"%#\"",col1Value,col2Value];
But,this is not working. Please help.
My code is below:
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
NSString *querySQL = [NSString stringWithFormat:#"UPDATE AssemblyAssessment SET countedunits=\"%#\" WHERE assemblyid=\"%#\"",self.SAcountedunits,self.asmbIdStr];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(ipadSites,query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(#"done...");
}
else
{
NSLog(#"not done...");
}
sqlite3_finalize(statement);
sqlite3_close(ipadSites);
}
You should use "?" in your prepared statement and use sqlite3_bind_text then to bind the string values, instead of using stringWithFormat and %#. This way you will prevent SQL injections and security issues in your SQL requests (e.g. in case your string contains quotes or other stuff).
For your problem, please be more precise than "it doesn't work". Does it return an error code, in which case which one? Does it return with an OK status but your db isn't working? What are the types of your variables? What are the values of your temporary variables like querySQL, did you try to put breakpoints in your code to check what is happening? Etc, etc.
what is not working exactly. You can try to print error message like this:
NSLog(#"%s",sqlite3_errmsg(ipadSites));
also, for such one-line requests you can use sqlite3_exec() function:
sqlite3_exec(ipadSites, query_stmt, NULL,NULL, NULL);
The code you posted shows you getting the path to the database file but there is no code to open the database. You need to make a call to sqlite3_open_v2 before you attempt to prepare the statement or execute the query.
It's also a bad idea to use a string format to build the query. Your query should be:
const char *query_stmt = "UPDATE AssemblyAssessment SET countedunits = ? WHERE assemblyid = ?";
Prepare that statement, then make use of the appropriate sqlite3_bind_xxx methods to bind the two values to the query. This is a much safer approach. It takes care of properly quoting and escaping the values.

After adding SQLcipher sqlite3_exec returns SQLITE_NOTADB

I configured SQLCipher as the tutorial in their site... I can compile & Run the project.
But sqlite3_exec returns SQLITE_NOTADB when trying to execute a statement.
Please find code snippet below:
=================
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(success) {
int sql_results = sqlite3_open([dbPath UTF8String], &SQLDB);
const char* key = [#"BIGSecret" UTF8String];
sqlite3_key(SQLDB, key, strlen(key));
if (sql_results == SQLITE_OK) {
NSString *sql;
const char *update_sql;
sql = [NSString stringWithFormat:#"DROP table %#",tablename];
update_sql = [sql cStringUsingEncoding:NSUTF8StringEncoding];
if(sqlite3_exec(SQLDB, update_sql, nil, nil, nil) == SQLITE_OK) {
NSLog(#"Good to go %# dropped",tablename);
}
else {
NSLog(#"Bad Delete Cat SQL: %s -- %d", update_sql,sql_results);
NSLog(#"error code %i", sql_results);
}
Am not able to get the issue, where I went wrong....
Thanks,
Ben
Cross posting from Mailing list:
I noticed in your code that you are only entering the block to
sqlite3_open if the database file exists. Are you by chance trying to
encrypt an existing standard SQLite database using SQLCipher using
this code? If so, calling sqlite3_key will not work that way. You'd
instead want to open the standard SQLite database, attach a new
encrypted database, and then export the data between the two. There
are some more details on this procedure here:
http://sqlcipher.net/sqlcipher-api/#sqlcipher_export
Once you're dealing with an encrypted database you can call
sqlite3_key as the first operation before using it.

the select method is adjusting but insert method not working properly

I am working on sqlite database , trying to insert into database but it is giving error "Error while inserting " Database is locked .
I searched some post and also write reset and finalize statement but it is giving same error.
Here is my code
if(addStmt == nil)
{
//const char *sql = "insert into Limittabel (limitAmt) Values(?)";
//const char *sql="INSERT INTO Limittabel (limitAmt, Profileid) VALUES(?, ?)";
const char *sql="insert into Limittabel (limitAmt,Profileid) Values (?,?)";
// Insert into Limittabel (limitAmt,Profileid) Values ($500,1)
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
sqlite3_bind_text(addStmt, 1, [limitAmt UTF8String], -1, SQLITE_TRANSIENT);
// NSString *str_id_poi = [[NSString alloc] initWithFormat:#"%d", [Profileid integerValue]];
// sqlite3_bind_text(addStmt, 2, [str_id_poi UTF8String], -1, SQLITE_TRANSIENT);
//sqlite3_bind_text(addStmt, 2, [ UTF8String], -1, SQLITE_TRANSIENT);
NSLog(#"***Storing END on Database ***");
if(SQLITE_DONE != sqlite3_step(addStmt))
{
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
} // sqlite3_finalize(addStmt);
else{
//sqlite3_last_insert_rowid;
limitid = sqlite3_last_insert_rowid(database);
NSLog(#"YES THE DATA HAS BEEN WRITTEN SUCCESSFULLY");
}
sqlite3_finalize(addStmt);
}
sqlite3_reset(addStmt);
//sqlite3_finalize(addStmt);
}
If I am not opening the database it is giving Database locked error, if opening database it is giving ' No such Table ' error
Please Help me.
Thanks
I don't understand the "if I am not opening the database it is giving Database locked error" comment, because you simply can't use a database without opening it. It makes no sense to call SQLite functions without first opening database. Maybe I'm not understanding this comment.
But ignoring that for a second, you later say, "if opening database it is giving 'No such table' error": Are you sure you're finding the database correctly? The problem is, if you open database and it's not found, then a blank database will be created. Are you sure this hasn't happened to you? If this may have happened to you, you might want to
Reset the simulator (if you're using simulator) or delete and reinstall the app to make sure any blank databases that sqlite3_open may have created for you will be removed; and
Check to make sure the database exists before you open it or replace your occurrence of sqlite3_open with sqlite3_open_v2 with a third parameter of SQLITE_OPEN_READWRITE and fourth parameter of NULL. See SQLite will not prepare query when accessing database in Xcode
As an aside, you don't mention whether you're opening this from the bundle or Documents, but generally I advise to programmatically copy from bundle to Documents and then open it from there.
If you're doing this on the simulator, I sometimes find it helpful to examine the database used by the simulator from my Mac. Thus, I go to "~/Library/Application Support/iPhone Simulator/5.1/Applications/" (replace the 5.1 with whatever version of your simulator you are using ... if the Library is hidden, unhide it from Terminal with chflags nohidden ~/Library), I then go into the directory for the particular application, go into it's Documents folder, and then open the database in the Mac command line sqlite3 program. You can use that to examine the database and make sure the db is as you expect it.
Just a few thoughts for the "no such table" error.
Here is link for creating, Open , inserting, and retrieve data from the SQLite database . It will help you.
SQLite Datase Create,Insert and Retrieve from the database Click here
jonty to deal with the database its compulsory that first we open the database and then we makes changes in database
and if it giving the error No such table then i recommend you check the existence of table in database i.e. such table created or not.
Try this code,
if(sqlite3_open([YourDatabasePath UTF8String],&db) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"insert into Limittabel (limitAmt,Profileid) Values (?,?)"];
char *errmsg=nil;
if(sqlite3_exec(db, [querySQL UTF8String], NULL, NULL, &errmsg)==SQLITE_OK)
{
NSLog(#"YES THE DATA HAS BEEN WRITTEN SUCCESSFULLY");
}
}
sqlite3_close(db);
If this code doesn't work then there is a problem in your query, check your query again. this code works at my side.

Delete statement in iphone not working

I am deleting all data from the table by using below code snippet
NSString *deleteStatementNS = [NSString stringWithFormat:
#"DELETE FROM %#",[tableNames objectAtIndex:i]];
const char *prepareDelete ="DELETE FROM '?'";
const char *tbleName = [[tableNames objectAtIndex:i] UTF8String];
if (sqlite3_prepare_v2(dBase, prepareDelete, -1, &dbpreprdstmnt, NULL) == SQLITE_OK)
{
dbrc = sqlite3_bind_text(dbpreprdstmnt, 1, tbleName, -1, SQLITE_TRANSIENT);
dbrc = sqlite3_step(dbpreprdstmnt);
sqlite3_finalize(dbpreprdstmnt);
dbpreprdstmnt = NULL;
}
else
{
NSLog(#"Error %#",[NSString stringWithCString:sqlite3_errmsg(dBase) encoding:NSUTF8StringEncoding]);
}
But unfortunately the delete is not happening I am getting error as Error no such table: ?
I am not able to prepare the statement only. But if i use prepare statement like below
const char *prepareDelete =[deleteStatementNS UTF8String];
This is working absolutely fine. I am not able to bind the variable to stop SQL injection attacks.May I know the reason behind this error please. I found many places where this code snippet is reported as its is working fine.
I am not able to bind the variable to stop SQL injection attacks.
Table names cannot be bound as variables.
To avoid SQL injection attacks don't let your users specify which table names will be deleted. Make sure the table names come from a trusted source (e.g. hardcoded in your program).
In fact it's a really bad idea to delete all data in a table when the table name comes from an untrusted source. Even if you prevent SQL injection attacks, an attacker could still delete data you didn't want them to delete.

iPhone SQLite commands with apostrophes

I'm writing an application for the iPhone that communicates with a SQLite database but I'm running into a small problem. Whenever I try to query information based on a condition that contains an apostrophe, no results are returned.... even if a result that matches the requested condition exists. Let me give some specifics...
SQLite Table
Row--Column1--Column2---------
Test Data - 001
User's Data - 002
Objective-C Code
//Create the sql statement
sqlite3_stmt *sqlStatement;
//Create the name of the category that will be passed in
NSString *categoryName = #"User's Data";
//Create the rest of the SQL query
NSString *sqlQuery = "SELECT * FROM theTableName WHERE Column1 = ?";
//If there are no errors in the SQL query
if (sqlite3_prepare_v2(theDatabase, sqlQuery, -1, &sqlStatement, nil) == SQLITE_OK)
{
//Bind the category name to the sql statement
sqlite3_bind_text(sqlStatement, 1, [categoryName UTF8String], -1, SQLITE_TRANSIENT);
//While there are rows being returned
while (sqlite3_step(sqlStatement) == SQLITE_ROW)
{
//Retrieve row data
}
}
else
{
//Save error message to the application log and terminate the app
NSAssert1(0,#"Error: Failed to prepare the SQL statement with message '%s'.", sqlite3_errmsg(database));
}
//Reset the sql statement
sqlite3_reset(sqlStatement);
I'm semi-new to objective C, so my first thought when writing this code was to sanitize the user inputs. But after doing some research, I read that the sqlite3_bind calls do the necessary sanitation for you. But whenever the code runs, the while loop is skipped right over because there are no rows being returned. It should return the second row from the database table. If I copy/paste the exact same SQL query into a SQL managing program (I use SQLite Manager) (and with the necessary query sanitation of course), it returns the correct data.
I've spent a long time trying to debug this myself and even a greater amount of time trying to search online for a similar problem being explained and resolved, but to no avail. As of now, I just disabled the user's ability to key in an apostrophe on the iPhone's virtual keyboard. But this is a feature I'd love to include in my finished product. Can anyone here offer me any helpful tips? Any kind of help would be greatly appreciated.
For sqlite your request will be (as you can see it is even wrong highlighted):
SELECT * FROM theTableName WHERE Column1 = User's data
And it will wait for the closing ' symbol
You should echo ' symbol, for example in following way:
NSString *sqlQuery = [NSString stringWithFormat:#"SELECT * FROM tableName WHERE Column1=\"%#\"", categoryName];
In this case query will be
select * from theTableName where column1="User's data"
that is completely legal query.
In this case you don't need binding any more and final code will look like:
if (sqlite3_prepare_v2(database, [sqlQuery UTF8String], -1, &sqlStatement, nil) == SQLITE_OK)
{
//While there are rows being returned
while (sqlite3_step(sqlStatement) == SQLITE_ROW)
{
//Retrieve row data
}
}
else
{
//Save error message to the application log and terminate the app
NSAssert1(0,#"Error: Failed to prepare the SQL statement with message '%s'.", sqlite3_errmsg(database));
}
The official character is ''
sanitize with:
NSString *stringToSanitize = #"This is the value with ' character";
NSString *sanitized = [stringToSanitize stringByReplacingOccurrencesOfString:#"'"
withString:#"''"];
Then you can use it on your querys