NSMutableArray losing all of its objects - ios

I am making a function which allows you to read from a database and then puts the data into a NSMutableArray which it later returns for the user. Though for some reason when it is about to return the data the data is deleted from the array. Here is the code for the function:
+(NSMutableArray *) readFromDataBaseWithName:(NSString *)name withSqlStatement:(NSString *)sql {
sqlite3 *database;
NSMutableArray *rtn = [[NSMutableArray alloc] init];
NSMutableArray *new = [[NSMutableArray alloc] init];
int index = 0;
NSString *filePath = [self copyDatabaseToDocumentsWithName:name];
if (sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStateMent = [sql cStringUsingEncoding:NSASCIIStringEncoding];
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare(database, sqlStateMent, -1, &compiledStatement, NULL) == SQLITE_OK) {
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
// loop through elements in row and put them into array
const char *s = (char *)sqlite3_column_text(compiledStatement, index);
while (s) {
[new addObject:[NSString stringWithUTF8String:s]];
index++;
s = (char *)sqlite3_column_text(compiledStatement, index);
}
[rtn addObject:new];
[new removeAllObjects];
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return rtn;
}
Any advice would be much appreciated.

You keep reusing new. You need to create individual arrays each time.
+(NSMutableArray *) readFromDataBaseWithName:(NSString *)name withSqlStatement:(NSString *)sql {
sqlite3 *database;
NSMutableArray *rtn = [[NSMutableArray alloc] init];
int index = 0;
NSString *filePath = [self copyDatabaseToDocumentsWithName:name];
if (sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStateMent = [sql cStringUsingEncoding:NSASCIIStringEncoding];
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare(database, sqlStateMent, -1, &compiledStatement, NULL) == SQLITE_OK) {
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
// loop through elements in row and put them into array
NSMutableArray *new = [[NSMutableArray alloc] init];
const char *s = (char *)sqlite3_column_text(compiledStatement, index);
while (s) {
[new addObject:[NSString stringWithUTF8String:s]];
index++;
s = (char *)sqlite3_column_text(compiledStatement, index);
}
[rtn addObject:new];
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return rtn;
}

Related

Facing an issue while fetching data in sqlite in iOS

- (NSMutableArray*)getAllDataFromTableUSERINFO:(NSString *)fetchQuery {
NSMutableArray *resultArray1 =[[NSMutableArray alloc]init];
#autoreleasepool {
if (sqlite3_open([[self getDBPath]UTF8String],&database)==SQLITE_OK){
sqlite3_stmt *stmt;
const char *sqlfetch=[fetchQuery UTF8String];
if (sqlite3_prepare(database, sqlfetch, -1,&stmt, NULL)==SQLITE_OK) {
while (sqlite3_step(stmt)==SQLITE_ROW){
RM_USER_INFO *UserInfo = [[RM_USER_INFO alloc]init];
UserInfo.uid=[NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt,0)];
UserInfo.username=[NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt,1)];
UserInfo.password=[NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt,2)];
UserInfo.fname=[NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt,3)];
UserInfo.mname=[NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt,4)];
[resultArray1 addObject:UserInfo];
}
}
sqlite3_finalize(stmt);
stmt=nil;
sqlite3_close(database);
sqlite3_release_memory(120);
}
}
return resultArray1;
}
Get always EXE_BAD_ACCESS after fews operations
Try this function:
static NSInteger DBBUSY;
+(NSMutableArray *)executeQuery:(NSString*)str{
sqlite3_stmt *statement= nil;
sqlite3 *database;
NSString *strPath = Your Database path here;
while(DBBUSY);
DBBUSY = 1;
NSMutableArray *allDataArray = [[NSMutableArray alloc] init];
if (sqlite3_open([strPath UTF8String],&database) == SQLITE_OK) {
if (sqlite3_prepare_v2(database, [str UTF8String], -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSInteger i = 0;
NSInteger iColumnCount = sqlite3_column_count(statement);
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
while (i< iColumnCount) {
NSString *str = [self encodedString:(const unsigned char*)sqlite3_column_text(statement, i)];
NSString *strFieldName = [self encodedString:(const unsigned char*)sqlite3_column_name(statement, i)];
if(!str)
str = #"";
[dict setObject:str forKey:strFieldName];
i++;
}
[allDataArray addObject:dict];
}
}
DBBUSY = 0;
sqlite3_finalize(statement);
}
sqlite3_close(database);
return allDataArray;
}
This may help you :)

Getting database locked error while adding row 2nd time [duplicate]

This question already has answers here:
sqlite error database is locked
(8 answers)
Closed 6 years ago.
I am getting error Database Locked.
at first attempt it adds the row but after that i am getting the error
database locked.
I am trying to make web page saver so at first time when app loads it is adding the row but when again I try to save any webpage it is not saving and I am getting the error database locked.
Even the deletion is also not happening after saving one web page.
#import "DBManager.h"
static DBManager *sharedInstance = nil;
static sqlite3 *database = nil;
static sqlite3_stmt *statement = nil;
#implementation DBManager
+(DBManager*)getSharedInstance{
if (!sharedInstance) {
sharedInstance = [[super allocWithZone:NULL]init];
[sharedInstance createDB];
}
return sharedInstance;
}
-(BOOL)createDB{
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent: #"browser.db"]];
BOOL isSuccess = YES;
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
char *errMsg;
NSLog(#"insod");
const char *sql_stmt ="create table if not exists list(sno int primary key,name varchar(50),category varchar(30),path varchar(500),fav int)";
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg)
!= SQLITE_OK)
{
isSuccess = NO;
NSLog(#"Failed to create table");
}
sqlite3_close(database);
return isSuccess;
}
else {
isSuccess = NO;
NSLog(#"Failed to open/create database");
}
}else{
NSLog(#"File Exist");
}
return isSuccess;
}
-(BOOL) Delete:(NSString *) name{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK){
NSString *query = [NSString stringWithFormat:#"delete from list where name like '%#'",name];
const char *stmt = [query UTF8String];
sqlite3_prepare_v2(database, stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
NSLog(#"error: %s",sqlite3_errmsg(database));
sqlite3_finalize(statement);
return NO;
}
}else{
sqlite3_close(database);
return NO;
}
}
-(NSDictionary *) CatList:(NSString *) cat{
const char *dbpath = [databasePath UTF8String];
NSDictionary *dict;
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL =[NSString stringWithFormat:#"select name,path from list where category like '%#'",cat];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
// NSLog(#"inside list");
NSMutableArray *arr1 = [[NSMutableArray alloc] init];
NSMutableArray *arr2 = [[NSMutableArray alloc] init];
// NSMutableArray *arr3 = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
NSString *name = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
[arr1 addObject:name];
//NSLog(#"%#",name);
NSString *category = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
[arr2 addObject:category];
// //NSLog(#"%#",dept);
// NSString *path = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 3)];
// [arr3 addObject:path];
}
sqlite3_finalize(statement);
dict = #{#"name":arr1,#"path":arr2};
//NSLog(#"%#",dict);
}else{
NSLog(#"error: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
return dict;
}
- (BOOL) saveData:(NSString*)name category:(NSString*)category path:(NSString*)path{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *highest = #"select max(sno) from list";
const char *Query = [highest UTF8String];
if (sqlite3_prepare_v2(database, Query, -1, &statement, NULL) == SQLITE_OK){
if (sqlite3_step(statement) == SQLITE_ROW){
int sno = sqlite3_column_int(statement, 0);
NSString *insertSQL = [NSString stringWithFormat:#"insert into list values(\"%d\",\"%#\",\"%#\", \"%#\",\"%d\")",sno+1,name, category, path,0];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
sqlite3_finalize(statement);
return NO;
}
}else{
NSString *insertSQL = [NSString stringWithFormat:#"insert into list values(\"%d\",\"%#\",\"%#\", \"%#\",\"%d\")",1,name, category, path,0];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
sqlite3_finalize(statement);
return NO;
}
}
}
sqlite3_close(database);
}
return NO;
}
-(BOOL) Fav:(NSString *) name{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK){
NSString *query = [NSString stringWithFormat:#"update list set fav = 1 where name like '%#'",name];
const char *stmt = [query UTF8String];
sqlite3_prepare_v2(database, stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
sqlite3_finalize(statement);
return NO;
}
}else{
return NO;
}
}
-(NSArray *) GetListFav{
const char *dbpath = [databasePath UTF8String];
NSArray *dict;
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL = #"select name from list where fav = 1";
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
NSMutableArray *arr1 = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
NSString *name = [[NSString alloc] initWithUTF8String: (const char *) sqlite3_column_text(statement, 0)];
[arr1 addObject:name];
}
sqlite3_finalize(statement);
dict = arr1;
}else{
NSLog(#"error: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
return dict;
}
-(BOOL) removeFav:(NSString *) name{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK){
NSString *query = [NSString stringWithFormat:#"update list set fav = 0 where name like '%#'",name];
const char *stmt = [query UTF8String];
sqlite3_prepare_v2(database, stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE){
sqlite3_finalize(statement);
return YES;
}else {
sqlite3_finalize(statement);
return NO;
}
}else{
return NO;
}
}
-(NSArray *) GetList{
const char *dbpath = [databasePath UTF8String];
NSArray *dict;
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL = #"select name from list";
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
//NSLog(#"inside list");
NSMutableArray *arr1 = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
NSString *name = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
[arr1 addObject:name];
}
sqlite3_finalize(statement);
dict = arr1;
}else{
NSLog(#"error: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
return dict;
}
#end
You can only access sqllite once at a time. If you have multiple threads, you can run in this situation. Example:
So always try to close database once it is used using:
sqlite3_close(database);
You need to make sure every sqlite3_open is balanced with a sqlite3_close before trying to do sqlite3_open again:
Your saveData method has quite a few return statements that will prevent the database from ever calling sqlite3_close. Make sure all paths out of the method close the database properly. In the end, this means that you'll try to open the database although it's already open.
Or, better, just open the database once and leave it open, eliminating the repeated opening and closing of the database.
Your Delete, Fav, and removeFav methods are also not closing the database.
A few unrelated observations:
You should be wary about using stringWithFormat to build SQL with string parameters. If the string being searched for had a apostrophe in it, your code will fail. Use ? placeholders and then use sqlite3_bind_text to bind values to those placeholders.
If you make your sno column a AUTOINCREMENT, you won't have to do that "get the max sno before inserting new row" logic. Thus, the CREATE statement might look like:
create table if not exists list (
sno integer primary key autoincrement,
name text,
category text,
path text,
fav integer)
You can then omit sno from the INSERT statements, and it will automatically be assigned a unique identifier.

How to set results from sqlite to array NSMutableArray

HERE IS MY CODE:
NSString *ask = [NSString stringWithFormat:#"SELECT name FROM users"];
sqlite3_stmt *statement;
const char *query_statement = [ask UTF8String];
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_DB) == SQLITE_OK){
{
if (sqlite3_prepare_v2(_DB, query_statement, -1, &statement, nil) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *nameField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 0)];
}
sqlite3_finalize(statement);
sqlite3_close(_DB);
}
}
I want to set those result above to NSMUtableArray like this example:
totalStrings =[[NSMutableArray alloc]initWithObjects:#"xxx",#"xxx",#"xxx", nil];
What should I do ?
=================UP DATE ALL CODE =======================
Here is the aditonal code to make it easy to see. I really donĀ“t know what I have done wrong.
#interface ViewController ()
{
NSMutableArray *totalStrings;
NSMutableArray *filteredStrings;
BOOL isFiltered;
}
#property(strong, nonatomic)NSMutableArray *entries;
#end
#implementation ViewController;
#synthesize entries;
- (void)viewDidLoad {
// totalStrings =[[NSMutableArray alloc]initWithObjects:#"ggg",#"gggggg", nil];
// NSLog(#"%#",totalStrings);
NSMutableArray* result=[[NSMutableArray alloc] init];
NSString *ask = [NSString stringWithFormat:#"SELECT * FROM users"];
sqlite3_stmt *statement;
const char *query_statement = [ask UTF8String];
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_DB) == SQLITE_OK){
{
if (sqlite3_prepare_v2(_DB, query_statement, -1, &statement, nil) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *nameField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 0)];
//add your namefield here.
[result addObject:nameField];
totalStrings=[[NSMutableArray alloc] initWithArray:result];
}
sqlite3_finalize(statement);
sqlite3_close(_DB);
}
}
NSLog(#"%#",totalStrings);
//AND PUT THOSE RESULTS INTO THIS ARRAY ( I WILL USE THIS LATER)
//I want it to be this format: totalStrings=[[NSMutableArray alloc]initWithObjects:#"test1",#"test2",#"test3", nil];
}
The code below should work in case you want to get all namefields in array
NSMutableArray* result=[[NSMutableArray alloc] init];
NSString *ask = [NSString stringWithFormat:#"SELECT name FROM users"];
sqlite3_stmt *statement;
const char *query_statement = [ask UTF8String];
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_DB) == SQLITE_OK){
{
if (sqlite3_prepare_v2(_DB, query_statement, -1, &statement, nil) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *nameField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 0)];
//add your namefield here.
[result addObject:nameField];
}
sqlite3_finalize(statement);
sqlite3_close(_DB);
}
}
In the end you can do
totalStrings=[[NSMutableArray alloc] initWithArray:result];
Create and Alloc New NSMutableArray totalStrings and add nameField in the totalStrings in While Loop.
NSMutableArray *totalStrings = [[NSMutableArray alloc] init];
In while loop
[totalStrings addObject:nameField];
You can get it like this,
-(NSArray *)list_totalStrings
{
NSMutableArray *totalStrings = [[NSMutableArray alloc] init];
NSString *ask = [NSString stringWithFormat:#"SELECT name FROM users"]; //Make sure field and table names are proper
sqlite3_stmt *statement;
const char *query_statement = [ask UTF8String];
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_DB) == SQLITE_OK){
if (sqlite3_prepare_v2(_DB, query_statement, -1, &statement, nil) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *nameField = [[NSString alloc] initWithUTF8String:(const char *)sqlite3_column_text(statement, 0)];
[totalStrings addObject:nameField];
}
sqlite3_finalize(statement);
sqlite3_close(_DB);
NSLog(#"%#",totalStrings);
return totalStrings;
}
else
return nil;
}
else
return nil;
}

Why does one statement work and one not

I have a table in a database which I access like this:
+(NSMutableArray *) queryDatabaseWithSQL:(NSString *)sql params:(NSArray *)params {
sqlite3 *database;
NSMutableArray *rtn = [[NSMutableArray alloc] init];
int index = 0;
NSString *filepath = [self copyDatabaseToDocumentsWithName:#"database"];
if (sqlite3_open([filepath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = [sql cStringUsingEncoding:NSASCIIStringEncoding];
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
if ([params count]) {
for (int i = 0; i < [params count]; i++) {
NSString *obj = [params objectAtIndex:i];
sqlite3_bind_blob(compiledStatement, i + 1, [obj UTF8String], -1, SQLITE_TRANSIENT);
}
}
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSMutableArray *arr = [[NSMutableArray alloc] init];
index = 0;
const char *s = (char *)sqlite3_column_text(compiledStatement, index);
while (s) {
[arr addObject:[NSString stringWithUTF8String:s]];
index++;
s = (char *)sqlite3_column_text(compiledStatement, index);
}
if (![rtn containsObject:arr]) {
[rtn addObject:arr];
}
}
}
sqlite3_finalize(compiledStatement);
}
NSLog(#"ERROR: %s", sqlite3_errmsg(database));
sqlite3_close(database);
return rtn;
}
This works fine when I call the function like this:
NSLog(#"%#", [database queryDatabaseWithSQL:#"SELECT * FROM FRIENDSUSERS WHERE USER = ?" params:#[[delegate->user objectForKey:#"username"]]]);
Then when I call the function using a string like this it doesn't return any rows:
NSLog(#"%#", [database queryDatabaseWithSQL:#"SELECT * FROM FRIENDSUSERS WHERE USER = ?" params:#[#"username"]]);
I haven't got a clue what is going one with but I have checked the strings match and they do so I'm now stuck
Can anyone see any reason why this would not work
I have run error checks as well and every time it returns no error, or rows :(
Thanks in advance

Retrive Table names from sqlite database in objective-c

How can I retrieve sqlite3 table names in objective-c.For example if I created several tables, now i want to get (display) their names like .table in terminal.Thanks.
Use below code:
-(NSMutableArray *)fetchTableNames
{
sqlite3_stmt* statement;
NSString *query = #"SELECT name FROM sqlite_master WHERE type=\'table\'";
int retVal = sqlite3_prepare_v2(YOUR_DB_OBJ,
[query UTF8String],
-1,
&statement,
NULL);
NSMutableArray *selectedRecords = [NSMutableArray array];
if ( retVal == SQLITE_OK )
{
while(sqlite3_step(statement) == SQLITE_ROW )
{
NSString *value = [NSString stringWithCString:(const char *)sqlite3_column_text(statement, 0)
encoding:NSUTF8StringEncoding];
[selectedRecords addObject:value];
}
}
sqlite3_clear_bindings(statement);
sqlite3_finalize(statement);
return selectedRecords;
}
SELECT name FROM sqlite_master WHERE type='table'
SELECT * FROM sqlite_master where type='table'
try this.
- (NSArray *)listOfColumnNamesForTable:(NSString *)tableName WithDBFilePath:(NSString*)databasePath {
sqlite3 *sqlite3Database;
NSMutableArray *columnNames = [NSMutableArray array];
int openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
if(openDatabaseResult == SQLITE_OK) {
sqlite3_stmt *compiledStatement;
NSString *query = [NSString stringWithFormat:#"pragma table_info ('%#')",tableName];
int prepareStatementResult = sqlite3_prepare_v2(sqlite3Database, [query UTF8String], -1, &compiledStatement, NULL);
if(prepareStatementResult == SQLITE_OK) {
sqlite3_stmt* statement;
int retVal = sqlite3_prepare_v2(sqlite3Database,
[query UTF8String],
-1,
&statement,
NULL);
if ( retVal == SQLITE_OK )
{
while(sqlite3_step(statement) == SQLITE_ROW )
{
NSString *value = [NSString stringWithCString:(const char *)sqlite3_column_text(statement, 1)
encoding:NSUTF8StringEncoding];
[columnNames addObject:value];
}
}
sqlite3_clear_bindings(statement);
sqlite3_finalize(statement);
sqlite3_close(sqlite3Database);
return [columnNames mutableCopy];
}
}
sqlite3_close(sqlite3Database);
return nil;
}

Resources