First of all I am from spain so sorry about my grammar. I am writing some data to a sqlite data base, here is my code:
I have allredy checked that the data base, table and column names are ok, when I change anything I get errors, so the code its working properly.
#try {
NSFileManager *fileMgr=[NSFileManager defaultManager];
NSString *dbPath=[self database];
BOOL succes=[fileMgr fileExistsAtPath:dbPath];
if(!succes)
{
NSLog(#"Cannot locate database '%#'.",dbPath);
}
if (!(sqlite3_open([dbPath UTF8String], &dbcapturas)==SQLITE_OK)) {
NSLog(#"An error has occured: %#",sqlite3_errmsg(dbcapturas));
}
//sqlite3_stmt *sqlStatement;
NSString *asd=numero.text;
NSString *insertStatement=[NSString stringWithFormat:#"INSERT INTO captura(key,tecnico, fecha,provincia,municipio,latitud,longitud,altura,familia,especie,numero,comentario)Values(\"%#\", \"%#\", \"%#\", \"%#\", \"%#\", \"%#\", \"%#\", \"%#\", \"%#\", \"%#\", \"%#\", \"%#\")",asd,tecnico,fechaHora,tecnico,municipio,latitud,longitud,altura,tecnico,animal,asd,coment];
char *error;
if((sqlite3_exec(dbcapturas, [insertStatement UTF8String], NULL, NULL, &error))==SQLITE_OK)
{
NSLog(#"Person inserted.");
}
else
{
NSLog(#"Error: %s", error);
}
} #catch (NSException *exception) {
NSLog(#"fail");
}
#finally {
NSLog(#"cerrada");
sqlite3_close(dbcapturas);
}
the first time I click on the save button I get:
2012-07-04 12:17:45.644 adasdasd[1783:f803] Person inserted.
and the second time I get :
2012-07-04 12:29:18.959 adasdasd[1840:f803] Error: column key is not
unique
So my code should be ok but when I open the database with the firefox add-on its totally empty, any idea?
Edit: I now call
-(NSString *)database{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"capturas.sqlite"];
}
but now I get a error saying me: no such table: capturas
I have a table capturas in my db 100% sure
When setting up your table, the column key is probably indexed or defined to be unique or auto-incrementing. When you do the insert, you pass a specific key, namely whatever is in the variable asd. If you try that the second time, you will get the sqlite error because the column key has to be unique. If it is auto increment, just leave it out and it will be filled automatically.
The first entry should be in the database if you closed it correctly. Make sure you are checking the correct copy of the database with Firefox (test by inserting a dummy record in your app delegate, for example).
Related
I'm new to developing in objective C and am struggling to step into an IF statement (sqlite3_exec==SQLITE_OK). I have been using tutorials and dont seem to be able to find my answer.
Is anyone able to show me where I'm going wrong?
-(IBAction)addItemButton:(id)sender {
char *error;
if (sqlite3_open([dbPathString UTF8String], &itemDB) == SQLITE_OK) {
NSString *insertStat = [NSString stringWithFormat:#"INSERT INTO ITEMS(ITEM) values ('%s')", [self.itemField.text UTF8String]];
const char *insert_stat = [insertStat UTF8String];
if (sqlite3_exec(itemDB, insert_stat, NULL, NULL, &error)== SQLITE_OK) {
NSLog(#"Item Added");
Item *item = [[Item alloc]init];
[item setItem:self.itemField.text];
[arrayOfItem addObject:item];
}else{
NSLog(#"Item not added");
}
sqlite3_close(itemDB);
}
}
I have written a simple SQLite helper for performing general database tasks with few lines of code like fetching records from DB, Inserting, Updating and Deleting records.
Source code can be found here with example
Download and Drag, drop the ZeeSQLiteHelper classes in your project and set your DB name in ZeeSQLiteHelper class.
Getting records example:
[ZeeSQLiteHelper initializeSQLiteDB];
NSString *query = #"SELECT * FROM recipes";
NSMutableArray *results = [ZeeSQLiteHelper readQueryFromDB:query];
[ZeeSQLiteHelper closeDatabase];
For insertion
[ZeeSQLiteHelper initializeSQLiteDB];
NSString *queryString = [NSString stringWithFormat:#"insert into %# (%#,%#) VALUES ('%#','%#')",downloadsTblName, tblAttrFileName, tblAttrFileURL, downloadInfo.fileName, downloadInfo.fileURL];
[ZeeSQLiteHelper executeQuery:queryString];
[ZeeSQLiteHelper closeDatabase];
For Updation
[ZeeSQLiteHelper initializeSQLiteDB];
NSString *queryString = [NSString stringWithFormat:#"UPDATE %# SET %#='%#' WHERE %#='%#'",downloadsTblName, tblAttrFileName, newFilePath.lastPathComponent, tblAttrFileName,oldFilePath.lastPathComponent];
[ZeeSQLiteHelper executeQuery:queryString];
[ZeeSQLiteHelper closeDatabase];
For Deletion
[ZeeSQLiteHelper initializeSQLiteDB];
NSString *queryString = [NSString stringWithFormat:#"DELETE FROM %# WHERE %#='%#'",downloadsTblName, tblAttrFileName,downloadedFileObj.videoTitle];
[ZeeSQLiteHelper executeQuery:queryString];
[ZeeSQLiteHelper closeDatabase];
Appropriate message of success or failure will be logged on console.
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 can't make a Select on a table in a sqlite database.
I have the following code to copy the .sqlite-file to the user's directory:
// copy the database to the user's directory
- (void)checkAndCreateDB {
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:databasePath];
// If the database already exists then return without doing anything
if(success) return;
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp = [[NSBundle mainBundle] pathForResource:databaseName ofType:nil];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
[fileManager release];
}
And the select here:
sqlite3 *database;
categories = [[NSMutableArray alloc] init];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "select * from category";
sqlite3_stmt *compiledStatement;
NSLog(#"get");
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
NSLog(#"test");
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *cId = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *cName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
Category *category = [[Category alloc] initWithId:cId name:cName];
[categories addObject:category];
[categories release];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
the log shows only: "get". "test" isn't there.
I hope someone can help me.
I believe your database copy code isn't working as you are passing nil to the ofType parameter of [NSBundle pathForResource]. Try passing the correct file extension and add code to detect the success or failure of the copy operation (and make your checkAndCreateDB method return BOOL) and take it from there.
Your database select code looks OK to me, so I'm guess you have an empty database as explained in #Micheal's answer.
sqlite3_open will create a new (empty) database if the one specified doesn't exist. To make sure that this isn't what's happening, try using sqlite3_open_v2 instead and use SQLITE_OPEN_READWRITE as the flags argument. That way you'll get an error if you attempt to open a database that doesn't exist.
There is an example project for using SQLite here you can refer to: https://github.com/AaronBratcher/ABSQLite
It has classes for accessing SQLite in a more traditional database way that I feel makes things easier.
Here's the code... anybody see what's wrong? Also, why does the 2nd NSLog of "errmsg" cause the debugger to crash when debugging to the device (iPhone 3GS)
// Get the path to the database file
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = [searchPaths objectAtIndex:0];
NSString *databasePath = [documentPath stringByAppendingPathComponent:#"ppcipher.s3db"];
const char *cDatabasePath = [databasePath cStringUsingEncoding:NSUTF8StringEncoding];
NSLog(#"databasePath: %#", databasePath);
NSString *sqlCommand = #"CREATE TABLE CardData (card_id TEXT PRIMARY KEY NOT NULL, card_name TEXT NOT NULL, "
#"card_type TEXT, cide_val TEXT, create_date TEXT DEFAULT CURRENT_DATE, user_notes TEXT, gps_loc TEXT)";
const char cSQLCommand = [sqlCommand cStringUsingEncoding:NSUTF8StringEncoding];
char * errmsg = NULL;
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:databasePath error:NULL]; // <------------ delete d/b TESTING ONLY!
BOOL fileExists = [fileManager fileExistsAtPath:databasePath];
if(!fileExists) {
if(sqlite3_open(cDatabasePath, db) == SQLITE_OK) { // doesn't exist, so create it...
sqlite3_exec(db, &cSQLCommand, NULL, NULL, &errmsg); // now create the table...
NSLog(#"error: %#", errmsg);
}
It's crashing because errmsg is not an Objective-C object, which you're requiring by your use of the %# substitution. errmsg is a char *, which means you should be using %s.
As for why it's crashing....
sqlite3_open is defined as:
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
Your db is declared as sqlite3*. In other words, you're passing the wrong thing in. You should be doing:
sqlite3_open(cDatabasePath, &db)
While your desire to understand the SQLite C API is great, I still think you should use FMDB. It really mitigates these sorts of errors and lets you concentrate on the real problems with your code.
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.