I have the below code that should populate the TableViewController with information from my sqlite file, it lets me add fine, and i can view the file and the information is there, but I'm getting the above error message, and failing miserably at fixing it....
-(NSMutableArray *) stockList
{
NSString *filePath = [self getWritableDBPath];
if(sqlite3_open([filePath UTF8String], &db) == SQLITE_OK)
{
const char *sql = "Select Description, Quantity from StockTable";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with query: %s", sqlite3_errmsg(db));
}
else
{
while (sqlite3_step(sqlStatement)==SQLITE_ROW)
{
Stock * stock = [[Stock alloc] init];
stock.desc = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 1)];
stock.qty = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 2)];
[thestock addObject:stock];
stock = nil;
}
}
sqlite3_finalize(sqlStatement);
}
sqlite3_close(db);
return thestock;
}
thanks for any help, currently googling it myself..
connection strings as mentioned below: (reason being it causes a LINK error and states that MyDB is a duplicate in both views)
TableView:
NSString * MyDB2=#"StockDatabase.db";
AddingView:
NSString * MyDB=#"StockDatabase.db";
One (or both) of the columns you are fetching from the database is NULL:
stock.desc = [NSString stringWithUTF8String:(char *)sqlite3_column_text(sqlStatement, 1)];
stock.qty = [NSString stringWithUTF8String:(char *)sqlite3_column_text(sqlStatement, 2)];
Guard against that with:
const char *desc = sqlite3_column_text(sqlStatement, 1);
if (desc)
stock.desk = #(desc);
const char *qty = sqlite3_column_text(sqlStatement, 2);
if (qty)
stock.qty = #(qty);
I got this error too. How I solved it is by setting the first column text index to "0" instead of "1". And the error went away.
char *charPrice = (char*) sqlite3_column_text(stmt, 0);
NSString *price = [NSString stringWithUTF8String:charPrice];
char *charName = (char*) sqlite3_column_text(stmt, 1);
NSString *name = [NSString stringWithUTF8String:charName];
Related
I have a project in Objective-c in which I am trying to find a way of saving the attributedText from a UITextView to a SQLite3 table.
My Project Target OS is 12.1.
I am using an object called "MMItem" with a NSData property called "notesAttributed".
In my viewController Class I am using NSKeyedArchiver to encode the AttributedText into a NSdata format then copying to the object property.
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.itemNotes.attributedText requiringSecureCoding:YES error:Nil];
self.item.notesAttributed = data;
I then call a method in my model to save the object
NSString *resultStr = [self.meetingModel saveAttributedItemNote:item];
In the model I'm attempting to save the attributed string to a field in the Item table setup as type 'blob'
- (NSString *)saveAttributedItemNote:(MMItem *)item{
NSString *errorMessage;
NSString *sql;
NSInteger result = 0;
if (item) {
//create blob encoded data for Attributed notes
NSInteger itemID = item.itemID;
sql = [NSString stringWithFormat:
#"UPDATE Item set noteAttributed = %# WHERE itemID = %ld",item.notesAttributed, (long)itemID];
char *err;
// open DB and save
if ([self openDB]){
//NSLog(#"%#", NSStringFromSelector(_cmd));
result = sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err);
sqlite3_close(db);
}
if (result != SQLITE_OK)
{
errorMessage = #"Error";
}
else
{
//NSLog(#"Table updated");
errorMessage = #"OK";
[self saveAttributedItemNote:item];
}
}
item = nil;
return errorMessage;
}
The SQL Execute statement fails with error 1.
I suspect I'm meant to insert the blob into the table using 'binding' and not an Execute statement but I just find how to put this all together using Objective-c.
Any help would be great thanks.
With acknowledgement to the following post iOS SQLite Blob data is saving NULL
I managed to get a working solution. It's apparent that to save a blob into an SQLite you must use a Prepare statement with a sqlite3_bind_blob to insert the blob parameters into the statement, then to use sqlite3_step to deploy it.
This then allows the bytes and length parameters to also be passed into the statement, which I don't think can be done using the execute method I was originally trying.
Here is the code that works perfectly.
- (NSString *)saveAttributedItemNote:(MMItem *)item{
NSString *errorMessage;
if (item) {
//create blob encoded data for Attributed notes
int itemID = (int)item.itemID;
if ([self openDB]) {
const char *insert_stmt = "UPDATE Item set notesAttributed = ? WHERE itemID = ?";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(db, insert_stmt, -1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_blob(statement, 1, item.notesAttributed.bytes, (int)item.notesAttributed.length, SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 2, itemID);
if (sqlite3_step(statement) == SQLITE_DONE) {
errorMessage = #"OK";
//update successfull
}else{
const char *err = sqlite3_errmsg(db);
NSString *error = [[NSString alloc] initWithUTF8String:err];
NSLog(#"Update error ID:%#",error);
errorMessage = #"Error";
}
sqlite3_finalize(statement);
}else{
errorMessage = #"Error";
NSLog(#"Unable to prepare stsement %s: %s",insert_stmt, sqlite3_errmsg(db));
}
sqlite3_close(db);
}
}
item = nil;
return errorMessage;
}
The following code then shows how the field was retrieved from sqlite. Column 11 is the blob.
if (sqlite3_prepare(db, [sql UTF8String], -1, &statement, nil)==SQLITE_OK)
{
//NSLog(#"SQL Select OK");
while (sqlite3_step(statement)==SQLITE_ROW) {
MMItem *item = [[MMItem alloc]init];
item.itemID = sqlite3_column_int(statement, 0);
item.topicID = sqlite3_column_int(statement, 1);
item.sequenceID = sqlite3_column_int(statement, 2);
char *description = (char *) sqlite3_column_text(statement, 3);
if(description) item.itemDescription = [[NSString alloc]initWithUTF8String:description];
char *notes = (char *) sqlite3_column_text(statement, 4);
if(notes) item.notes = [[NSString alloc]initWithUTF8String:notes];
char *actionBy = (char *) sqlite3_column_text(statement, 5);
if(actionBy) item.actionBy = [[NSString alloc]initWithUTF8String:actionBy];
char *requiredBy = (char *) sqlite3_column_text(statement, 6);
if (requiredBy) item.requiredBy = [[NSString alloc]initWithUTF8String:requiredBy];
item.completed = sqlite3_column_int(statement, 7);
char *proposedBy = (char *) sqlite3_column_text(statement, 8);
if (proposedBy) item.proposedBy = [[NSString alloc]initWithUTF8String:proposedBy];
char *secondedBy = (char *) sqlite3_column_text(statement, 9);
if (secondedBy) item.secondedBy = [[NSString alloc]initWithUTF8String:secondedBy];
item.carried = sqlite3_column_int(statement, 10);
NSData *attributedTextData = [[NSData alloc]initWithBytes:sqlite3_column_blob(statement,11) length:sqlite3_column_bytes(statement, 11)];
item.notesAttributed = attributedTextData;
[items addObject:item];
item = nil;
}
}
Then in the ViewController, the following was used to take the NSData property and decode this for the UITextView (self.itemNotes)
self.itemNotes.attributedText = [NSKeyedUnarchiver unarchivedObjectOfClass:([NSAttributedString class]) fromData:self.item.notesAttributed error:&error];
Weird how just posting the question lead me to finding the right solution. Thanks to El Tomato for your help bud.
I have an error. Problem with prepare statement: out of memory.
How to fix it?
Other queries are working normally. I do not know what can be.
Maybe this is a problem -(TelefonDetail *)telefonDetails:(int)iDMob ??
-(TelefonDetail *)telefonDetails:(int)iDMob
{
TelefonDetail *retvalTelefon = nil;
NSString *ZaprosTelefons = #"SELECT iDMob , marka, model,wifi, os, razmeri,Display,Camera,Stoimos,imageTel,opisCrat FROM MobTele WHERE iDMob=1";
sqlite3_stmt *statement1;
if (sqlite3_prepare_v2(_database, [ZaprosTelefons UTF8String], -1, &statement1, nil)
!= SQLITE_OK) {
NSLog(#"Problem with prepare statement: %s", sqlite3_errmsg(_database));
}
else{ while (sqlite3_step(statement1) == SQLITE_ROW) {
int iDMob = sqlite3_column_int(statement1, 0);
char *Marka = (char *) sqlite3_column_text(statement1, 1);
char *Model = (char *) sqlite3_column_text(statement1, 2);
char *Wifi = (char *) sqlite3_column_text(statement1, 3);
char *OS = (char *) sqlite3_column_text(statement1, 4);
char *Razmeri = (char *) sqlite3_column_text(statement1, 5);
char *Display = (char *) sqlite3_column_text(statement1, 6);
char *Camera = (char *) sqlite3_column_text(statement1, 7);
char *Stoimos = (char *) sqlite3_column_text(statement1, 8);
Byte *imgTel = (Byte *) sqlite3_column_blob(statement1, 9);
NSString *marka = [[NSString alloc] initWithUTF8String:Marka];
NSString *model = [[NSString alloc] initWithUTF8String:Model];
NSString *wifi = [[NSString alloc] initWithUTF8String:Wifi];
NSString *os = [[NSString alloc] initWithUTF8String:OS];
NSString *razmeri = [[NSString alloc] initWithUTF8String:Razmeri];
NSString *display = [[NSString alloc] initWithUTF8String:Display];
NSString *camera = [[NSString alloc] initWithUTF8String:Camera];
NSString *Stoimost = [[NSString alloc] initWithUTF8String:Stoimos];
int len = sqlite3_column_bytes(statement1, 9);
NSData *imgData = [[NSData alloc] initWithBytes:imgTel length:len];
retvalTelefon = [[TelefonDetail alloc]initWhithIDMob:iDMob marka:marka model:model wifi:wifi os:os razmeri:razmeri display:display camera:camera Stoimost:Stoimost imegeTel:imgData];
}
sqlite3_finalize(statement1);
}
return retvalTelefon;
}
The "out of memory" error is often a misleading error message caused by trying to use a database without having opened it first (or if you accidentally set the sqlite3 database pointer to NULL). For example:
sqlite3 *db = NULL;
sqlite3_stmt *statement;
int rc;
// deliberately did not open database -- ERROR
// now try to use SQLite without opening database
if ((rc = sqlite3_prepare_v2(db, "select * from test", -1, &statement, NULL)) != SQLITE_OK)
NSLog(#"rc=%d errmsg=%s", rc, sqlite3_errmsg(db));
This will generate a return code (rc) of 21, SQLITE_MISUSE. And the error message is a misleading "out of memory":
2014-05-11 17:36:22.035 MyApp[19942:60b] rc=21 errmsg=out of memory
I have these codes that retrieve value from the SQLite database and comparing it to a NSString declared in the header file.
Retrieving from database:
NSString *sql = [[NSString alloc] initWithFormat:#"SELECT TESTONE, TESTTWO, TESTTHREE, TESTFOUR FROM STUDENTS WHERE NAME='%#'",Name];
sqlite3_stmt *statement;
if(sqlite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil)== SQLITE_OK)
{
while(sqlite3_step(statement) == SQLITE_ROW){
char *one = (char *) sqlite3_column_text(statement,0);
tOne = [[NSString alloc] initWithUTF8String:one];
char *two = (char *) sqlite3_column_text(statement,1);
tTwo = [[NSString alloc] initWithUTF8String:two];
char *three = (char *) sqlite3_column_text(statement,2);
tThree = [[NSString alloc] initWithUTF8String:three];
char *four = (char *) sqlite3_column_text(statement,3);
tFour = [[NSString alloc] initWithUTF8String:four];
}
}
Comparing string:
if(tOne == #"Yes")
{
//blablabla
}
else if(tOne == #"No")
{
//blablabla
}
It doesn't seem to go into the 'IF' at all.
I have double-checked the field in the database and its TEXT datatype.
I made a UILabel to display the tOne value and it shows "Yes".
May i know what or where went wrong during the comparison?
You can't compare strings like this, you have to use isEqualToString:
if([tOne isEqualToString:#"Yes"])
{
//blablabla
}
else if([tOne isEqualToString:#"No"])
{
//blablabla
}
You are currently comparing the address of the NSString object, not its contents. Use the compare: or isEqualToString: family of methods to compare the content of the string.
Reference.
I have a database. It has two tables in it. I want to call one table in an if condition. How do I call the second table in the else part if the if conditions fail?
This is the code I used:
{
NSArray *Paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *DocumentsDirectory = [Paths objectAtIndex:0];
NSString *Path = [DocumentsDirectory stringByAppendingPathComponent:#"StoreList.sqlite"];
// Open the database from the users filessytem.
if (sqlite3_open([Path UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
//*********const char *sqlStatement = "select * from Store where Zipcode ='%#'",inputTxt ;
NSString *sqlStatement = [NSString stringWithFormat:#"select * from Store where Zipcode ='%#' or Address = '%#' or CityName = '%#'",inputTxt, inputTxt, inputTxt];
NSLog(#" Query in if :%#",sqlStatement);
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array.
if(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *latValue = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSLog(#"Latitude:%#",latValue);
NSString *longValue = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSLog(#"Longitude:%#",longValue);
//currentLocationLbl.text=[NSString stringWithFormat:#" %# , %#" ,latValue,longValue];
// delegate.latitudeVal=latValue;
// delegate.longitudeVal=longValue;
txtChangeLocation.text = #"";
isFromChangeLoc=TRUE;
//self.tabBarController.selectedIndex=3;
}
else {
NSLog(#"ELSE PART");
// Open the database from the user's filessytem.
if (sqlite3_open([Path UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
//*********const char *sqlStatement = "select * from Store where Zipcode ='%#'",inputTxt ;
NSString *sqlStatement = [NSString stringWithFormat:#"select * from zipcodes where zip ='35004'"];
NSLog(#" Query in if :%#",sqlStatement);
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
if(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *latValue = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSLog(#"Latitude:%#",latValue);
NSString *longValue = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSLog(#"Longitude:%#",longValue);
//currentLocationLbl.text=[NSString stringWithFormat:#" %# , %#" ,latValue,longValue];
// delegate.latitudeVal=latValue;
// delegate.longitudeVal=longValue;
txtChangeLocation.text = #"";
isFromChangeLoc=TRUE;
}
}
}
}
sqlite3_finalize(compiledStatement);
sqlite3_close(database);
}
}
I'm getting the input from the text box. When I give the correct value, which is there in the database, it is working fine, the fetch of the data is correct. If I give the wrong data in the textbox it's not working fine - the else condition fails.
How can this issue be fixed?
When going on else you open the same database again, that's not needed (and might cause some problems as well, haven't tried it). Use a BOOL when running the first (select) statement and set it to YES or NO if it fails or not. After you finish with the first statement check the BOOL value and if ==NO run the second statement.
...
BOOL success = NO;
NSString *sqlStatement = [NSString stringWithFormat:#"select * from Store where Zipcode '%#' or Address = '%#' or CityName = '%#'",inputTxt, inputTxt, inputTxt];
NSLog(#" Query in if :%#",sqlStatement);
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK){
if(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *latValue = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSLog(#"Latitude:%#",latValue);
NSString *longValue = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSLog(#"Longitude:%#",longValue);
//currentLocationLbl.text=[NSString stringWithFormat:#" %# , %#" ,latValue,longValue];
// delegate.latitudeVal=latValue;
// delegate.longitudeVal=longValue;
txtChangeLocation.text = #"";
isFromChangeLoc=TRUE;
//self.tabBarController.selectedIndex=3;
success=YES;
}
}
sqlite3_finalize(compiledStatement);
if(success){
//do the else from your code
NSString *sqlStatement = [NSString stringWithFormat:#"select * from zipcodes where zip ='35004'"];
NSLog(#" Query in if :%#",sqlStatement);
if(sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK){
// Loop through the results and add them to the feeds array
if(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *latValue = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSLog(#"Latitude:%#",latValue);
NSString *longValue = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSLog(#"Longitude:%#",longValue);
//currentLocationLbl.text=[NSString stringWithFormat:#" %# , %#" ,latValue,longValue];
// delegate.latitudeVal=latValue;
// delegate.longitudeVal=longValue;
txtChangeLocation.text = #"";
isFromChangeLoc=TRUE;
}
}
sqlite3_finalize(compiledStatement);
}
I haven't run it, so it might contain some bugs.
In my app I am executing a query to get the count of images which are having same category and that category is passed by me as the parameter. Now when the query is executed I want to get two results either 1 or more than one. For that purpose I think I need to convert the string to integer. When I check the value of the String it is showing me 1 but when that value is returned to the method it is showing something like this:695842 and something else also. What could be the reason? Please help. I am posting the part of code:-
-(NSInteger)searchImagesInSameCategory:(NSString *)categoryName
{
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory= [paths objectAtIndex:0];
NSString *path=[documentsDirectory stringByAppendingPathComponent:#"SymbolTalkLanguageElement.sqlite"];
//Open the database
//might have to make database as property
if(sqlite3_open([path UTF8String], &dataBase) ==SQLITE_OK)
{
sqlite3_stmt *statement;
NSString *strSQL = [[NSString alloc]init];
strSQL = #"select Count(ImageName) from tblLanguageElement where Category='";
strSQL = [[strSQL stringByAppendingString:categoryName] stringByAppendingString:#"'"];
const char *bar = [strSQL UTF8String];
if(sqlite3_prepare(dataBase, bar, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"%#",[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)]);
int k;
//NSString *string=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
//NSLog(string);
k=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
//NSLog([NSString stringWithFormat:#"Count for k:-%d",k]);
//[list addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)]];
//return [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
return k;
}
}
}
return 1;
}
You should use intValue method to convert a NSString to int.
NSString *integerStr = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
k = [integerStr intValue];