SQLite Syntax (order by causing error) - iphone

Looking for some syntax help for SQLite, a very odd thing is happening. I am running the query on an iPhone.
Here is the query that fails: (Assume that the tables are correct, this runs great in the firefox sqlite plugin)
select tcodes.DisplayOrder, StatusText, StatusCode
from tcodes
join tcode_transitions on tcode_transitions.available = tcodes.UNID
where StatusCode = 'AAA'
order by tcodes.DisplayOrder
To get it to run, I have to remove the order by clause, which seems a bit strange.
Here is the call:
// 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
int rtn = sqlite3_prepare_v2(database, [sql UTF8String], -1, &compiledStatement, nil);
if(rtn != SQLITE_OK) {
NSLog(#"SQL Error: %d",rtn);
sqlite3_close(database);
}
}
in the above, rtn is == 1, which indicates a SQL error.
Again, the query runs great outside the phone. Is it possible that the SQL libraries on the iPhone have a different syntax for the order by?

Use sqlite3_errmsg (or sqlite3_errmsg16) to get more information about error.
Try adding DisplayOrder to select clause.
Some databases require that all columns in ORDER BY clause are also present in SELECT clause.

Related

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.

iPhone app crashes with sqlite3_bind_text()

I'm attempting to make a simple app that stores and displays flash cards, however I'm having an awful time getting my SQLite to work. The database connection is fine, but when I try an insert, it crashes and gives no indication of what went wrong. This is the code I am using to insert the flash card into the table.
const char *insert = "INSERT OR REPLACE INTO LIST (TERM, DEFINITION) VALUES (?, ?);";
sqlite3_stmt *statement;
sqlite3_prepare_v2(database, insert, -1, &statement, nil);
sqlite3_bind_text(statement, 1, [term UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [def UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_step(statement);
sqlite3_finalize(statement);
I've determined that the bind text method is the weak link with some NSLog() methods I placed earlier. In this example, term and def are NSStrings that do hold the correct value (I know that much for sure). Any help would be appreciated. I haven't quite mastered portable c.
Not 100% why its not working but I have a few things to suggest:
Get rid of the ; at the end of the insert statement, I've never had it in mine.
Put the prepare and step into an if statement like so
if(sqlite3_prepare_v2(db, sql, -1, &statement, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(db));
}
if (SQLITE_DONE != sqlite3_step(statement)) {
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(db));
}
None of this might help but it might get you closer as to whats wrong.
Also, one thing that might help. When I've been working with SQLite its been an utter pain if I make a change to the db or if I'm not putting correct data in. I've spent a lot of time resetting the iPhone simulator and cleaning the build

sqlite3_prepare_v2 character limit?

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.

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

Why I am getting sqlite3error?

I am trying to reuse an sqlite statement in my application in a method. Here's the relevant code
if(getsets_statement == nil){
const char *sql = "SELECT DISTINCT num,roll FROM mytable WHERE cls like ? and divname like ?";
if(sqlite3_prepare_v2(database, sql, -1, &getsets_statement, NULL) != SQLITE_OK){
NSAssert1(0, #"Error: Failed to prepare stmt with message '%s'", sqlite3_errmsg(database));
}
}
sqlite3_bind_text(getsets_statement, 1, [cls UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(getsets_statement, 2, [divname UTF8String], -1, SQLITE_TRANSIENT);
while(sqlite3_step(getsets_statement) == SQLITE_ROW){
setNumber= sqlite3_column_int(getsets_statement, 0);
roll = sqlite3_column_int(getsets_statement, 1);
[numArr addObject:[NSNumber numberWithInt:setNumber]];
[rollArr addObject:[NSNumber numberWithInt:roll]];
}
sqlite3_reset(getsets_statement);
The statement executes perfectly the first time it is called. But the next time I call this method, I get a sqlite3error. The values of divname and cls are present (did an NSLog and checked) but I don't understand why I am getting this error. I get the error at the first bind_text statement.
This is in the gdb console
Program received signal: “EXC_BAD_ACCESS”.
(gdb) where
#0 0x9041857f in sqlite3Error ()
#1 0x9041acea in vdbeUnbind ()
#2 0x9041b2c8 in bindText ()
Any help?
Make sure nothing else is actually the issue (is the database being closed somewhere else? Is the getsets_statement pointing to the same object? Has it been finalized?). Then try using NULL or SQLITE___STATIC instead of SQLITE_TRANSIENT. Since [NSString UTF8String] returns data that doesn't need to be freed (by you), it obviously doesn't need a destructor, and it will stay valid until after your function exits, at which time you're done running the statement anyway.
I believe you need to call sqlite3_reset and sqlite3_clear_bindings on the prepared statement before attempting to reuse it. Also, you should really check your return codes.