I would like to know how could I identify if there is no element affected by an SQL statement (specifically a Delete). I have the next function associated to a button that erases the content of an UITableView, the parameter i give to it (nombre) it`s a UITextField.text element. Any further information would be given
#import "SD9ProxyBD.h"
#include <sqlite3.h>
#implementation SD9ProxyBD
-(NSMutableArray *)nombres{
sqlite3 *laBd;
sqlite3_stmt *consultaPreparada;
const char *consulta="Select nombre from informacion";
NSString *ruta=[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:#"mibd"];
sqlite3_open([ruta UTF8String], &laBd);
sqlite3_prepare(laBd,consulta,-1,&consultaPreparada,NULL);
NSMutableArray *resultados=[[NSMutableArray alloc]init];
while (sqlite3_step(consultaPreparada)==SQLITE_ROW) {
[resultados addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(consultaPreparada,0)]];
}
sqlite3_close(laBd);
return resultados;
}
-(void)insertarNombre:(NSString *)nombre{
sqlite3 *laBd;
sqlite3_stmt *consultaPreparada;
const char *consulta="Insert into informacion(nombre) values(?)";
NSString *ruta=[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:#"mibd"];
sqlite3_open([ruta UTF8String], &laBd);
sqlite3_prepare(laBd,consulta,-1,&consultaPreparada,NULL);
sqlite3_bind_text(consultaPreparada,1,[nombre UTF8String],-1,SQLITE_TRANSIENT);
sqlite3_step(consultaPreparada);
sqlite3_finalize(consultaPreparada);
sqlite3_close(laBd);
}
-(void)eliminarNombre:(NSString *)nombre{
sqlite3 *laBd;
sqlite3_stmt *consultaPreparada;
const char *consulta="Delete from informacion where nombre=?";
NSString *ruta=[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:#"mibd"];
sqlite3_open([ruta UTF8String], &laBd);
sqlite3_prepare(laBd,consulta,-1,&consultaPreparada,NULL);
sqlite3_bind_text(consultaPreparada,1,[nombre UTF8String],-1,SQLITE_TRANSIENT);
sqlite3_step(consultaPreparada);
sqlite3_finalize(consultaPreparada);
sqlite3_close(laBd);
}
#end
And here is the code of the button:
- (IBAction)eliminar:(id)sender {
[self.texto resignFirstResponder];
[self.proxyBD eliminarNombre:self.texto.text];
[self.tabla reloadData];
}
Related
I have create sqlite db Table as below
NSString * sqlStmt =#"CREATE TABLE IF NOT EXISTS SONGS (ID INTEGER PRIMARY KEY AUTOINCREMENT, SONGNAME TEXT UNIQUE NOT NULL,ALBUMNAME TEXT ,ARTIST TEXT ,SIZE FLOAT ,IMAGE BLOB)";
when i am trying to get data from this table getting nothing
NSString *sqlQuery = [NSString stringWithFormat:
#"SELECT ARTIST ,IMAGE FROM SONGS WHERE SONGNAME=kannulada"];
but iam getting data when iam trying to get data by id.
NSString *sqlQuery = [NSString stringWithFormat:
#"SELECT ARTIST ,IMAGE FROM SONGS WHERE id=1"];
when i debugging it not excuting prepare loop
-(NSMutableArray*)retrieveDataArrayWHICHISequql
{
[dataArray removeAllObjects];
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &_SQliteDB) == SQLITE_OK)
{
const char * selectQuery =[sqlQuery UTF8String];
if (sqlite3_prepare_v2(_SQliteDB, selectQuery, -1, &statement, NULL)== SQLITE_OK)
{
while (sqlite3_step(statement)== SQLITE_ROW)
{
NSString * addressStr = [[NSString alloc]initWithUTF8String:(const char*)sqlite3_column_text(statement, 0)];
NSString * phNumStr = [[NSString alloc]initWithUTF8String:(const char*)sqlite3_column_text(statement, 1)];
// NSString * nameStr = [[NSString alloc]initWithUTF8String:(const char*)sqlite3_column_text(statement, 2)];
NSMutableDictionary * dataDict = [[NSMutableDictionary alloc]init];
[dataDict setObject:addressStr forKey:#"getaddress"];
[dataDict setObject:phNumStr forKey:#"getphone"];
// [dataDict setObject:nameStr forKey:#"getname"];
[dataArray addObject:dataDict];
}
sqlite3_finalize(statement);
sqlite3_close(_SQliteDB);
}
}
return dataArray;
NSString *sqlQuery = [NSString
stringWithFormat:
#"SELECT ARTIST ,IMAGE FROM SONGS WHERE SONGNAME='kannulada'"]
;
kannulada is string , so you must use single quote
The problem is that if you have an error in sqlite3_prepare_v2 (it didn't return SQLITE_OK). So, if that happens, you should look at what sqlite3_errmsg returned, and it will tell you precisely why it failed. If you don't look at the meaningful error message that SQLite returns, you're flying blind.
if (sqlite3_prepare_v2(_SQliteDB, selectQuery, -1, &statement, NULL)== SQLITE_OK)
{
...
} else {
NSLog(#"SQL Error: %s", sqlite3_errmsg(_SQliteDB));
}
Regarding why it's failing, it's because you have to either quote the string literal, 'kannulada', or, better, use a SQL placeholder, ?, and then use sqlite3_bind_text.
I have a sqlite in my app , and everything seem to be ok , but i database method the while loop is not executed , and i can't get the result from query. Could somenone help me? Any help will be apreciate !
I also create a copy for databse, as i saw in other answer for other questions .
- (void)viewDidLoad {
[super viewDidLoad];
int sqlite3_open(const char *filename, sqlite3 **database);
sqlite3 *contactDB; //Declare a pointer to sqlite database structure
NSString *path = [[NSBundle mainBundle] pathForResource:#"verbeGeo" ofType:#"sqlite"];
if (sqlite3_open([path UTF8String], &contactDB) == SQLITE_OK)
{
NSLog(#"DB is open");
} else {
NSLog(#"DB can be open");
}
NSString *querySQL = #"select id from conjugare where rowid=1";
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(contactDB, query_stmt, -1,
&statement, NULL) == SQLITE_OK)
{
NSLog(#"Statement prepared successfully");
} else {
NSLog(#"Statement preparation failed");
NSLog(#"Error while creating update statement. '%s'", sqlite3_errmsg(contactDB));
NSLog(#"%s Prepare failure '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(contactDB), sqlite3_errcode(contactDB));
}
sqlite3_step(statement);
sqlite3_finalize(statement);
[self database];
}
-(void)database{
sqlite3 *contactDB;
NSString *querySQL = #"select id from conjugare where rowid=1";
const char *query_stmt = [querySQL UTF8String];
sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL);
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *idNumber =
[[NSString alloc] initWithUTF8String:
(const char *) sqlite3_column_text(statement, 0)];
}
sqlite3_finalize(statement);
}
Your sqlite3_open statement is initializing the contactDB variable defined in viewDidLoad. The contactDB variable defined in database is local to that method and not initialized.
1) Either make contactDB an instance variable or pass it to database.
2) Check error returns for all calls (e.g. sqlite3_prepare_v2 in the database method).
I am creating Address book. its save group name in sqlite. but its not working. its not entering in loop.? please check my code. what is the problem in my code?
-(void) selectGroup
{
ssArray = [[NSMutableArray alloc]init];
NSString *selectStmt=[NSString stringWithFormat:#"select GroupName from AddGroup;"];
NSLog(#"the selet statement is :%#",selectStmt);
const char *cSelectStmt=[selectStmt UTF8String];
sqlite3_prepare_v2(database, cSelectStmt, -1, &statement, NULL);
while (sqlite3_step(statement)==SQLITE_ROW) {
const unsigned char *cName = sqlite3_column_text(statement, 0);
NSString *name=[NSString stringWithUTF8String:(const char *)cName];
[self.ssArray addObject:name];
}
sqlite3_finalize(statement);
NSLog(#"Array from database is :%#",ssArray);
}
I have a problem that is haunting me a few days. All I want to do is add a command inside the method 'ViewDidLoad' which will make entering data into sqlite, which would make it simple do not need other fields and buttons, so, on the simulation runs, the new record will be inserted automatically in sqlite, so I try this:
In SQLite Manager Database (Plugin in firefox), I create a New Database who name is 'registros', and the program save it 'registros.sqlite'
I create this table:
CREATE TABLE "main"."campos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE , "campo1" VARCHAR, "campo2" VARCHAR, "campo3" VARCHAR)
In my project file, all I did was, create a file who name is 'MYFristViewController' with xib file, In the 'build Phases' I add the 'libsqlite3.dylib'. In the MyFristViewController.m I add this code:
#import "MyFristViewController.h"
#import <sqlite3.h>
#implementation MyFristViewController
- (void)viewDidLoad{
[super viewDidLoad];
sqlite3 *db;
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"registros.sqlite"];
sqlite3_open([dbPath UTF8String], &db);
char *sql = "INSERT INTO campos (campo1,campo2,campo3) VALUES (?,?,?)";
sqlite3_stmt *stmt;
int resultado2 = sqlite3_prepare_v2(db, sql, -1, &stmt, nil);
sqlite3_bind_text(stmt, 1, [#"Campo_01" UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, [#"Campo_02" UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, [#"Campo_03" UTF8String], -1, SQLITE_TRANSIENT);
resultado2 = sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
#end
As a beginner I'm not sure what else to do, I even tried modifying the fifth parameter of the command 'sqlite3_bind_text' to SQLITE_STATIC or SQLITE_TRANSIENT, but it seems that the values were not added to the database, could someone help me?
to create a new register in database, in .h file (Inherited NSObject), do you need import sqlite3.h, get the path of database:
#interface RegistroCrud : NSObject{
sqlite3 *bd;
}
-(NSString *) getPathBD;
-(void)newRegister:(NSString *)campo1 campo2:(NSString *)campo2 campo3:(NSString *)campo3;
getPathDB method is to get the database if does exits, or create it if does not exits
in .m file:
-(NSString *)getPathBD
{
NSString *dirDocs;
NSArray *rutas;
NSString *rutaBD;
rutas = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
dirDocs = [rutas objectAtIndex:0];
NSFileManager *fileMgr = [NSFileManager defaultManager];
rutaBD = [[NSString alloc] initWithString:[dirDocs
stringByAppendingPathComponent:#"registros.sqlite"]];
if([fileMgr fileExistsAtPath:rutaBD] == NO){
[fileMgr copyItemAtPath:[[[NSBundle mainBundle]resourcePath]stringByAppendingPathComponent:#"registros.sqlite"] toPath:rutaBD error:NULL
];
}
return rutaBD;
}
-(void)newRegister:(NSString *)campo1 campo2:(NSString *)campo2 campo3:(NSString *)campo3
{
NSString *pathDB = [self getPathBD];
if(!(sqlite3_open([pathDB UTF8String], &bd) == SQLITE_OK)){
NSLog(#"No se puede conectar con la BD");
return;
} else {
NSString *sqlInsert = [NSString stringWithFormat:#"INSERT OR IGNORE INTO campos (campo1,campo2,campo3) VALUES (%#,%#,'%#')",campo1,campo2,campo3];
const char *sql = [sqlInsert UTF8String];
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare_v2(bd, sql, -1, &sqlStatement, NULL) != SQLITE_OK){
NSLog(#"Problema al preparar el statement");
return;
} else {
if(sqlite3_step(sqlStatement) == SQLITE_DONE){
sqlite3_finalize(sqlStatement);
sqlite3_close(bd);
}
}
}
}
Do you need have the registros.sqlite in the project
there is a tutorial in spanish: http://www.imaginaformacion.com/tutoriales/crear-una-aplicacion-con-sql-lite-en-ios-5-parte-i/ to make crud in database in ios with sqlite, ;)
I tried many things but did not get any results, here I leave with you the files of my project:
www.fazerbem.com.br/TesteUltimoSql.zip
i have a view Controller called as VegQuantity which does totalcost=(quantity*cost of the dish) and inserts the itemname,quantity,totalcost into a table called as FINALORDER with database name FinalOrder
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &FinalOrder) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: #"INSERT INTO FINALORDER (itemname, quantity, totalcost) VALUES (\"%#\", \"%#\", \"%#\")", itemName.text, input.text, output.text];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(FinalOrder, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
// status.text = #"Contact added";
// name.text = #"";
// address.text = #"";
// phone.text = #"";
NSLog(#"added");
} else {
NSLog(#"Couldnt add");
}
sqlite3_finalize(statement);
sqlite3_close(FinalOrder);
}
Final View Controller viewdidload method
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &FinalOrder) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat: #"SELECT * FROM FINALORDER"];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(FinalOrder, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *itemname = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
item.text = itemname;
NSString *qua = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)];
quantity.text = qua;
NSString *total = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 2)];
totalcost.text=total;
}
sqlite3_finalize(statement);
}
sqlite3_close(FinalOrder);
}
But i keep getting this error called expected expression before FinalOrder,and is it correct for me to write this code inside viewdidload? i dont have any button in Final view controller i have a button called order in a view controller called as Restaurant which actually shows me Final view controller..am i supposed to search for the db file again in the Final viewcontroller and i am sorry question seems kind of vague but in brief i just want to know how to retrieve and display the data which i have inserted in VegQuantity view controller into the final view controller thanks
I believe that the problem must rest in the definition of FinalOrder which, on the basis of the error message, looks like has been defined as a class, not as a sqlite3 * variable. Given that the scope of your usage of the database is limited to these two methods, I'd suggest defining a sqlite3 * within that scope, and use that, such as:
- (void)saveRecord
{
sqlite3 *database;
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
[self purgeTable:database];
NSString *insertSQL = #"INSERT INTO FINALORDER (itemname, quantity, totalcost) VALUES (?, ?, ?)";
if (sqlite3_prepare_v2(database, [insertSQL UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
sqlite3_bind_text(statement, 1, [itemName.text UTF8String], -1, NULL);
sqlite3_bind_int(statement, 2, [input.text intValue]);
sqlite3_bind_double(statement, 3, [output.text doubleValue]);
if (sqlite3_step(statement) == SQLITE_DONE)
{
// status.text = #"Contact added";
// name.text = #"";
// address.text = #"";
// phone.text = #"";
NSLog(#"added");
} else {
NSLog(#"%s Couldn't add; errmsg='%s'", __FUNCTION__, sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
} else {
NSLog(#"%s Couldn't prepare; errmsg='%s'", __FUNCTION__, sqlite3_errmsg(database));
}
sqlite3_close(database);
}
}
Note, in addition to using a sqlite3 * variable for the database, to make this a little more robust:
I have replaced the stringWithFormat statement that built the SQL insert statement with an INSERT statement that uses the ? placeholders and then use sqlite3_bind_text to bind values to that statement. This way, if someone entered a value that included a quotation mark, the insert statement will still work (your original implementation would have crashed and/or was susceptible to a SQL injection attack).
I have also added the sqlite3_errmsg statements so if something goes wrong, I know what the problem was.
Rather than treating these three fields as text fields, I'm assuming your table is defined as CREATE TABLE IF NOT EXISTS FINALORDER (itemname TEXT, quantity INT, totalcost REAL); and therefore use text, int, and double bind statements.
This, incidentally, invokes a purgeTable method, so if you run it twice, it will remove the old record in there:
- (void)purgeTable:(sqlite3 *)database
{
if (sqlite3_exec(database, "DELETE FROM FINALORDER;", NULL, NULL, NULL) != SQLITE_OK)
NSLog(#"%s Couldn't purge table %s", __FUNCTION__, sqlite3_errmsg(database));
}
Anyway, you can then read this data via:
- (void)loadRecord
{
sqlite3 *database;
const char *dbpath = [databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *querySQL = #"SELECT * FROM FINALORDER";
if (sqlite3_prepare_v2(database, [querySQL UTF8String], -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *itemname = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)];
item.text = itemname;
//[itemname release]; // if not ARC, uncomment this line
int qua = sqlite3_column_int(statement, 1);
quantity.text = [NSString stringWithFormat:#"%1d", qua];
double total = sqlite3_column_double(statement, 2);
totalcost.text = [NSString stringWithFormat:#"%1.2f", total];
}
sqlite3_finalize(statement);
} else {
NSLog(#"%s Couldn't prepare; errmsg='%s'", __FUNCTION__, sqlite3_errmsg(database));
}
sqlite3_close(database);
}
}
Note,
I've added a sqlite3_errmsg log statement if the sqlite3_prepare fails, and I've retired the stringWithFormat (because you weren't formatting anything).
Given that quantity was INT and total was REAL, I'm retrieving the values using the appropriate variation of sqlite3_column_text, sqlite3_column_int, or sqlite3_column_double, as appropriate.
I infer that you're not using ARC and therefore, the [NSString alloc] must have an associated release or autorelease.
Finally, in our chat, you said that you received an error message (presumably an "Undefined Symbols" message) that said:
OBJC_CLASS_$"_FinalOrder"
This means that you are trying to use an object class of FinalOrder, but you haven't defined that class anywhere. Take a look at which .o files it's reporting this error for and look at the corresponding .m file, and look for your use of the FinalOrder class there. You clearly have a FinalOrder class interface defined somewhere, but never defined the class implementation, or, if you have one, for some reason it's not included in your target's "Compile Sources" listing, so double check it's here:
Finally, by the way, make sure your database is in the Documents folder, not trying to open a copy of the database in your project's bundle (because that's read only). If you have a copy of the database in your bundle, just check to see if you already have it in you Documents folder, and if not, copy it from the bundle to the Documents folder.