I got this exc_bad_access problem in AppDelegate.m
What I did and want is to have multiple sql query. To avoid complexity, I did two blocks (it will have more) and both are querying different table from sql.
-(void)readDataFromDatabase {
// Setup the database object
sqlite3 *database;
// Initialize the budgetobjects Array
Part1Array = [[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 part1TBL";
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
// You can add more rows based on your object
NSString *Part1_Name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *Part1_Description = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
// Create a new Restaurant with the data from the database
Part1 *newPart1 = [[Part1 alloc] initWithName:Part1_Name description:Part1_Description];
// Add the budgetobject to BudgetObjectsrantArray
[Part1Array addObject:newPart1];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
// Setup the database object
sqlite3 *database2;
// Initialize the budgetobjects Array
Part2Array = [[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 part2TBL";
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
// You can add more rows based on your object
NSString *Part2_Name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *Part2_Description = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
// Create a new Restaurant with the data from the database
Part2 *newPart2 = [[Part2 alloc] initWithName:Part2_Name description:Part2_Description];
// Add the budgetobject to BudgetObjectsrantArray
[Part2Array addObject:newPart2];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database2);
}
#end
The exc_bad_access highlighted at the end where
sqlite3_close(database2);
I'm not familiar with sqlite, but it looks like the issue with your code is that you're never opening 'database2'. Instead, you open 'database' twice, which looks like a typo.
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
....
sqlite3_close(database);
...
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// <--- This should be &database2
...
sqlite3_close(database2);
EDIT: Please note Mat's answer as well - there's several places where you're using database when you meant to use database2, and you might want to consider just reusing database, or extracting this functionality into a shared function if applicable.
Related
Here is my code i am getting only the last value of the database in the array but i need the entire column values in my array...
//select the values from the db
NSString *sql = [NSString stringWithFormat:#"SELECT * FROM district_details"];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil)==SQLITE_OK)
{
while (sqlite3_step(statement)==SQLITE_ROW)
{
char *field2 = (char *)sqlite3_column_text(statement, 1);
field2Str = [[NSString alloc]initWithUTF8String:field2];
str = [NSString stringWithFormat:#"%#", field2Str]; NSLog(#"the value from thr field1 from the district name is %#...",field2Str);
myarray =[[NSMutableArray alloc]initWithObjects:#"--select the value--",nil];
[myarray addObject:field2Str];
NSLog(#"the value of the myarray is......%#",myarray);
}
}
Initiate your array object once before you use it, if you initiate it inside while loop like you do it loses the previous added objects and takes fresh allocation inside the heap memory.
Just put this code inside viewDidLoad method and remove from while loop:
- (void)viewDidLoad {
[super viewDidLoad];
// mutable array allocation do once here
myarray =[[NSMutableArray alloc]initWithObjects:#"--select the value--",nil];
}
Now use below code to fetch entire column from data base:
//select the values from the db
NSString *sql = [NSString stringWithFormat:#"SELECT * FROM district_details"];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil)==SQLITE_OK)
{
while (sqlite3_step(statement)==SQLITE_ROW)
{
char *field2 = (char *)sqlite3_column_text(statement, 1);
field2Str = [[NSString alloc]initWithUTF8String:field2];
// --------- myarray allocation removed from here -----------
[myarray addObject:field2Str];
NSLog(#"the value of the myarray is......%#",myarray);
}
sqlite3_finalize(statement);
}
sqlite3_close(db);
The problem is that you are instantiating a new mutable array in ever loop of your while statement. You want to instantiate it once, before the loop, and inside the loop merely addObject.
NSString *sql = [NSString stringWithFormat:#"SELECT * FROM district_details"];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil)==SQLITE_OK) {
myarray = [[NSMutableArray alloc] initWithObjects:#"--select the value--",nil];
while (sqlite3_step(statement)==SQLITE_ROW) {
char *field2 = (char *)sqlite3_column_text(statement, 1);
field2Str = [[NSString alloc] initWithUTF8String:field2];
[myarray addObject:field2Str];
}
sqlite3_finalize(statement); // remember to finalize to prevent SQLite leak
}
Trying to learn Sqlite without using a wrapper and have managed most things but am really stuck on UPDATE queries
I am trying to update a sting in one column based on its _ID number which is the primary Key and is unique.
I have tried all sorts of code from all over google . This one says it has worked but when I check the column has not been updated
here is the code
NSDateFormatter *formatter;
NSString *dateString;
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy HH:mm"];
dateString = [formatter stringFromDate:[NSDate date]];
NSString *IDCODE = code.stringValue;
NSInteger b = [IDCODE integerValue];
sqlite3 *contactDB; //Declare a pointer to sqlite database structure
const char *dbpath = [dbPath UTF8String]; // Convert NSString to UTF-8
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
//Database opened successfully
NSString *databaseName = #"vistorlog.db";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
const char *dbPath=[databasePath UTF8String];
if (sqlite3_open(dbPath, &myDB)==SQLITE_OK) {
NSLog(#"database Opened");
const char* updateQuery="update LOG set TIMEOUT='22/03/19' where _ID=1";
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(myDB, updateQuery, -1, &stmt, NULL)==SQLITE_OK) {
NSLog(#"Query Executed");
}else{
NSLog(#"Query NOT Executed");
}
}
sqlite3_close(myDB);
}
else {
//Failed to open database
}
It opens the DB vistorlog.db ok. There is a table called LOG and there is column called TIMEOUT which is where I want the string to be updated and there is a column called _ID which is what Im basing the query on yet it won't update
eventually I want to have the update statement use the string variable dateString as the string to update and b as the integer variable for the _ID
any ideas where Im going wrong?
Any help appreciated
Mark
EDIT
WORKING CODE TO UPDATE A QUERY
sqlite3 *contactDB; //Declare a pointer to sqlite database structure
const char *dbpath = [dbPath UTF8String]; // Convert NSString to UTF-8
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
//Database opened successfully
NSString *databaseName = #"vistorlog.db";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
const char *dbPath=[databasePath UTF8String];
if (sqlite3_open(dbPath, &myDB)==SQLITE_OK) {
NSLog(#"database Opened");
// define dateString and IDCODE as strings before this
const char *updateQuery = "Update log set TIMEOUT=? where _ID=?";
sqlite3_stmt *stmt;
// Prepare Stment
if (sqlite3_prepare_v2(myDB, updateQuery, -1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, [dateString UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, [IDCODE UTF8String], -1, SQLITE_TRANSIENT); if(sqlite3_step(stmt) == SQLITE_DONE) {
NSLog(#"Query Executed");
} else {
NSLog(#"Query NOT Executed: %s", sqlite3_errmsg(myDB));
}
sqlite3_finalize(stmt);
}else{
NSLog(#"Statement NOT Prepared: %s", sqlite3_errmsg(myDB));
}
}
sqlite3_close(myDB);
}
else {
//Failed to open database
}
Don't forget to import sqlite3.h
Mark
You are only preparing the statement but not actually executing it.
You need to execute sqlite3_step() after you execute sqlite3_prepare_v2
if (sqlite3_prepare_v2(myDB, updateQuery, -1, &stmt, NULL) == SQLITE_OK) {
if(sqlite3_step(stmt) == SQLITE_DONE) {
NSLog(#"Query Executed");
} else {
NSLog(#"Query NOT Executed: %s", sqlite3_errmsg(myDB));
}
sqlite3_finalize(stmt);
}else{
NSLog(#"Statement NOT Prepared: %s", sqlite3_errmsg(myDB));
}
I'm inserting some data on a sqlite db, It works fine but what I noticed is that I can't insert words that contains the character ", is it a common issue? should I change parse the text and edit every " character I find?
This is the code i'm using in order to insert data into my DB:
UICollectionViewCell *cell = (UICollectionViewCell *)button.superview.superview;
NSIndexPath *indexPath = [self.customCollectionView indexPathForCell:cell];
FolderProducts *item = _feedItems[indexPath.item];
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &Carrello) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO CarrelloMese (titolo, codice, prezzo, urlImg) VALUES (\"%#\", \"%#\", \"%#\", \"%#\")",item.nomeProdotto, item.codice, item.prezzo, item.urlImg];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(Carrello, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
} else {
}
sqlite3_finalize(statement);
sqlite3_close(Carrello);
}
You need to bind your SQLite statements using the sqlite3_bind_xxx() function. Basically, you remove all variables from your statement (in your case the %#) and replace them with '?'. SQLite then knows that where an ? is HAS to be a variable, and therefore doesn't get it mixed up with a command.
For example, say you wanted to bind the word "INSERT". Using ? SQLite won't read this as a command and then flag an error.
Read the docs (link above) for full information on how to use the bind function.
Here's what your code might look like with binding (UNTESTED):
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &Carrello) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO CarrelloMese (titolo, codice, prezzo, urlImg) VALUES (?,?,?,?)"];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(Carrello, insert_stmt, -1, &statement, NULL);
if (sqlite3_bind_text(statement, 0, item.nomeProdotto.UTF8String, item.nomeProdotto.length, SQLITE_STATIC) != SQLITE_OK) {
NSLog(#"An error occurred");
}
// Etc etc
// SQLite bind works like this: sqlite_bind_text/int/e.t.c(sqlite3_stmt,index_of_variable, value);
// there are optionally parameters for text length and copy type SQLITE_STATIC and SQLITE_TRANSIENT.
if (sqlite3_step(statement) == SQLITE_DONE)
{
} else {
}
sqlite3_finalize(statement);
sqlite3_close(Carrello);
}
I am trying to program a username/password log in view controller, there is no errors, no warnings in my app but it always output out "match not found" even when i select a username that already exist in my database..I'd really appreciate it if u could help
this is the code:
[super viewDidLoad];
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths [0];
_databasePath = [[NSString alloc]initWithString:[docsDir stringByAppendingPathComponent:#"bank.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath:_databasePath] == NO)
{
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_bankDb) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt = " CREATE TABLE IF NOT EXISTS USER (USERNAME TEXT PRIMARY KEY, PASSWORD TEXT)";
if (sqlite3_exec(_bankDb, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
_status.text= #"failed to create table";
}
sqlite3_close(_bankDb);
} else {
_status.text=#"failed to open/create database";
}
}
- (IBAction)findContact:(id)sender {
const char *dbpath = [_databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &_bankDb) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:#"SELECT USERNAME, PASSWORD FROM USER WHERE USERNAME=\"%#\"", _usernameTextField.text];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(_bankDb, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *usernameField=[[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
_usernameTextField.text=usernameField;
NSString *passwordField = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1) ];
_passwordTextField.text=passwordField;
_status.text=#"match found";
} else {
_status.text=#"match not found";
}
sqlite3_finalize(statement);
}
sqlite3_close(_bankDb);
}
}
You should do the following things,
look at sqlite3_errmsg values if any queries fail (e.g. sqlite3_prepare_v2 does not return SQLITE_OK or sqlite3_step does not return either SQLITE3_DONE or SQLITE3_ROW);
Do not use stringWithFormat with your queries, but rather use ? placeholders and bind values with sqlite3_bind_text
Thus:
if (sqlite3_open(dbpath, &_bankDb) == SQLITE_OK)
{
const char *query_stmt = "SELECT USERNAME, PASSWORD FROM USER WHERE USERNAME=?";
if (sqlite3_prepare_v2(_bankDb, query_stmt, -1, &statement, NULL) != SQLITE_OK)
NSAssert(0, #"prepare failed: %s", sqlite3_errmsg(_bankDb));
if (sqlite3_bind_text(statement, 1, [_usernameTextField.text UTF8String], -1, NULL) != SQLITE_OK)
NSAssert(0, #"bind failed: %s", sqlite3_errmsg(_bankDb));
int rc = sqlite3_step(statement);
if (rc == SQLITE_ROW)
{
NSString *usernameField=[[NSString alloc]initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
_usernameTextField.text=usernameField;
NSString *passwordField = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1) ];
_passwordTextField.text=passwordField;
_status.text=#"match found";
} else if (rc == SQLITE_DONE) {
_status.text=#"match not found";
} else {
NSAssert(0, #"step failed: %s", sqlite3_errmsg(_bankDb));
}
sqlite3_finalize(statement);
sqlite3_close(_bankDb);
}
If you're still failing with match not found, you should:
examine the contents of _usernameTextField.text to make sure your IBOutlet is hooked up correctly.
look at the contents of the database and make sure a record with the desired userid is found; you haven't shown us where you add the userid, so it's hard for us to diagnose why the userid in question was not found.
I must confess that the overall logic (just looking for matching records for that userid and populating the password field if you found the userid) looks highly suspect (you shouldn't be storing passwords in plaintext, you certainly shouldn't be returning a password provided simply a userid), but I'm focusing solely on the tactical issue of why you're seeing match not found error message.
Say I am having 1 table called ABC with fields ABCid,ABCname,ABCImagePath,ABCSequence. Now this table contains more than 40 rows inside the same.
Now I have an array of numbers say 1,4,5,7,8 and I want to compare these numbers with ABCid and fetch all the data from table ABC as per these IDs.
+ (void) getSelectedData : (int)ABCId
{
NSString *dbPath = [self getDBPath];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
NSString *query =[NSString stringWithFormat:#"select * from [ABC] where ABCId=%d",ABCId];
const char *sql = [query cStringUsingEncoding:NSUTF8StringEncoding];
sqlite3_stmt *selectstmt;
if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK)
{
[self getInitialDataToDisplay:dbPath];
ABC *DataObj = [[ABC alloc] initWithPrimaryKey:ABCId];
DataObj.ABCName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
ABCImagePath = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)];
DataObj.ABCSequence = sqlite3_column_int(selectstmt,8);
[appDelegate.arrGetData addObject:DataObj]; }
else
{
NSAssert1(0,#"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
NSLog(#"%d",[appDelegate.DataArrayTrans count]);
}
else
sqlite3_close(database); //Even though the open call failed, close the database connection to release all the memory.
}
But app gets crashed in the if condition. Also note that I use below lines from the pageController to call the above function from ABC Object file.
for(int i=0;i<[arrRId count];i++)
{
[ABC getSelectedData:[[arrRId objectAtIndex:i]integerValue]];
[arr576576 addObject:[appDelegate.arrGetData valueForKey:#"ABCId"]];
}
Please guide me where I am making mistake. Thank you.
your query should be like this select * from ABC where ABCId IN (1,4,5,7,8)
that's it.