Hi can anyone point out what I'm doing wrong please? The error is this:
SQL error 'out of memory' (7)
- (NSArray *)RecipeInfo
{
NSMutableArray *retval = [[NSMutableArray alloc] init];
NSString *query = [NSString stringWithFormat:#"SELECT key, name FROM recipes WHERE type = \'%#\'", self.RecipeType];
NSLog(query);
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, NULL) != SQLITE_OK)
{
NSLog(#"[SQLITE] Error when preparing query!");
NSLog(#"%s SQL error '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(_database), sqlite3_errcode(_database));
}
else
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
int uniqueId = sqlite3_column_int(statement, 0);
char *nameChars = (char *) sqlite3_column_text(statement, 1);
NSString *name = [[NSString alloc] initWithUTF8String:nameChars];
RecipeInfo *info = [[RecipeInfo alloc] initWithUniqueId:uniqueId name:name];
[retval addObject:info];
}
sqlite3_finalize(statement);
}
return retval;
}
The sql executes fine in the database management environment I use, it has to be something to do with the way I'm using the sql api, can anyone spot whats wrong?
You can get that error, confusingly, if you neglected to open the database and the pointer is NULL (or, as rmaddy says, if it's NULL for any reason). Put a log statement where you open the database and make sure that it was successful and that you have a valid sqlite3 pointer.
Related
I am trying to read data from sql database in obj c. I have a problem because all time I receive
Prepare-error #26: file is encrypted or is not a database.
I tried everything what I found on the internet (I am looking for solutions lots of hours).
My code:
sqlite3 *database;
products = [[NSMutableArray alloc]init];
if (sqlite3_open([databasePath UTF8String],&database)==SQLITE_OK) {
NSString* sqlStatement = #"select * from products";
const char *sql = [sqlStatement UTF8String];
static sqlite3_stmt *compiledStatement;
int result = sqlite3_prepare_v2(database, sql, -1, &compiledStatement, NULL);
if(result != SQLITE_OK) {
NSLog(#"Prepare-error #%i: %s", result, sqlite3_errmsg(database));
}
if(sqlite3_prepare_v2(database, sql, -1, &compiledStatement, NULL) == SQLITE_OK) {
while (sqlite3_step(compiledStatement)==SQLITE_ROW) {
int aId = sqlite3_column_int(compiledStatement, 1);
NSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aDescriptions = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
double aDo = sqlite3_column_double(compiledStatement, 4);
Product *product = [[Product alloc]initWithUniqueId:aId name:aName descriptions:aDescriptions do:aDo];
[products addObject:product];
NSLog(#"%#",products);
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
I have almost identical code, and I see nothing wrong with your code. Error 26 is (according to sqlite3.h) "File opened that is not a database file".
I tried my code with a path to a text file, and got result=1 from sqlite3_prepare_v2() -- so sqlite3_open() passed without failure. I suspect your file is not an sqLite file, or perhaps is corrupt.
Try to verify the database file integrity by opening it with an sqLite editor application. Also logging the path to verify it wouldn't hurt. If there are spaces in the path they might need to be escaped -- or not, I can't recall.
Hope this helps.
I try to retrieve data from sqlite. Unfortunately the table is filled with null values.
The console shows FIRST ID RECUPERÉ : (null). Can you give me your opinions please?
This is the code:
NSString * statementID = [NSString stringWithFormat:#"SELECT id_message FROM messages;"];
const char * sql_stmt_id = [statementID UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(contactDB, sql_stmt_id, -1, &compiledStatement, NULL) == SQLITE_OK)
{
[tableauMsgReceived removeAllObjects];
while(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
[tableauMsgReceived addObject:[NSString stringWithFormat:#"%s",(char *) sqlite3_column_text(compiledStatement, 0)]];
NSLog(#"First ID : %#", [tableauMsgReceived objectAtIndex:0]);
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(contactDB);
The only way that the NSLog statement will give that result given your code is if tableauMsgReceived is nil.
Somewhere you need to do:
tableauMsgReceived = [[NSMutableArray alloc] init];
First of all, make sure you have done something like
tableauMsgReceived = [[NSMutableArray alloc] init];
Then, check whether database opened successfully
if (sqlite3_open([YourDBPath UTF8String], &yourDatabase) == SQLITE_OK){}
Last thing, maybe you can try
[tableauMsgReceived addObject:[NSString stringWithUTF8String:(const char *)sqlite3_column_text(statement, 0)]];
I'm trying to get data from my DB but I have some problem.
Here is my code:
NSString *action=[[NSString alloc]init];
NSString *queryStatement = [NSString stringWithFormat:#"SELECT ACTIONNAME FROM ACTIONS WHERE ACTIONSYMBOL = '%#'", symbol];
// Prepare the query for execution
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [queryStatement UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
// Create a new address from the found row
while (sqlite3_step(statement) == SQLITE_ROW) {
action = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)]; // fails on this line
}
sqlite3_finalize(statement);
return action;
}
(the parameter symbol come from outside)
When I run this, it fails at the line with the call to stringWithUTF8String with sqlite3_column_text results.
You probably want to collect the results in an NSMutableArray:
NSMutableArray *action = [[NSMutableArray alloc] init];
...
while (sqlite3_step(statement) == SQLITE_ROW) {
[action addObject:[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)]];
}
...
You can then see what was collected later:
for (NSString *s in action) {
NSLog(#"%#", s);
}
EDIT As pointed out in #Rob's answer, the first column is 0, not 1.
In your call to sqlite3_column_text, you're using the index 1, but it takes a zero-based index. Use 0 instead of 1. See the SQLite sqlite_column_XXX documentation, which says:
The leftmost column of the result set has the index 0.
By the way, since stringWithUTF8String throws an exception if you pass it a NULL value, it's often safer to check the result if sqlite3_column_text is not NULL before proceeding, and handle the error gracefully otherwise. Also, you might want to check for sqlite3_step and sqlite3_prepare_v2 errors, like so:
NSString *queryStatement = [NSString stringWithFormat:#"SELECT ACTIONNAME FROM ACTIONS WHERE ACTIONSYMBOL = '%#'", symbol]; // note, it can be dangerous to use `stringWithFormat` to build SQL; better to use `?` placeholders in your SQL and then use `sqlite3_bind_text` to bind the `symbol` value with the `?` placeholder
if (sqlite3_prepare_v2(database, [queryStatement UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
int rc;
while ((rc = sqlite3_step(statement)) == SQLITE_ROW) {
const unsigned char *value = sqlite3_column_text(statement, 0); // use zero
if (value) {
NSString *action = [NSString stringWithUTF8String:(const char *)value];
// now do whatever you want with `action`, e.g. add it to an array or what
} else {
// handle the error (or NULL value) gracefully here
}
// make sure to check for errors in `sqlite3_step`
if (rc != SQLITE_DONE)
{
NSLog(#"%s: sqlite3_step failed: %s", __FUNCTION__, sqlite3_errmsg(database));
}
}
}
else
{
NSLog(#"%s: sqlite3_prepare_v2 failed: %s", __FUNCTION__, sqlite3_errmsg(database));
}
Incidentally, as the above illustrates, to correctly perform all of the error checking is a little cumbersome. This is where FMDB can be useful, simplifying the above to (where db is an FMDatabase object that has been opened):
FMResultSet *rs = [db executeQuery:#"SELECT ACTIONNAME FROM ACTIONS WHERE ACTIONSYMBOL = ?", symbol];
if (!rs) {
NSLog(#"%s: executeQuery failed: %#", __FUNCTION__, [db lastErrorMessage]);
return;
}
while ([rs next]) {
NSString *action = [rs stringForColumnIndex:0];
// do whatever you want with `action` here
}
[rs close];
And if you use ? placeholders (rather than using stringWithFormat to build your SQL, which is dangerous) the benefits of using FMDB are even more compelling.
I have a DBManager wich is fetching data from database (sqlite file). All other queries are fine, but this one seems to be somehow not working
-(NSArray *)readCountries{
NSLog(#"[DBManager] readCountries");
NSMutableArray *countriesArray = [[NSMutableArray alloc] init];
//open db from users filesystem
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
const char* sql = "SELECT DISTINCT country FROM aed ORDER BY rowid";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
//loop through results
while (sqlite3_step(statement) == SQLITE_ROW) {
//read data from record
NSString *_country;
char* tmpCountry = (char*)sqlite3_column_text(statement, 1);
NSLog(#"tmpCountry = %#", [NSString stringWithUTF8String:tmpCountry]);
if (tmpCountry != NULL) {
_country = [NSString stringWithUTF8String:tmpCountry];
}else{
_country = #"n/a";
}
NSLog(#"country = %#", _country);
[countriesArray addObject:_country];
}
}
//finalize statement
sqlite3_finalize(statement);
}
//close database
sqlite3_close(database);
NSLog(#"[DBManager] countriesArray has %d objects", [countriesArray count]);
return (NSArray*)countriesArray;
}
All I get from logs, that my array has 5 objects, which is fine - but it souldn't be only "n/a"... any idea? Other queries are good, they mostly use sqlite3_column_text so I don't get it, why it's not working here - maybe a fresh eye will help.
This is a confusing inconsistency with the sqlite C-api. When using the sqlite3_column_xxx functions, the column index is 0-based. But with the sqlite3_bind_xxx functions, the column index is 1-based.
Change this:
char* tmpCountry = (char*)sqlite3_column_text(statement, 1);
to:
char* tmpCountry = (char*)sqlite3_column_text(statement, 0);
BTW - you should add else statements to your sqlite3_open and sqlite3_prepare calls. If they fail you can log the error using the sqlite3_errmsg function.
I have tried following the guide on this page SQLite Tutorial? Deleting Data | iPhone SDK Articles but I just can't understand how to implement it in my app, because I the NSMutableArray isn't declared in the AppDelegate as it is in the tutorial
Can someone have a look and guide me through it? I want to be able to delete rows from the tableview and the database and to be able to add data as well.
Here is my app: http://ge.tt/9JNVd89?c
Even the slightest tip will be appreciated.
Will probably need a bit more information as to your current level of knowledge. How far have you gotten? Are you able to connect and read data from it? Do you understand how SQL works?
If you wanted to retrieve data from the db you could write something like the following:
+ (NSArray *)getAllUsers
{
sqlite3 *db = **However you get your db conn**
sqlite3_stmt *statement = nil;
NSMutableArray *userArray = [NSMutableArray array];
NSString *fullQuery = #"SELECT * FROM User";
const char *sql = [fullQuery UTF8String];
if(sqlite3_prepare_v2(db, sql, -1, &statement, NULL)!=SQLITE_OK)
NSAssert1(0, #"Error preparing statement '%s'", sqlite3_errmsg(db));
else
{
while(sqlite3_step(statement) == SQLITE_ROW)
{
User *currentUser = [[User alloc] init];
[User setPk:[NSString stringWithUTF8String:(const char*)sqlite3_column_text(statement, 0)]];
[User setName:[NSString stringWithUTF8String:(const char*)sqlite3_column_text(statement, 1)]];
[User setAge:[NSString stringWithUTF8String:(const char*)sqlite3_column_text(statement, 2)]];
[userArray currentUser];
[currentUser release];
}
}
sqlite3_finalize(statement);
sqlite3_close(db);
return [NSArray arrayWithArray:userArray];
}
and if you wanted to insert data into it:
+ (void)insertUser:(NSString *)username
{
sqlite3 *db = **However you get your db conn**
sqlite3_stmt *statement = nil;
NSString *fullQuery = [NSString stringWithFormat:#"INSERT INTO User (userName) VALUES (%#);", username];
const char *sql = [fullQuery UTF8String];
sqlite3_prepare_v2(db, sql2, -1, &statement, NULL);
if(sqlite3_step(statement) == SQLITE_DONE)
{
NSLog(#"User inserted");
}
sqlite3_finalise(statement);
sqlite3_close(db);
}
If you are having trouble getting a database into your application and connecting to it, let me know and I can post some of that code as well.
Hope that helps :)