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.
Related
I want to check at the load time of application whether data is available or not in the table so for that I using following code on the viewload of my first file if available then move to other file else retain same but it can't give perfect result mainly row count is not working
NSString *dbPath;
NSString *docsDir;
NSArray *dirPath;
int count=0;
dirPath=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir=[dirPath objectAtIndex:0];
dbPath=[[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent:#"TimerDataBaseMain.db"]];
NSFileManager *fileManager=[NSFileManager defaultManager];
if([fileManager fileExistsAtPath: dbPath] == YES)
{
const char *databsPath=[dbPath UTF8String];
NSLog(#"from created;");
if(sqlite3_open(databsPath,&sqlDatabase) == SQLITE_OK)
{
const char *query="SELECT COUNT(*) FROM PRJDATA";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(sqlDatabase, query, -1, &statement, NULL)==SQLITE_OK) {
while(sqlite3_step(statement)==SQLITE_ROW)
{
count++;
NSLog(#"from count");
}
NSLog(#"from row count");
}
sqlite3_finalize(statement);
}
sqlite3_close(sqlDatabase);
}
if (count>0) {
ListEventCreated *listObject=[[ListEventCreated alloc] initWithNibName:#"ListEventCreated" bundle:[NSBundle mainBundle]];
listObject.title=#"List of event";
NSLog(#"from if condition");
NSLog(#"%i",count);
[self.navigationController pushViewController:listObject animated:YES];
[listObject release];
listObject=nil;
}
I believe , this is WRONG
SELECT COUNT(*) PRJDATA
You should use this
SELECT COUNT(*) FROM PRJDATA
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!
SQLite insert statement does not insert the new data
i am using this code
- (void) addN: (number *) theN
{
const char *sql = "insert into table (valueN) Values(?)";
sqlite3_stmt *addStmt = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString * docsDir = [paths objectAtIndex:0];
NSString * thePath = [docsDir stringByAppendingPathComponent: #"theDB.sqlite"];
sqlite3_open([thePath UTF8String], &database);
sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL);
sqlite3_bind_int(addStmt, 1, theN.theNumber);
sqlite3_step(addStmt);
sqlite3_finalize(addStmt);
sqlite3_close(database);
}
and the method to insert the record is
- (IBAction) saveN: (id) sender
{
numbers *theNumbers = [[numbers alloc] init];
number *theNumber = [[number alloc] init];
theNumber.theNumber = newN;
[theNumbers addN:theNumber];
[theNumbers release];
[theNumber release];
}
the code is executed but no record is inserted in the DB.
can someone please point me where is the mistake - cause there obviously is a mistake :)
You're not checking the return values of any of the sqlite3 calls. There's a good chance one of them is failing.
this code seems to work:
- (void) addN: (number *) theN
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *thePath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"theDB.sqlite"];
BOOL success = [fileManager fileExistsAtPath:thePath];
if (!success)
{
NSLog(#"Failed to find database file '%#'.", thePath);
}
if (!(sqlite3_open([thePath UTF8String], &database) == SQLITE_OK))
{
NSLog(#"An error opening database, normally handle error here.");
}
const char *sql = "insert into table (valueN) Values(?)";
sqlite3_stmt *addStmt = nil;
if (sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
{
NSLog(#"Error, failed to prepare statement, normally handle error here.");
}
sqlite3_bind_int(addStmt, 1, theN.theNumber);
sqlite3_step(addStmt);
if(sqlite3_finalize(addStmt) != 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.");
}
}
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
I'm trying to cache some images in sqlite as nsdata and I'm having an issue when I attempt to insert the byte array using sqlite3_exec and a raw SQL string (as NSString)
NSData *imgData = UIImagePNGRepresentation(img);
NSString* sql = [NSString stringWithFormat:#"INSERT INTO persistedimg (imgx,idvalx) VALUES (%#,'%#')", imgData, idValue];
rc = sqlite3_exec(db, [sql UTF8String], callbackFunction, (void*)contextObject, &zErrMsg);
But the problem with the above is I'm adding NSData to the sql string directly instead of the bytes.
I wanted to do something like this
... [imgData bytes], [imgData length]
But because I'm not using the typical "_bind_blob" like approach I'm not sure how to do it w/ a raw string
Update
I'm using a wrapper that I'd like to stick w/ and simply write a new method to support image insert / query commands
the below is my entire wrapper class so far
**
#import "SQLiteAccess.h"
#import <sqlite3.h>
#implementation SQLiteAccess
+ (NSString *)pathToDB {
NSString *dbName = #"test123";
NSString *originalDBPath = [[NSBundle mainBundle] pathForResource:dbName ofType:#"db"];
NSString *path = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *appSupportDir = [paths objectAtIndex:0];
NSString *dbNameDir = [NSString stringWithFormat:#"%#/test123", appSupportDir];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDir = NO;
BOOL dirExists = [fileManager fileExistsAtPath:dbNameDir isDirectory:&isDir];
NSString *dbPath = [NSString stringWithFormat:#"%#/%#.db", dbNameDir, dbName];
if(dirExists && isDir) {
BOOL dbExists = [fileManager fileExistsAtPath:dbPath];
if(!dbExists) {
NSError *error = nil;
BOOL success = [fileManager copyItemAtPath:originalDBPath toPath:dbPath error:&error];
if(!success) {
NSLog(#"error = %#", error);
} else {
path = dbPath;
}
} else {
path = dbPath;
}
} else if(!dirExists) {
NSError *error = nil;
BOOL success =[fileManager createDirectoryAtPath:dbNameDir attributes:nil];
if(!success) {
NSLog(#"failed to create dir");
}
success = [fileManager copyItemAtPath:originalDBPath toPath:dbPath error:&error];
if(!success) {
NSLog(#"error = %#", error);
} else {
path = dbPath;
}
}
return path;
}
+ (NSNumber *)executeSQL:(NSString *)sql withCallback:(void *)callbackFunction context:(id)contextObject {
NSString *path = [self pathToDB];
sqlite3 *db = NULL;
int rc = SQLITE_OK;
NSInteger lastRowId = 0;
rc = sqlite3_open([path UTF8String], &db);
if(SQLITE_OK != rc) {
NSLog(#"Can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return nil;
} else {
char *zErrMsg = NULL;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
rc = sqlite3_exec(db, [sql UTF8String], callbackFunction, (void*)contextObject, &zErrMsg);
if(SQLITE_OK != rc) {
NSLog(#"Can't run query '%#' error message: %s\n", sql, sqlite3_errmsg(db));
sqlite3_free(zErrMsg);
}
lastRowId = sqlite3_last_insert_rowid(db);
sqlite3_close(db);
[pool release];
}
NSNumber *lastInsertRowId = nil;
if(0 != lastRowId) {
lastInsertRowId = [NSNumber numberWithInteger:lastRowId];
}
return lastInsertRowId;
}
static int singleRowCallback(void *queryValuesVP, int columnCount, char **values, char **columnNames) {
NSMutableDictionary *queryValues = (NSMutableDictionary *)queryValuesVP;
int i;
for(i=0; i<columnCount; i++) {
[queryValues setObject:values[i] ? [NSString stringWithFormat:#"%s",values[i]] : [NSNull null]
forKey:[NSString stringWithFormat:#"%s", columnNames[i]]];
}
return 0;
}
+ (NSString *)selectOneValueSQL:(NSString *)sql {
NSMutableDictionary *queryValues = [NSMutableDictionary dictionary];
[self executeSQL:sql withCallback:singleRowCallback context:queryValues];
NSString *value = nil;
if([queryValues count] == 1) {
value = [[queryValues objectEnumerator] nextObject];
}
return value;
}
+ (NSNumber *)insertWithSQL:(NSString *)sql {
sql = [NSString stringWithFormat:#"BEGIN TRANSACTION; %#; COMMIT TRANSACTION;", sql];
return [self executeSQL:sql withCallback:NULL context:NULL];
}
+ (void)updateWithSQL:(NSString *)sql {
sql = [NSString stringWithFormat:#"BEGIN TRANSACTION; %#; COMMIT TRANSACTION;", sql];
[self executeSQL:sql withCallback:NULL context:nil];
}
#end
**
Any help with this solution would be huge!
I think a large part of the issue you are running into here is that you are trying to simplify the SQLite3 APIs too much. The APIs are not just for executing textual SQL queries; prepared statements and bind parameters exist for a reason. You shouldn't be trying to insert binary data in a string. That's just asking for problems, especially if your binary data has nulls in it.
To insert blobs, you really do need to use sqlite3_bind_blob with sqlite3_prepare_v2. When you bind the blob, you will need to also use [imgData bytes] as the blob data.
Are you perhaps looking for help reconstructing your API to make this sort of thing easier for this particular image caching use case?
Edit
Here's a simple example using bind to insert binary data. Assume there is a table called my_table with 2 columns: name of type VARCHAR and data of type BLOB. Please note that I have not tested or even tried compiling this, so there may be typos or errors.
sqlite3 *database;
// Open a connection to the database given its file path.
if (sqlite3_open("/path/to/sqlite/database.sqlite3", &database) != SQLITE_OK) {
// error handling...
}
// Construct the query and empty prepared statement.
const char *sql = "INSERT INTO `my_table` (`name`, `data`) VALUES (?, ?)";
sqlite3_stmt *statement;
// Prepare the data to bind.
NSData *imageData = UIImagePNGRepresentation([UIImage imageNamed:#"something"]);
NSString *nameParam = #"Some name";
// Prepare the statement.
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
// Bind the parameters (note that these use a 1-based index, not 0).
sqlite3_bind_text(statement, 1, nameParam);
sqlite3_bind_blob(statement, 2, [imageData bytes], [imageData length], SQLITE_STATIC);
// SQLITE_STATIC tells SQLite that it doesn't have to worry about freeing the binary data.
}
// Execute the statement.
if (sqlite3_step(statement) != SQLITE_DONE) {
// error handling...
}
// Clean up and delete the resources used by the prepared statement.
sqlite3_finalize(statement);
// Now let's try to query! Just select the data column.
const char *selectSql = "SELECT `data` FROM `my_table` WHERE `name` = ?";
sqlite3_stmt *selectStatement;
if (sqlite3_prepare_v2(database, selectSql, -1, &selectStatement, NULL) == SQLITE_OK) {
// Bind the name parameter.
sqlite3_bind_text(selectStatement, 1, nameParam);
}
// Execute the statement and iterate over all the resulting rows.
while (sqlite3_step(selectStatement) == SQLITE_ROW) {
// We got a row back. Let's extract that BLOB.
// Notice the columns have 0-based indices here.
const void *blobBytes = sqlite3_column_blob(selectStatement, 0);
int blobBytesLength = sqlite3_column_bytes(selectStatement, 0); // Count the number of bytes in the BLOB.
NSData *blobData = [NSData dataWithBytes:blobBytes length:blobBytesLength];
NSLog("Here's that data!\n%#", blobData);
}
// Clean up the select statement
sqlite3_finalize(selectStatement);
// Close the connection to the database.
sqlite3_close(database);