I am trying to insert values in database but while preparing statement it is giving me error "SQL error or missing database"...can anyone know what this error is and how one can resolve this?????my path for database is
2010-07-22 14:34:59.933 DatabaseApp[1521:207] path of database /Users/nuzhat/Library/Application Support/iPhone Simulator/User/Applications/C50A0188-2A9A-487F-951C-6E7FFCE3CFBB/Documents/UserName.db3
here is my code:-
// Open the database connection and retrieve minimal information for all objects.
- (void)initializeDatabase {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"TextWandiPhone.db3"];
//for second database
NSString *path1 = [documentsDirectory stringByAppendingPathComponent:#"UserName.db3"];
// Open the database. The database was prepared outside the application.
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK)
{
// Get the primary key for all books.
const char *sql = "SELECT CountryName FROM Country";
sqlite3_stmt *statement = nil;
// Preparing a statement compiles the SQL query into a byte-code program in the SQLite library.
// The third parameter is either the length of the SQL string or -1 to read up to the first null terminator.
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK)
{
// int success=sqlite3_step(statement);
// We "step" through the results - once for each row.
while(sqlite3_step(statement) == SQLITE_ROW)
{
// if(success == SQLITE_ROW) {
//NSLog(#"value of success %d",success);
// The second parameter indicates the column index into the result set.
char *str = (char *)sqlite3_column_text(statement, 0);
NSString *country = (str) ? [NSString stringWithUTF8String:str] : #"";
//NSLog(#"value :%#",country);
//NSLog(#"after running query");
//NSLog(#"after initializing array");
[arrCountry addObject:country];
//NSLog(#"after adding values");
//[return arrCountry];
}//while
//NSLog(#"values of array %#",arrCountry);
}//aft prepare
sqlite3_finalize(statement);
}//aft open
//for second database
//else if (sqlite3_open([path1 UTF8String], &database1) == SQLITE_OK)
if (sqlite3_open([path1 UTF8String], &database1) == SQLITE_OK)
{
// Get the primary key for all books.
const char *sql1 = "SELECT UserID FROM User";
sqlite3_stmt *statement1=nil;
// Preparing a statement compiles the SQL query into a byte-code program in the SQLite library.
// The third parameter is either the length of the SQL string or -1 to read up to the first null terminator.
int value1=sqlite3_prepare_v2(database1, sql1, -1, &statement1, NULL);
NSLog(#"value of preparing stmt %d",value1);
if ( value1== SQLITE_OK)
{
// int success=sqlite3_step(statement);
// We "step" through the results - once for each row.
while(sqlite3_step(statement1) == SQLITE_ROW)
{
// if(success == SQLITE_ROW) {
//NSLog(#"value of success %d",success);
// The second parameter indicates the column index into the result set.
int userid = sqlite3_column_int(statement1, 0);
//NSString *country = (str) ? [NSString stringWithUTF8String:str] : #"";
//NSLog(#"value :%#",country);
//NSLog(#"after running query");
//NSLog(#"after initializing array");
NSString *strUserId = [[NSNumber numberWithInt:userid] stringValue];
[arrUser addObject:strUserId];
//[return arrCountry];
}
NSLog(#"values of array %#",arrUser);
}//aft prepare
// "Finalize" the statement - releases the resources associated with the statement.
//sqlite3_finalize(statement1);
}//aft opening 2nd database
else {
// Even though the open failed, call close to properly clean up resources.
sqlite3_close(database);
sqlite3_close(database1);
NSAssert1(0, #"Failed to open database with message '%s'.", sqlite3_errmsg(database));
NSAssert1(0, #"Failed to open database with message '%s'.", sqlite3_errmsg(database1));
// Additional error handling, as appropriate...
}
}
thanks in advance....
Not enough information here, but I think it could be a couple of things. Does the user of the database you are using have the permissions that allow them to insert data to the database? You might want to append your post so it includes the SQL statement you are using.
Related
I have been trying to save highscore into database and have been failing for past week, and I have no clue why it is not working. I keep receiving "Problem with prepare statement" and refuses to insert info into database. I have checked with database manager to make sure there is not a typo with sql statement, and when query is run on manager, it works fine - it's just the iphone that's giving me the problem. If anyone could please look over quickly and see something wrong with it and could let me know, I would really appreciate it!
- (NSMutableArray *) saveLocal {
NSLog(#"save local database");
#try {
[self checkDB];
sqlite3_stmt *sqlStatement2;
NSString *sqlS = [NSString stringWithFormat:#"INSERT INTO localHighscore (difficulty, score, uname, puzzles, multiplier, oneshots, hints) VALUES (%i,%i,\"%#\",%i,%i,%i,%i)",[[MySingleton sharedMySingleton] goDifficulty],[[MySingleton sharedMySingleton] goScore],_player, [[MySingleton sharedMySingleton] goPuzzles], [[MySingleton sharedMySingleton] goMultiplier], [[MySingleton sharedMySingleton] goOneshots], [[MySingleton sharedMySingleton] goHints]];
NSLog(#"%#",sqlS);
const char *sql = [sqlS UTF8String];
if(sqlite3_prepare_v2(localHighscore, sql, -1, &sqlStatement2, NULL) == SQLITE_OK)
{
sqlite3_step(sqlStatement2);
sqlite3_reset(sqlStatement2);
sqlite3_finalize(sqlStatement2);
NSLog(#"save complete");
} else {
NSLog(#"Problem with prepare statement");
}
sqlite3_close(localHighscore);
}#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}#finally{
NSLog(#"DB Loaded!");
}
}
and here is checkDB method which checks if database exists and creates one if it does not
- (void)checkDB {
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"localHighscore.sqlite"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
NSLog(#"file was not found");
if (sqlite3_open(dbpath, &localHighscore) == SQLITE_OK)
{
NSLog(#"db open");
char *errMsg;
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS localHighscore(pk INTEGER PRIMARY KEY AUTOINCREMENT, difficulty TINYINT, score MEDIUMINT, uname VARCHAR(255), puzzles TINYINT, multiplier TINYINT, oneshots TINYINT, hints TINYINT)";
if (sqlite3_exec(localHighscore, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(#"Failed to create table");
}
sqlite3_close(localHighscore);
} else {
NSLog(#"Failed to open/create database");
}
}
[filemgr release];
}
Thanks in advance for the help!
A couple of thoughts:
You don't appear to call sqlite3_open before trying to use the database.
Whenever you get an error, you should look at sqlite3_errmsg, e.g.
if (sqlite3_exec(localHighscore, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(#"Failed to create table: %s", sqlite3_errmsg(localHighscore));
}
Probably unrelated to your problem, but you should generally not build a SQL statement using stringWithFormat (at least if you have any text fields). Use ? placeholders in your SQL and then use sqlite3_bind_xxx functions.
const char *sql = "INSERT INTO localHighscore (difficulty, score, uname, puzzles, multiplier, oneshots, hints) VALUES (?,?,?,?,?,?,?)";
if(sqlite3_prepare_v2(localHighscore, sql, -1, &sqlStatement2, NULL) == SQLITE_OK)
{
if (sqlite3_bind_int(sqlStatement2, 1, [[MySingleton sharedMySingleton] goDifficulty]) != SQLITE_OK) {
NSLog(#"bind 1 failed: %s", sqlite3_errmsg(localHighscore));
}
if (sqlite3_bind_int(sqlStatement2, 2, [[MySingleton sharedMySingleton] goScore]) != SQLITE_OK) {
NSLog(#"bind 2 failed: %s", sqlite3_errmsg(localHighscore));
}
if (sqlite3_bind_text(sqlStatement2, 3, [_player UTF8String], -1, NULL) != SQLITE_OK) {
NSLog(#"bind 3 failed: %s", sqlite3_errmsg(localHighscore));
}
// repeat this bind process for each variable
if (sqlite3_step(sqlStatement2) != SQLITE_DONE) {
NSLog(#"step failed: %s", sqlite3_errmsg(localHighscore));
}
// reset not needed (doesn't hurt, but not needed unless you're going to re-use it
// sqlite3_reset(sqlStatement2);
sqlite3_finalize(sqlStatement2);
NSLog(#"save complete");
} else {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(localHighscore));
}
sqlite3_close(localHighscore);
If you find this syntax unwieldy, then maybe consider using FMDB, which simplifies your SQL interaction. But be very wary of stringWithFormat with SQL (if the inserted string had a quotation mark, the sqlite3_prepare will fail, theoretically, your app is exposed to SQL injection attacks, etc.).
As an aside, you should not [filemgr release], as you don't own it.
I saw that the "sqlite3_prepare_v2 ()" function, returns a 'generic error' (error code = 1) when the SQL statement contains conditions like "booleanfield=false" instead of "booleanfield=0". The same SQL statement executed in the SQL box of SQLiteStudio program gives good results using indifferently the first or the second form of the comparison.
I am passing the xml to my addRowToTheDatabase function . In this function i simply parse the xml file and and retrieved elements to the xml file. Now I am testing this application. How can I test whether the row added in the database or not in from unit test case ?
// I manipulated one of my queries real quick.. I'm assuming you're already connecting to a DB in SQLite, so much of this is un-needed. But this is the basic structure of a query.. as long as the DB resides in your application itself.
-(void) basicQuery
{
#try {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *theDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"databasename.sqlite"];
BOOL success = [fileManager fileExistsAtPath:theDBPath];
if (!success) {
NSLog(#"Failed to find database file '%#'.", theDBPath);
}
if (!(sqlite3_open([theDBPath UTF8String], &database) == SQLITE_OK)) {
NSLog(#"An error opening database, normally handle error here.");
}
const char *sql = "SELECT * FROM TABLE"; // your basic query
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK){
NSLog(#"Error, failed to prepare statement, normally handle error here.");
}
while (sqlite3_step(statement) == SQLITE_ROW) {
NSString *value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
NSLog(#"value = %#",value);
}
if(sqlite3_finalize(statement) != SQLITE_OK){
NSLog(#"Failed to finalize data statement, normally error handling here.");
}
if (sqlite3_close(database) != SQLITE_OK) {
NSLog(#"Failed to close database, normally error handling here.");
}
}
#catch (NSException *e) {
NSLog(#"An exception occurred: %#", [e reason]);
return nil;
}
}
I have some problem with reading from sqlite3 database.
-(void) readMessengesFromDatabase {
sqlite3 *database;
messenges = [[NSMutableArray alloc] init];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(#"Connection OK");
const char *sqlStatement = "select * from MessagesData";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) NSLog(#"connect to table OK"); else NSLog(#"connect to table FALSE");
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) { //не проходит условие
NSLog(#"Connection to table OK");
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSLog(#"Read rows OK");
NSString *dbMessageID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
NSString *dbMessageText = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *dbMessageDate = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *dbMediaOrNot = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
Message *messege = [[Message alloc] initWithName:dbMessageText messageID:dbMessageID messageDate:dbMessageDate mediaOrNot:dbMediaOrNot];
[messenges addObject:messege];
[messege release];
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
My first NSLog shows me what connection to database is ok. But next step "select * from MessagesData" and if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) NSLog(#"connect to table OK"); else NSLog(#"connect to table FALSE"); shows me "connect to table FALSE". Tried select from my database's table whith Terminal and got error "unable to open database file" . Where is my mistake? I don't see any problems in my code...
If you print the error code returned by sqlite3_prepare_v2 it will be a lot easier to diagnose the problem. The numeric values can be found on this page.
int errorCode = sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL);
if(errorCode != SQLITE_OK) {
NSLog(#"Connect to table failed: %d", errorCode);
}
However, if you cannot even select from the database in the sqlite3 command line tool, I suggest you check that the file exists, is readable and in the correct format.
Try to reproduce the error in your simulator (failing that, copy the database file to your computer e.g. using Organizer). Try to run the query using sqlite3 (I know you did try that, but make sure you are checking the following).
If you are getting the message Error: file is encrypted or is not a database, it means that the database file is corrupt. If you get Error: no such table:, it means your database does not exist, is empty, or simply hasn't got the table. If you get (as in your question): Error: unable to open database (you get this during the opening of sqlite, not when performing the query), it means that sqlite cannot read the file (for example permissions).
well i m guessing ur Database is not being able to connect.
Try My Answer From Here...
I mentioned few things here and i believe u ll be just Fine
Let me know it worked
write a code for check that table exist or not. and before u execute the query select u should check that create table if not exists ....
NSLog(#"Connection OK");
sqlite3_exec(database,"CREATE TABLE IF NOT EXISTS MessagesData (ID INTEGER PRIMARY KEY AUTOINCREMENT ,"
"FirstName TEXT,LastName TEXT"));
const char *sqlStatement = "select * from MessagesData";
If it work please like it
I have problems with SQLite function sqlite3_prepare_v2, it always returns 1 error code. I'm using SQLite wrapper SQLitemanagerforIOS4. Previously the same error happened without using the wrapper, I switched to it because, despite the statement was encoded in UTF8, the error still happened. I checked the database path with the debugger, and it's correct, so I'm lost...By the way, database is correctly opened and closed.
Here it is the pice of code :
- (NSArray *)getRowsForQuery:(NSString *)sql {
NSMutableArray *resultsArray = [[NSMutableArray alloc] initWithCapacity:1];
if (db == nil) {
[self openDatabase];
}
sqlite3_stmt *statement;
const char *query = [sql UTF8String];
int prepareStatus = sqlite3_prepare_v2(db, query, -1, &statement, NULL);
while (sqlite3_step(statement) == SQLITE_ROW) {
Many thanks for your help.
Here they are the parameters passed to the wrapper object:
- (void)viewDidLoad
{
[super viewDidLoad];
dbManager = [[SQLiteManager alloc] initWithDatabaseNamed:#"XLO.sqlite"];
SArray *provinciaArray = [dbManager getRowsForQuery:[NSString stringWithFormat:#"SELECT provincia FROM provincias;"]];
Thanks!
Peter, here it is:
- (NSError *) openDatabase {
NSError *error = nil;
NSString *databasePath = [self getDatabasePath];
const char *dbpath = [databasePath UTF8String];
#ifdef DEBUG
NSLog(#"SQL result: <%s>", dbpath );
#endif
int result = sqlite3_open(dbpath, &db);
if (result != SQLITE_OK) {
const char *errorMsg = sqlite3_errmsg(db);
NSString *errorStr = [NSString stringWithFormat:#"The database could not be opened: %#",[NSString stringWithCString:errorMsg encoding:NSUTF8StringEncoding]];
error = [self createDBErrorWithDescription:errorStr andCode:kDBFailAtOpen];
}
return error;
}
Many thanks to all!
Because it's saying the database table does not exist, you may not be opening the database # the path that you think you are. Remember that sqlite is passive - it will create a database on first write.
Run the app in the simulator and print out the path. Then go to that path in terminal and use the sqlite cmdline to confirm the db is there and it has the tables.
I am very new to IOS programming so I am not quite sure how this issue can be best solved.
I have a database of events that are being displayed on a tableview, when you select one of those items, it shows details along with the option to save it as a "favorite" which just updates a column in the db and sets it to 1.
I have a second table view that looks for all instances that have their "favorite" set to 1.
The problem I have run into is that I have only figured out how to get the "updateItem" database query to function off of the path of the item that you selected. Since each tableview shows the same item on different paths, the "updateItem" query is updating the incorrect item in the database when you are using the "favorites" table view.
I understand that in the UpdateItemAtID method, it is using the aryDatabase, and the favorites query uses the aryDatabaseFav. I had to create the second array the get around the favorites tableview, maybe there is a better way to have everything I want with just the original aryDatabase array rather than having 2 different arrays.
Here is the code I have for the two select statements as well as the update query, is there a better way that I can get around needing the path of the item?
-(void)readItems {
if (!database) return; // earlier problems
if (!selStmt)
{
const char *sql = "SELECT * FROM Events;";
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
{
selStmt = nil;
}
}
if (!selStmt)
{
NSAssert1(0, #"Can't build SQL to read items [%s]", sqlite3_errmsg(database));
}
// loop reading items from list
[aryDatabase removeAllObjects]; // clear list for rebuild
int ret;
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{ // get the fields from the record set and assign to item
//bindings omitted
[aryDatabase addObject:se]; // add to list
[se release]; // free item
}
sqlite3_reset(selStmt); // reset (unbind) statement
selStmt = nil;}
-(void)readFavItems {
if (!database) return; // earlier problems
if (!selStmt)
{
const char *sql = "SELECT * FROM Events WHERE mySchedule = 1;";
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
{
selStmt = nil;
}
}
if (!selStmt)
{
NSAssert1(0, #"Can't build SQL to read items [%s]", sqlite3_errmsg(database));
}
// loop reading items from list
[aryDatabaseFav removeAllObjects]; // clear list for rebuild
int ret;
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{ // get the fields from the record set and assign to item
//bindings omitted
[aryDatabaseFav addObject:se]; // add to list
[se release]; // free item
}
sqlite3_reset(selStmt); // reset (unbind) statement
selStmt = nil;}
-(void)updateItemAtID:(NSIndexPath *)path {
singleEvent *i = (singleEvent *)[aryDatabase objectAtIndex:path.row];
int ret;
const char *sql = "UPDATE events SET mySchedule = ? WHERE _id = ?;";
if (!updStmt)
{ // build update statement
if ((ret=sqlite3_prepare_v2(database, sql, -1, &updStmt, NULL))!=SQLITE_OK)
{
NSAssert1(0, #"Error building statement to update items [%s]", sqlite3_errmsg(database));
}
}
// bind values to statement
NSInteger m = i.intId;
sqlite3_bind_int(updStmt, 1, m);
NSInteger p = i.intPk;
sqlite3_bind_int(updStmt, 2, p);
if ((ret=sqlite3_step(updStmt)) != SQLITE_DONE)
{
NSAssert1(0, #"Error updating values [%s]", sqlite3_errmsg(database));
}
sqlite3_reset(updStmt);
}
I've updated the code and getting a result=0 on sqlite3_bind_text. Does mean it was updated with no error or no record was updated at all? Not sure what else to do at this point...
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"bh.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
NSLog(writableDBPath);
if(success)
{
const char *dbPath= [writableDBPath UTF8String];
//[G msgBox:writableDBPath title:#""];
//const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
sqlite3 *contactDB = NULL;
if (sqlite3_open(dbPath, &contactDB) == SQLITE_OK)
{
NSString *updateSQL = #"UPDATE account SET name = ? ";
const char *update_stmt = [updateSQL UTF8String];
int e = sqlite3_prepare_v2(contactDB, update_stmt, -1, &statement, nil);
if(e != SQLITE_OK) {
NSLog(#"Problem with updateEntryWithUniqueID");
NSLog(#"Error Code: %d, message '%s'", e, sqlite3_errmsg(contactDB));
return;
}else{
NSLog(#"Updated");
[G setNickname:thisNickname];
}
int result=sqlite3_bind_text(statement, 1, [thisNickname UTF8String], -1, SQLITE_TRANSIENT);
NSLog(#"bind result= %i", result);
if(sqlite3_step(statement) != SQLITE_DONE) {
NSLog(#"Problems updating");
}
/* Finished */
sqlite3_finalize(statement);
}else
{
NSLog(#"Can not open DB.");
}
}else{
NSLog(#"path not exsist"); }
Base of my understanding, it seems like the way the NSArray is structured when they load the data could be different since you are using NSIndexPath.
I do recommend the following approach, using a Singleton Object.
Singleton Object works like a container that is shared among a fews view controller(s) or classes.
Back to your issue, you can store the object (singleEvent) in the Singleton for the other uitableview to pick it up.
This is assuming that your singleEvent object have the key fields such as Id.
Hope this helps.