I'm trying to add SQLite support in my app but I had a problem, so I tried to search something on the Internet and I found a tutorial. But the problem is that the db used by the tutorial is read by the app but when I add my personal db (I've modified the code) it is not read. Any suggestions?
This is (part of) the code:
static sqlite3 *database = nil;
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
const char *sql = "select id,name from myDb";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
while(sqlite3_step(selectstmt) == SQLITE_ROW) {
id = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 0)];
name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
dictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:id, #"id", name, #"nome", nil];
[dictionary release];
}
}
else{
sqlite3_close(database);
}
Before the else statement you need to release the resources:
// "Finalize" the statement - releases the resources associated with the statement.
sqlite3_finalize(selectstmt);
And what is the purpose of the release statement?
Related
I am having SQLite database where I have one table called tblUser,where I am having variables say Id,name,image,gender.
In my app,I am giving functionality to add,delete update the User entry (Common functionality). Say I have 2 record by default on the page with 2 users and that both are deleted. Now the 3rd record inserted will be provided Primary key as 3.
Now if I edit that particular record then it is not updated with new data rather the primary key of the same gets replaced with 1 when I call following function :
+ (void) getInitialDataToDisplay:(NSString *)dbPath
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//sqlite3_open([dbPath UTF8String], &database);
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
const char *sql = "select UserId,UserAge,UserName,UserGender,UserImage from [tblUser]";
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK)
{
while(sqlite3_step(selectstmt) == SQLITE_ROW)
{
NSInteger primaryKey = sqlite3_column_int(selectstmt,0);
UserDetail *DataObj = [[UserDetail alloc] initWithPrimaryKey:primaryKey];
DataObj.UserAge = sqlite3_column_int(selectstmt,1);
DataObj.UserName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)];
DataObj.UserGender = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 3)];
DataObj.UserImage = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 4)];
DataObj.isDirty = NO;
[appDelegate.DataArray addObject:DataObj];
}
}
else
{
NSAssert1(0,#"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
}
else
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
Note that I am calling this function when I come back to the page where listing of the user is shown after clicking save button of the page where all details need to be filled. Any hint will be much helpful. Thank you.
Assuming that UserId is an INTEGER PRIMARY KEY:
SQLite will create new IDs as one larger than the previously largest value,
but if the table is empty, it will (re)start at 1.
This must be a stupid problem but i cant get my query to work. Its as if my database is empty (I double checked, its not). Its a simple SELECT * FROM table query. This is how i try it:
+(MyDatabase *)database{
if (database == nil) {
database = [[MyDatabase alloc] init];
}
return database;
}
- (id)init
{
self = [super init];
if (self) {
NSString *sqliteDb = [[NSBundle mainBundle] pathForResource:#"personsDB" ofType:#"sqlite3"];
if (sqlite3_open([sqliteDb UTF8String], &database) != SQLITE_OK) {
NSLog(#"Fail to open Database.");
}
}
return self;
}
and
-(NSArray *)getAllRows{
NSMutableArray *retArray = [[NSMutableArray alloc] init];
NSString *query = #"SELECT * FROM persons";
sqlite3_stmt *statement;
NSLog(#"checking SQLITE_OK?");
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) {
NSLog(#"SQLITE_OK");
while (sqlite3_step(statement) == SQLITE_ROW) {
int personID = sqlite3_column_int(statement, 0);
char *personChars = (char *) sqlite3_column_text(statement, 1);
int gender = sqlite3_column_int(statement, 2);
int related = sqlite3_column_int(statement, 3);
NSString *person = [[NSString alloc] initWithUTF8String:personChars];
MyDBInfo *info = [[MyDBInfo alloc] initWithpersonID:personID person:person gender:gender related:related ];
[retArray addObject:info];
}
sqlite3_finalize(statement);
}
return retArray;
}
I think this is all the interesting stuff.
In my Log I get checking SQLITE_OK?, but no SQLITE_OK. I'm not getting Fail to open Database. so I'm assuming that its all good there.
My Database is full and there is a table called persons. I'm very new to sqlite in iOS apps.
Thank you.
Are you sure the db is included in your bundle? The default behavior of sqlite3_open is SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, so it will be created on your device/simulator if it wasn't there already, so you won't see Fail to open Database. Use sqlite3_open_v2 if you don't want SQLITE_OPEN_CREATE. Anyway, I sometimes have added files to my xcode project and they're not automatically included in my bundle. Select the target in the top of the project navigator, click on the target, select the target in the main panel, select "Build Phases", and see if your db is included in the "Copy Bundle Resources".
Probably unrelated, but I always copy the database from the bundle to documents folder (if it's not there already).
If I don't receive the expected SQLITE_OK, I always look at my return code or log my error message and error codes (and this would probably report that the table in question was not found, which would have let you identify the problem).
Thus,
NSLog(#"%s db err '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(contactDB), sqlite3_errcode(contactDB));
I'm having some trouble getting this to work.
This is the code I want to execute:
[self openDB];
sqlite3_stmt *statement;
NSString *sql2 = [NSString stringWithFormat:#"INSERT INTO CheckList (CLName, DateAdd, Active, Costum, Percentage, UserId) VALUES ('ola232332332324', '2012-02-03', 1, 1, NULL, 1)"];
if(sqlite3_prepare_v2(db, [sql2 UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
alert1 = [[UIAlertView alloc]
initWithTitle:#"Grats" message:#"The query was executed!" delegate:self cancelButtonTitle:#"Continue" otherButtonTitles: nil];
[alert1 show];
[alert1 release];
}
else {
NSAssert(0, #"Failed to execute");
}
sqlite3_finalize(statement);
And this is the code I use to call the db:
-(NSString *) filePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"prosegur.sqlite"];
}
-(void) openDB {
sqlite3_open([[self filePath] UTF8String], &db);
if (sqlite3_open([[self filePath] UTF8String], &db) != SQLITE_OK){
NSAssert(0, #"Failed to open db");
}
}
Edit: Trying to use the FMDB, here's the code:
FMDatabase *database = [FMDatabase databaseWithPath:#"prosegur.sqlite"];
if([database open]){
NSLog(#"yes");
[database executeUpdate:#"INSERT INTO CheckList (CLName, DateAdd, Active, Costum, UserId) VALUES ('cenas', '2012-02-0', 1, 1, 1)"];}
else
{
NSLog(#"not");
}
Passes by the [database open] verification, but it doesn't execute the query.
EDIT 2: Already did what it was suggested, i'm starting to think that it creates a database and executes the query inside of it, but since it doesn't exist any table, it ignores that fact.
Here's the updated code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [[paths objectAtIndex:0] retain];
NSString *path = [[docsPath stringByAppendingPathComponent:#"prosegur.sqlite"] retain];
FMDatabase *database = [FMDatabase databaseWithPath:path];
[database open];
if([database open])
{
NSLog(#"yes");
[database executeUpdate:#"INSERT INTO CheckList (CLName) VALUES (?)", #"cenas"];
}
else
{
NSLog(#"no");
}
[database close];
Maybe a silly question, but you are aware that sqlite3_prepare_v2 only prepares the statement and does not actually execute it? You also need to call sqlite3_step to actually do the insert,
You could use sqlite3_exec instead, which simply executes a statement without doing the prepare/execute two-step.
I have had a lot of headache while using standart sqlite3 api in iOS development.
Check out FMDB framework. It is very simple to use, and you can find lots of tutorials on the web.
If you do not want that framework, try using NSError for catching an error on query execution.
Sample Example.
+(BOOL)InsertDataInPin:(NSString *)pin
{
NSString *databasePath =Your DatabasePath;
NSString *SQL=#"INSERT INTO pincode Values(?)";
sqlite3_stmt *dataset;
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK ) {
if (sqlite3_prepare_v2(database, [SQL UTF8String], -1, &dataset, NULL) == SQLITE_OK)
{
sqlite3_bind_text(dataset, 1, [pin UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_step(dataset);
}
sqlite3_close(database);
}
}
I found out the answer, if anyone is having troubles like this, check out the following link:
IPhone Development - Failed to use SQLite
Thanks to all of you for the support!
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
First of all, I know that I should not use an SQLite database to store image, but I only store favicon of website which are really small.
My problem is that I try to insert those favicon into the database (seems to work), I convert the favicon to NSData with the -tiffrepresentation method of NSimage and then insert it to my database into a blob column:
NSImage *favico = [webview mainFrameIcon];
[appDelegate insertBookmark:[titleField stringValue] url:[urlfield stringValue] data:[favico TIFFRepresentation]]
The SQLite method look like this:
-(void)insertBookmark:(NSString *)title url:(NSString *)url data:(NSData *)data
{
NSData *imagedata = [[NSData alloc]initWithData:data];
sqlite3 *database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSString *query = [NSString stringWithFormat:#"INSERT INTO Bookmarks (title, url, image) VALUES ('%#', '%#', '%#')",title, url, data];
const char *querychar = [query UTF8String];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, querychar, -1, &statement, NULL) == SQLITE_OK)
{
int row = 3;
sqlite3_bind_blob(statement, row, [imagedata bytes], [imagedata length], NULL);
sqlite3_step(statement);
sqlite3_finalize(statement);
}
else
{
NSLog(#"Error");
}
[databasePath retain];
[databaseName retain];
}
sqlite3_close(database);
[imagedata release];
}
When I look into the database I have value in the image column between <data> (normal ? )
Now when I extract the blob from the database and try to put it in my object I got null in the NSimage:
-(void) readDatabase {
// Setup the database object
sqlite3 *database;
bookmarks = [[NSMutableArray alloc] init];
// 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
const char *sqlStatement = "SELECT * FROM Bookmarks ORDER BY title ASC";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *aTitle = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aUrl = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSData *data = [[NSData alloc] initWithBytes:sqlite3_column_blob(compiledStatement, 3) length:sqlite3_column_bytes(compiledStatement, 3)];
NSImage *image = [[NSImage alloc]initWithData:data];
bookmarkObject *bookmark = [[bookmarkObject alloc] initWithName:aTitle url:aUrl favico:image];
[bookmarks addObject:bookmark];
[bookmark release];
[data release];
[image release];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
sqlite3_close(database);
[databasePath retain];
[databaseName retain];
}
}
Thanks in advance
The < and > around your actual data come from NSData. By using %# in your format string and providing data, NSString sends description to data. [NSData description] wraps the content between < and >.
Another issue with your code is, that you seem to mix parameter-less & parameter prepared statements:
Either use stringWithFormat: to create a complete query statement
or use a query like INSERT INTO Bookmarks (title ...) VALUES (? ...) combined with sqlite3_bind_blob
The parameter syntax SQLite supports can be found here:
http://www.sqlite.org/c3ref/bind_blob.html