inserting multiples values in sqlite - ios

I am working on iphone application in which i have to insert multiples values in table.
I am using the following code but getting the syntax error. Where is my syntax wrong?
INSERT INTO `ark1` (`A`, `B`, `C`) VALUES
('IKE', 'BEFÄLHAVARE OCH MILITÄRER', ' USA'),
('LEE', 'BEFÄLHAVARE OCH MILITÄRER', ' USA'),
('NEY', 'BEFÄLHAVARE OCH MILITÄRER', ' FRAN'),
('ALBA', 'BEFÄLHAVARE OCH MILITÄRER', ' SPAN'),
('FOCH', 'BEFÄLHAVARE OCH MILITÄRER', ' FRAN'),
('GIAP', 'BEFÄLHAVARE OCH MILITÄRER', ' VIET'),
('HAIG', 'BEFÄLHAVARE OCH MILITÄRER', ' USA')
Thanks

That's possible, but not with the usual comma-separated insert values.
Try this...
insert into myTable (col1,col2)
select aValue as col1,anotherValue as col2
union select moreValue,evenMoreValue
union...
Yes, it's a little ugly but easy enough to automate the generation of the statement from a set of values. Also, it appears you only need to declare the column names in the first select.

Following code is use to insert data into the Database
initialization of the database
-(id)init{
if(self=[super init]) {
documentsDirectory_Statement;
documentsDirectory=[documentsDirectory stringByAppendingPathComponent:#"yourApplication.sqlite"];
self.dbPath=documentsDirectory;
NSFileManager *fm=[NSFileManager defaultManager];
if(![fm fileExistsAtPath:self.dbPath]) {
NSString *localDB=[[NSBundle mainBundle] pathForResource:#"yourApplication" ofType:#"sqlite"];
NSError *err;
if(![fm copyItemAtPath:localDB toPath:self.dbPath error:&err]){
NSLog(#"Error in creating DB -> %#",err);
}
}
if(sqlite3_open([self.dbPath UTF8String], &database) !=SQLITE_OK){
NSLog(#"error while opening database.");
} else {
sqlite3_close(database);
}
}
return self;
}
Numbers of Constants
#define PUT_Value(_TO_,_FROM_) { \
NSString *str=[dObj valueForKey:_FROM_]; \
if(!str) str=#" "; \
sqlite3_bind_text(compiledStmt,_TO_,[str UTF8String],-1,SQLITE_TRANSIENT); \
}
#define PUT_Blob(_TO_,_FROM_) { \
sqlite3_bind_blob(compiledStmt,_TO_,[[dObj valueForKey:_FROM_] bytes],[[dObj valueForKey:_FROM_] length],NULL);\
}
#define PUT_Integer(_TO_,_FROM_) { \
NSInteger numbr=[[dObj valueForKey:_FROM_] intValue]; \
sqlite3_bind_int(compiledStmt,_TO_,numbr); \
}
#define PUT_Double(_TO_,_FROM_) { \
CGFloat doubleX=[[dObj valueForKey:_FROM_] floatValue]; \
sqlite3_bind_double(compiledStmt,_TO_,doubleX); \
}
#define PUT_Date(_TO_,_FROM_) { \
sqlite3_bind_text(compiledStmt,_TO_, [[[dObj valueForKey:_FROM_] description] UTF8String], -1, SQLITE_TRANSIENT);\
}
#define GET_Value(_TO_,_FROM_) NSString *_TO_; { \
const unsigned char *c=sqlite3_column_text(compiledStmt,_FROM_); \
_TO_= c ? [NSString stringWithUTF8String:(char*)c] : #"" ; \
}
#define GET_Double(_TO_,_FROM_) double _TO_;{ \
_TO_=sqlite3_column_double(compiledStmt,_FROM_); \
}
#define GET_Integer(_TO_,_FROM_) NSUInteger _TO_; { \
_TO_ = sqlite3_column_int(compiledStmt,_FROM_); \
}
#define GET_Date(_TO_,_FROM_) { \
_TO_=sqlite3_column_double(compiledStmt, _FROM_)];\
}
#define GET_Blob(_TO_,_FROM_) { \
_TO_=sqlite3_column_blob(compiledStmt, _FROM_) length:sqlite3_column_bytes(compiledStmt, _FROM_)];\
}
Insert Funcation
-(void)insertItem:(NSArray*)arItem{
sqlite3_stmt *compiledStmt;
if(sqlite3_open([self.dbPath UTF8String], &database) ==SQLITE_OK) {
sqlite3_prepare_v2(database, "BEGIN TRANSACTION", -1, &compiledStmt, NULL);
sqlite3_step(compiledStmt);
sqlite3_finalize(compiledStmt);
const char *sqlInsertQry="insert into alarm (id,years,months,days,hours,minutes,seconds,body) values(?,?,?,?,?,?,?,?)";
if(sqlite3_prepare_v2(database, sqlInsertQry, -1, &compiledStmt, NULL) == SQLITE_OK ){
for (NSDictionary *dObj in arItem) {
PUT_Integer(1,#"id");
PUT_Integer(2,#"years");
PUT_Integer(3,#"months");
PUT_Integer(4,#"days");
PUT_Integer(5,#"hours");
PUT_Integer(6,#"minutes");
PUT_Integer(7,#"seconds");
PUT_Value(8,#"body");
NSUInteger err = sqlite3_step(compiledStmt);
if (err != SQLITE_DONE){
NSLog(#"error while binding %d %s",err, sqlite3_errmsg(database));
}
sqlite3_reset(compiledStmt);
}
sqlite3_finalize(compiledStmt);
} else {
NSLog(#"Invalid Query");
}
sqlite3_prepare_v2(database, "END TRANSACTION", -1, &compiledStmt, NULL);
sqlite3_step(compiledStmt);
sqlite3_finalize(compiledStmt);
sqlite3_close(database);
} else {
NSLog(#"error while opening database.");
}
}
Hope this code is helping to implement the database connectivity.
#Samuel

For your above query you have to create array and insert in to sqlite.

Related

I would like to know how to test if the compiledStatement in sqlite return an answer or not, without missing the first line

I would like to test if the SQL return a result. If there is no result, I would like to send a message. The problem is that when I do that test, the first row is skipped when I want to do my process (when rows are found).
NSString *selectSQL = [NSString stringWithFormat:#"SELECT z_pk, zpostcode, zname, zfirstname, zstreetname, zstreetnumber, zcity FROM ZTAB_PARTICULIER where UPPER(ZNAME) like \'\%%%#%%\' and ZPOSTCODE like \'\%%%#%%\'", [self.name.text uppercaseString], self.postcode.text];
const char *query_stmt = [selectSQL UTF8String];
sqlite3_stmt *compiledStatement;
//Compilation de la requete et verification du succes
if (sqlite3_prepare_v2(database, query_stmt, -1, &compiledStatement, NULL) == SQLITE_OK)
{
NSLog(#"Prepare Database OK");
int stat = sqlite3_step(compiledStatement);
if (stat == SQLITE_DONE)
{
NSLog(#"NO ROWS!");
}
while (sqlite3_step(compiledStatement) == SQLITE_ROW)
{
...
Thanks in advance
Remove that first call to sqlite3_step. Just have a counter that you increment in your while loop, and after the while loop, just see if that counter was zero or not.
For example, you might do:
if (sqlite3_prepare_v2(database, query_stmt, -1, &compiledStatement, NULL) == SQLITE_OK) {
NSLog(#"Prepare Database OK");
// int stat = sqlite3_step(compiledStatement);
// if (stat == SQLITE_DONE)
// {
// NSLog(#"NO ROWS!");
// }
NSInteger rows = 0;
int rc;
while ((rc = sqlite3_step(compiledStatement)) == SQLITE_ROW) {
rows++;
...
}
if (rc != SQLITE_DONE) {
NSLog(#"Some error %s (%ld)", sqlite3_errmsg(), (long)rc);
}
if (rows == 0) {
NSLog(#"NO ROWS!");
}
...
Something like that checks for not only "no rows" situation, but also checks for errors.

sqlite3_step(statement) == SQLITE_DONE returning false all the time

Guys I have an issue with my snippet. I must also say I'm a newbie. I'm trying to insert data in to sqlite. but I keeps failing as sqlite_step == sqlite_done returns false all the time. Am I doing something wrong here. I had done something similar before and it was working fine. following is the code
sqlite3_stmt *statement;
const char *dbpath = [_databasePath UTF8String];
if(sqlite3_open(dbpath, &_db) == SQLITE_OK){
NSString *insertSQL = [NSString stringWithFormat:#"INSERT INTO userInfo (name, email, username, password) VALUES (\"%#\",\"%#\",\"%#\",\"%#\")", self.txtName.text, self.txtEmail.text, self.txtUsername.text, self.txtPassword.text];
if([self validateRegistration])
{
const char *insert_statement = [insertSQL UTF8String];
sqlite3_prepare_v2(_db, insert_statement, -1, &statement, NULL);
if(sqlite3_step(statement) == SQLITE_DONE){
[self showUIAlertWithMessage:#"User added to the database" andTitle:#"Message"];
self.txtName.text = #"";
self.txtEmail.text = #"";
self.txtUsername.text = #"";
self.txtPassword.text = #"";
self.txtConfirmPassword.text = #"";
}else{
[self showUIAlertWithMessage:#"Failed to add the user" andTitle:#"Error"];
}
sqlite3_finalize(statement);
sqlite3_close(_db);
}
}
You must check the return value of sqlite3_prepare_v2.
If either sqlite3_prepare_v2 or sqlite3_step fails, you must get the actual error message with sqlite3_errmsg.
If you check the result of sqlite3_prepare_v2, it almost certainly is not SQLITE_OK. And if you look at sqlite3_errmsg, it will tell you precisely what is wrong:
if (sqlite3_prepare_v2(_db, insert_statement, -1, &statement, NULL) != SQLITE_OK) {
NSLog(#"insert failed: %s", sqlite3_errmsg(_db));
Unrelated, but you should not use stringWithFormat to build your SQL. You should use ? placeholders in the SQL and then manually bind the values with sqlite3_bind_text() (or whatever).
const char *insert_statement = "INSERT INTO userInfo (name, email, username, password) VALUES (?, ?, ?, ?)";
if (sqlite3_prepare_v2(_db, insert_statement, -1, &statement, NULL) != SQLITE_OK) {
NSLog(#"prepare failed: %s", sqlite3_errmsg(_db));
if (sqlite3_bind_text(statement, 1, [self.txtName.text UTF8String], -1, NULL) != SQLITE_OK)
NSLog(#"bind 1 failed: %s", sqlite3_errmsg(_db));
if (sqlite3_bind_text(statement, 2, [self.txtEmail.text UTF8String], -1, NULL) != SQLITE_OK)
NSLog(#"bind 2 failed: %s", sqlite3_errmsg(_db));
if (sqlite3_bind_text(statement, 3, [self.txtUsername.text UTF8String], -1, NULL) != SQLITE_OK)
NSLog(#"bind 3 failed: %s", sqlite3_errmsg(_db));
if (sqlite3_bind_text(statement, 4, [self.txtPassword.text UTF8String], -1, NULL) != SQLITE_OK)
NSLog(#"bind 4 failed: %s", sqlite3_errmsg(_db));
if(sqlite3_step(statement) == SQLITE_DONE) {
[self showUIAlertWithMessage:#"User added to the database" andTitle:#"Message"];
self.txtName.text = #"";
self.txtEmail.text = #"";
self.txtUsername.text = #"";
self.txtPassword.text = #"";
self.txtConfirmPassword.text = #"";
}else{
NSLog(#"step failed: %s", sqlite3_errmsg(_db));
[self showUIAlertWithMessage:#"Failed to add the user" andTitle:#"Error"];
}
If you find this cumbersome, I'd suggest you consider FMDB, a SQLite wrapper, that does all of the appropriate binding of values to ? placeholders for you.
I had this issue because I haven't updated my create table statement according to my insert statements as I had made some changed some values that I am inserting.
You can use sqlite3_exec() for this:
char *err;
int code = sqlite3_exec(_db,insert_statement,NULL,NULL,&err);
if (code != SQLITE_OK) {
NSLog(#"something went wrong: %s", err);
}
You then tend to use the prepare function for reading data like this:
sqlite3_stmt *stmt;
int code = sqlite3_prepare_v2(_db,_query,-1,&stmt,NULL);
if (code == SQLITE_OK) {
while (sqlite3_step(stmt) == SQLITE_ROW) {
// Retrieve data here e.g.
// int num = sqlite3_column_int(stmt, 0);
}
}
See the documentation here for sqlite3_exec()

Error not an error sqlite database while attaching database

So here's my goal: I need to attach a sync database to my main database and update or replace any fields into my main database. So I first attach my database. I then attempt to go through all the tables. Here's the quirky part: inside of my master query string, when I say: SELECT name FROM sqlite_master the if statement does not execute and says "Error: not an error." Now, when I tell the master query to SELECT name FROM sync_db.sqlite_master, the if statement executes. However, I get an error saying that no such table: sync_db.sqlite_master exists. Could someone perhaps walk me through the proper protocol? Thanks in advance.
//Atataching the sync db to the master db
NSString *attachSQL = [NSString stringWithFormat:#"ATTACH DATABASE \'%#\' AS sync_db", dbPathSync];
NSLog(#"Here's the arratch string: %#", attachSQL);
//
if ((errorNum = sqlite3_exec(mainOpenHandle, [attachSQL UTF8String], NULL, NULL, &errorMessage)) == SQLITE_OK) {
NSString *masterQuery = [NSString stringWithFormat:#"SELECT name FROM sync_db.sqlite_master WHERE type='table';"];
const char *masterStmt = [masterQuery UTF8String];
sqlite3_stmt *statement;
//If statement does not execute and prints error saying "not an error" when
//place SELECT from "sqlite_master" inside master query.
if (sqlite3_prepare_v2(syncOpenHandle, masterStmt, -1, &statement, NULL)) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSString * currentTable = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
NSLog(#"Here's the current table: %#",currentTable);
//This is where the magic happens. If there are any keys matching the database, it will update them. If there are no current keys in the database, the query will insert them.
if ([currentTable isEqualToString:#"USER_DATA"] == NO && [currentTable isEqualToString:#"USER_ACTIVITY"]== NO && [currentTable isEqualToString:#"USER_ITINERARY"] == NO) {
NSString *tblUpdate = [NSString stringWithFormat:#"INSERT or REPLACE INTO main.%# SELECT * FROM sync_db.%#;",currentTable, currentTable];
const char *updateStmt = [tblUpdate UTF8String];
if ((errorNum = sqlite3_exec(mainOpenHandle, updateStmt, NULL, NULL, &errorMessage))!= SQLITE_OK) {
if (errorNum == 1) {
//A database reset is needded
self->isResetDataBase = YES;
}
dbErr = YES;
}
}
}
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
}
NSLog(#"Erorr syncing the database: Code: %d, message: '%s'", error,sqlite3_errmsg(mainOpenHandle));
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
sqlite3_finalize(statement);
//Detaching the database from the mainDB
NSString *detachSQL = [NSString stringWithFormat:#"DETACH DATABASE sync_db"]; // reference sync db
if ((errorNum = sqlite3_exec(mainOpenHandle, [detachSQL UTF8String], NULL, NULL, &errorMessage))!= SQLITE_OK) {
NSLog(#"Detatched syncDb Failed. ErrorMessage = %s ", errorMessage);
}
}
}
NSLog(#"Error sync ... '%s'", sqlite3_errmsg(syncOpenHandle));
//Closing the database when finished.
if (mainOpenHandle != nil) {
sqlite3_close(self.mainOpenHandle);
}
if (syncOpenHandle != nil) {
sqlite3_close(self.syncOpenHandle);
NSError *err;
int success = [fileManager fileExistsAtPath:dbPathSync];
if (success) {
[[NSFileManager defaultManager]removeItemAtPath:dbPathSync error: &error];
}
}
if (userOpenHandle != nil) {
sqlite3_close(self.userOpenHandle);
}
I then attempt to loop through all the rows. But here's the quirky part. Inside of
You should compare the result of sqlite3_prepare_v2 to SQLITE_OK.
When you simply do:
if (sqlite3_prepare_v2(syncOpenHandle, masterStmt, -1, &statement, NULL)) {
then the if statement will only succeed if there is an error. You want:
if (sqlite3_prepare_v2(syncOpenHandle, masterStmt, -1, &statement, NULL) == SQLITE_OK) {
You should also update your code to only log errors in the else block of the if statement.
if (sqlite3_prepare_v2(syncOpenHandle, masterStmt, -1, &statement, NULL) == SQLITE_OK) {
// process query
} else {
// log error here
}

about : asm (.desc xxx 0x10)

Any string written into this magic global variable ("crashreporter_info") will show up in that section of the crash log. Why?
const char *__crashreporter_info__ = NULL;
asm(".desc _crashreporter_info, 0x10");
#define MAAssert(expression, ...) \
do { \
if(!(expression)) { \
NSString *__MAAssert_temp_string = [NSString stringWithFormat: #"Assertion failure: %s in %s on line %s:%d. %#", #expression, __func__, __FILE__, __LINE__, [NSString stringWithFormat: #"" __VA_ARGS__]]; \
NSLog(#"%#", __MAAssert_temp_string); \
__crashreporter_info__ = [__MAAssert_temp_string UTF8String]; \
abort(); \
} \
} while(0)

Why do I get a SQLITE_MISUSE : Out of Memory error?

I am writing an iOS application that directly accesses SQLite. I have done this sort of thing many times on Android, so I'm struggling to see where my error lies - however my inserts are returning the SQLITE_MISUSE error (code 21), with the message "out of Memory". Below are the steps I have taken to lead me to this insert.
First, the table creation:
NSString *sql = #"CREATE TABLE IF NOT EXISTS UsersTable (lastName TEXT,id TEXT PRIMARY KEY NOT NULL,picture BLOB,firstName TEXT,age TEXT,email TEXT,sex TEXT,height TEXT,weight TEXT)";
//create the database if it does not yet exist
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: path ] == NO)
{
const char *dbpath = [path UTF8String];
//This was if (sqlite3_open(dbpath, &store) == SQLITE_OK) , but it has not made a difference.
if (sqlite3_open_v2(dbpath, &store, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) == SQLITE_OK)
{
char *errMsg = NULL;
const char *sql_stmt = [sql UTF8String];
if (sqlite3_exec(store, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(#"Failed to create table: %s", errMsg);
}
if (errMsg)
sqlite3_free(errMsg);
}
else
{
NSLog(#"Failed to open/create database");
}
}
Next, the insert (currently using the email address for the user ID):
INSERT INTO UsersTable (id,lastName,firstName,email) VALUES ("jsmith#foobar.com","Smith","John","jsmith#foobar.com")
I am using one selector for all database interactions, so the above text is passed here:
-(int)execSQL:(NSString *)statement
{
NSLog(#"%#",statement);
const char *insert_stmt = [statement UTF8String];
sqlite3_stmt *stmnt;
sqlite3_prepare_v2(store, insert_stmt, -1, &stmnt, NULL);
int result = sqlite3_step(stmnt);
sqlite3_finalize(stmnt);
if (result != SQLITE_OK)
{
NSLog(#"Error: %s", sqlite3_errmsg(store));//This prints "Error: out of memory"
}
return result;
}
What am I doing wrong?
Your open routine is only creating/opening the database if the database doesn't exist. Your database probably already exists and thus your routine isn't even opening it.
Bottom line, if you try calling SQLite functions without opening the database, you will get the SQLITE_MISUSE return code (which indicates that the SQLite functions were not called in the right order) and the sqlite3_errmsg will return the cryptic "out of memory" error.
A couple of other, unrelated observations:
You really should check the return code of sqlite3_prepare as well:
- (int)execSQL:(NSString *)statement
{
int result;
NSLog(#"%#",statement);
const char *insert_stmt = [statement UTF8String];
sqlite3_stmt *stmnt;
if ((result = sqlite3_prepare_v2(store, insert_stmt, -1, &stmnt, NULL)) != SQLITE_OK)
{
NSLog(#"%s: prepare failure '%s' (%d)", __FUNCTION__, sqlite3_errmsg(store), result);
return result;
}
if ((result = sqlite3_step(stmnt)) != SQLITE_DONE)
{
NSLog(#"%s: step failure: '%s' (%d)", __FUNCTION__, sqlite3_errmsg(store), result);
}
sqlite3_finalize(stmnt);
return result;
}
In my experience, many common development problems are related to the SQL itself, something that is identified by checking the return code of the sqlite3_prepare_v2 statement.
You really should not be building your SQL statement in a NSString. You open yourself to SQL injection attacks or, considering the more benign situation, just a SQL errors if someone's name has a quotation mark in it, e.g. The "Destroyer". You should be using ? placeholders and then use sqlite3_bind_xxx functions to bind the values. Something like:
- (int)insertIdentifier:(NSString *)identifier
lastName:(NSString *)lastName
firstName:(NSString *)firstName
email:(NSString *)email
{
int result;
const char *insert_stmt = "INSERT INTO UsersTable (id, lastName, firstName, email) VALUES (?, ?, ?, ?);";
sqlite3_stmt *stmnt;
if ((result = sqlite3_prepare_v2(store, insert_stmt, -1, &stmnt, NULL)) != SQLITE_OK)
{
NSLog(#"%s: prepare failure '%s' (%d)", __FUNCTION__, sqlite3_errmsg(store), result);
return result;
}
if ((result = sqlite3_bind_text(stmnt, 1, [identifier UTF8String], -1, NULL)) != SQLITE_OK)
{
NSLog(#"%s: bind #1 failure '%s' (%d)", __FUNCTION__, sqlite3_errmsg(store), result);
sqlite3_finalize(stmnt);
return result;
}
if ((result = sqlite3_bind_text(stmnt, 2, [lastName UTF8String], -1, NULL)) != SQLITE_OK)
{
NSLog(#"%s: bind #2 failure '%s' (%d)", __FUNCTION__, sqlite3_errmsg(store), result);
sqlite3_finalize(stmnt);
return result;
}
if ((result = sqlite3_bind_text(stmnt, 3, [firstName UTF8String], -1, NULL)) != SQLITE_OK)
{
NSLog(#"%s: bind #3 failure '%s' (%d)", __FUNCTION__, sqlite3_errmsg(store), result);
sqlite3_finalize(stmnt);
return result;
}
if ((result = sqlite3_bind_text(stmnt, 4, [email UTF8String], -1, NULL)) != SQLITE_OK)
{
NSLog(#"%s: bind #4 failure '%s' (%d)", __FUNCTION__, sqlite3_errmsg(store), result);
sqlite3_finalize(stmnt);
return result;
}
if ((result = sqlite3_step(stmnt)) != SQLITE_DONE)
{
NSLog(#"%s: step failure: '%s'", __FUNCTION__, sqlite3_errmsg(store));
}
sqlite3_finalize(stmnt);
return result;
}
You can then call this like so:
[self insertIdentifier:#"jsmith#foobar.com"
lastName:#"Smith"
firstName:#"John"
email:#"jsmith#foobar.com"];
As you can see, as you start writing code where you're appropriately checking each and every return value, binding each variable, etc., your SQLite code gets hairy awfully quickly. I'd suggest you contemplate looking at FMDB. It's a nice, thin wrapper around the SQLite functions, which greatly simplifies the exercise of writing SQLite code in Objective-C.
You're not checking the value of the sqlite3_prepare_v2 statement. If it's not SQLITE_OK then there's an issue.
Also, does the database file already exist? If not, you need to create it or load it from the bundle.

Resources