I am new to iphone development,i was trying to insert the data in a sqlite table .but data is not inserted in the table.there was no error on the console.
NSString *string1=#"Test";
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"TestData" ofType:#"sqlite"];
if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK)
{
sqlite3_stmt *compiledStatement=nil;
char * sql = "insert into Test (title,summary,question,choice,answer) values (?,?,?,?,?)";
if (sqlite3_prepare_v2(database, sql, -1, &compiledStatement, NULL) == SQLITE_OK)
{
{
sqlite3_bind_text(compiledStatement, 1, [string1 UTF8String], -1,SQLITE_TRANSIENT);
sqlite3_bind_text(compiledStatement, 2,[string1 UTF8String] , -1,SQLITE_TRANSIENT);
sqlite3_bind_text(compiledStatement, 3, [string1 UTF8String], -1,SQLITE_TRANSIENT);
sqlite3_bind_text(compiledStatement, 4, [string1 UTF8String], -1,SQLITE_TRANSIENT);
sqlite3_bind_text(compiledStatement, 5, [string1 UTF8String], -1,SQLITE_TRANSIENT);
if(sqlite3_step(compiledStatement) != SQLITE_DONE )
{
NSLog( #"Error: %s", sqlite3_errmsg(database) );
}
else {
NSLog( #"Insert into row id = %d", sqlite3_last_insert_rowid(database));
}
}
As your database in resource bundle you are trying to modify and update it. The better approach would be place your database first time in documents directory of sandbox and then perform operation on that database.
Here is the method using which you can move your database to documents directory of your application's sandbox. This method should be called only once while using database operation.(because only first time we need to place it at that location, other times we just need to access it).
Code :
// Name : configureDatabase:
// Description : Method configures the database with new name.
// Arguements : NSString : Databse file name
// Retrun : None
-(void) configureDatabase:(NSString *)newDatabaseName
{
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [[documentsDir stringByAppendingPathComponent:newDatabaseName]retain];
// Execute the "checkAndCreateDatabase" function
[self checkAndCreateDatabase:databasePath];
}
// Name : checkAndCreateDatabase:
// Description : Method checks and creates the database file at the given path if its not present.
// Arguements : NSString : file path.
// Retrun : None.
-(void) checkAndCreateDatabase:(NSString *)dbPath
{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:dbPath];
// If the database already exists then return without doing anything
if(success)
{
return;
}
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp=[[NSBundle mainBundle] pathForResource:#"TestData" ofType:#"sqlite"];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:dbPath error:nil];
}
Also note that if we are using database so it is good practice to locate it first in some directory from where user can take backup. Documents directory of sandbox is one of these backup ready directory.
Thanks,
Related
I created a table named "dept" in sqlite manually that has username (as Varchar) and Password (as Integer).
I used the following code to update a table
NSString *database2=[[NSBundle mainBundle]pathForResource:#"deptDatabase" ofType:#"sqlite"];
NSString *databasePath2=[NSString stringWithFormat:#"%#",database2];
const char *dbPath=[databasePath2 UTF8String];
if (sqlite3_open(dbPath, &dbHandler)==SQLITE_OK) {
NSLog(#"database Opened");
const char* updateQuery="update dept set password=1234 where username='suren'";
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(dbHandler, updateQuery, -1, &stmt, NULL)==SQLITE_OK) {
NSLog(#"Query Executed");
}
}
sqlite3_close(dbHandler);
but the table seems to be not updating.
Can anyone pls tell me how to update the table by altering the above code.
Thanks in advance
You can't not update fils in the mainBundle, these files are readonly.
To make changes to the database, you will have to copy it to the document directory.
And use the database in the document directory and not the one in the main bundle.
Only use the one in the main bundle as a payload file to be copied to the document directory if there is not file there.
Why do you create a new string here:
NSString *database2=[[NSBundle mainBundle]pathForResource:#"deptDatabase" ofType:#"sqlite"];
NSString *databasePath2=[NSString stringWithFormat:#"%#",database2];
The database2 is same as databasePath2. You are only using up memory here.
copy file from bundle to documents directory
NSString *databaseName = #"YOUR DB NAME WITH EXTENSION";
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL success=[fileManager fileExistsAtPath:databasePath];
if (!success) {
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
then u can work in the path databasePath (documents directory)
const char *dbPath=[databasePath UTF8String];
if (sqlite3_open(dbPath, &dbHandler)==SQLITE_OK) {
NSLog(#"database Opened");
const char* updateQuery="update dept set password=1234 where username='suren'";
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(dbHandler, updateQuery, -1, &stmt, NULL)==SQLITE_OK) {
NSLog(#"Query Executed");
}
}
sqlite3_close(dbHandler);
hope it helps.. happy coding :)
I have an application where I have two textfields and a button. In the first textfield I am entering the username of the user and in the second textfield I am entering the password of the user. When the user enters the username and password and click on create user button a backend api is called which will register the username and password of the user and at the time I want to enter the username and password of the user in local SQLite databse in encrypted format.
When a user is registered the username of that particular user should get displayed in the first textfield and it should not be editable and password field should be editable. Only one user is allowed to be registered for the entire application.
Don't use a sqlite dbs to store user credentials. With reverse engineering it is fairly simple to get to the data. This because you probably have some value in your program you use to encrypt/decrypt the password. For security purposes, please use the keychain. There are several projects on github which makes it very easy to use the keychain. There is no more secure way for saving credentials then the keychain, so please use that to store your credentials!!!
If I understood your requirement correctly, You can follow the below guideline.
Before inserting the data to the table, You can check if any record is added to the table.
If the count is 0, you can proceed to insert the record, else you can prompt the error.
I think this will be the simplest way to do this.
First step is to check the database exist in resource folder and create database:-
1)
-(void)checkAndCreateDatabase{
databaseName = #"databasename.sql";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
BOOL success;
// Create a FileManager object, we will use this to check the status of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:databasePath];
// If the database already exists then return without doing anything
if(success) {
return;
}
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
2) call the function to retrieve the data:-
-(NSMutableArray *) readFromDatabase:(NSString *)query{
// Setup the database object
sqlite3 *database;
// Init the animals Array
returnArray = [[NSMutableArray alloc] init];
NSString *readCommand= query;
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = [readCommand UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
[returnArray addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)]];
[returnArray addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)]];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return returnArray;
}
3) check for the retrun array is empty or nil then call the insert function defined at step
4) Insert into the database
-(void)insertIntoDatabase:(NSString *)username:(NSString *)password{
// Setup the database object
sqlite3 *database;
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
NSString *insertCommand=#"Insert into tableName values(username,password)";
const char *sqlStatement = [insertCommand UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {}
sqlite3_finalize(compiledStatement);
}
// Release the compiled statement from memory
}
sqlite3_close(database);
}
You can use NSUserDefaults saving locally it. following code is for saving data.
perf = [NSUserDefaults standardUserDefaults];
[perf setObject:#"1" forKey:#"remember"];
[perf setObject:emailAddresTextField.text forKey:#"email"];
[perf setObject:passwordTextField.text forKey:#"password"];
[perf synchronize];
And for retrieving data use following code
perf=[NSUserDefaults standardUserDefaults];
NSString *remString = [perf stringForKey:#"remember"];
if ([remString isEqualToString:#"1"]) {
emailAddresTextField.text=[perf stringForKey:#"email"];
passwordTextField.text = [perf stringForKey:#"password"];
[rememberBtn setTag:1];
[rememberBtn setImage:[UIImage imageNamed:#"on_radioButton.png"] forState:0];
}
I am inserted first record in sqlite, and when i am trying to add another it shows "Database Locked" error.
the code is:
- (void) addRecord:(NSMutableDictionary *)recordDict
{
if(addStmt == nil) {
const char *sql = "insert into Product(ProID, BarCode , ProductName ) Values(?,?,?)";
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
NSInteger recordId = [[recordDict objectForKey:#"ProID"] intValue];
NSLog(#"%d",recordId);
sqlite3_bind_int(addStmt, 1,recordId);
sqlite3_bind_text(addStmt, 2, [[recordDict objectForKey:#"BarCode"] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(addStmt, 3, [[recordDict objectForKey:#"ProductName"] UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(addStmt))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
else
{//SQLite provides a method to get the last primary key inserted by using sqlite3_last_insert_rowid
rowID = sqlite3_last_insert_rowid(database);
NSLog(#"last inserted rowId = %d",rowID);
//Reset the add statement.
sqlite3_reset(addStmt);
}
}
Nothing in your code jumps out at me. If you are getting "Database Locked" then that means you have an open transaction that is locking the database. This could be in your app (in another thread perhaps) or in another app that is also accessing the same database.
"Database Locked" means the database is not writable, two reasons for this -
1) You forget to finlalize your previous compiled statement or forgot to close the database try this in your previous query -
sqlite3_finalize(compiledStatement);
sqlite3_close(database);
2) Are you copying the database in Documents directory before using it? You can't modify the database in bundle itself. Here is the code to copy the database in documents directory.
-(void) checkAndCreateDatabase{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:databasePath];
// If the database already exists then return without doing anything
if(success) return;
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
[fileManager release];
}
Here is how to get database path -
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [[documentsDir stringByAppendingPathComponent:databaseName] retain];
NSLog(#"%#",databasePath);
i have a database that is in the documents directorys of the
Application/iPhoneSimulator/3.2/Applications/etc/Documents
I have this code under my method
databaseName = #"database.sql";
NSArray *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory.NSUserDomainMask,YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
How do i do an insert with a variable/ array .
Something like
"INSERT INTO TABLE (COLUMN) VALUES ('%#'),[appDelegate.variable objectAtIndex:0];
I insist you to go through this question.
First of all copy the database from main bundle to your application's document dir.
You can follow below code to implement it.
NSString *databaseFile=[[NSBundle mainBundle] pathForResource:kDataBaseName ofType:kDataBaseExt];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *dbPath=[basePath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#",kDataBaseName,kDataBaseExt]];
NSFileManager *fm=[NSFileManager defaultManager];
if(![fm fileExistsAtPath:dbPath]){
[fm copyItemAtPath:databaseFile toPath:dbPath error:nil];
}
[fm release];
self.dataBasePath=dbPath;
I am supplying you directly my project code. Please add comment if any doubts.
I have added comments for the explanation.
// function with multiple arguments which is going to be used for inserting into table.
+(void)insertBuilding:(NSString*)BName streetNo:(NSInteger)streetNo streetName:(NSString*)streetName streetDir:(NSString*)streetDir muni:(NSString*)muni province:(NSString*)province bAccess:(NSString*)bAccess bType:(NSString*)bType amnity:(NSString*)amnity latitude:(NSString*)latitude longitude:(NSString*)longitude imageName:(NSString*)imageName {
// application delegate where I have saved my database path.
BuildingLocatorAppDelegate *x=(BuildingLocatorAppDelegate *)[[UIApplication sharedApplication]delegate];
sqlite3 *database; // database pointer
// verifying if database successfully opened from path or not.
// you must open database for executing insert query
// i have supplied database path in argument
// opened database address will be assigned to database pointer.
if(sqlite3_open([[x dataBasePath] UTF8String],&database) == SQLITE_OK) {
// creating a simple insert query string with arguments.
NSString *str=[NSString stringWithFormat:#"insert into buildingDtl(b_name,streetNo,streetName,streetDir,muni,province,b_access,b_type,aminity,latitude,longitude,b_image) values('%#',%i,'%#','%#','%#','%#','%#','%#','%#','%#','%#','%#')",BName,streetNo,streetName,streetDir,muni,province,bAccess,bType,amnity,latitude,longitude,imageName];
// converting query to UTF8string.
const char *sqlStmt=[str UTF8String];
sqlite3_stmt *cmp_sqlStmt;
// preparing for execution of statement.
if(sqlite3_prepare_v2(database, sqlStmt, -1, &cmp_sqlStmt, NULL)==SQLITE_OK) {
int returnValue = sqlite3_prepare_v2(database, sqlStmt, -1, &cmp_sqlStmt, NULL);
((returnValue==SQLITE_OK) ? NSLog(#"Success") : NSLog(#"UnSuccess") );
// if NSLog -> unsuccess - that means - there is some problem with insert query.
sqlite3_step(cmp_sqlStmt);
}
sqlite3_finalize(cmp_sqlStmt);
}
sqlite3_close(database);
// please don't forget to close database.
}
+(NSString *)stringWithFormat:(NSString *)format parameters:...];
NSString sql = [NSString stringWithFormat:#"INSERT INTO table VALUES('%#')", #"Hello, world!"];
sqlite3_....
Use either prepared statements in combination with the bind_*() functions (e.g. bind_text()) or the mprintf() function to insert strings, see this question for details.
To get a raw C-string you can pass to these functions use -UTF8String or -cStringUsingEncoding: on a NSString.
I have a problem with my app it opens this database and selects rows from it ok,
Then when I want to add new rows using the following code and I always get the following problem at the execution of the prepare_V2.
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error while creating add statement. 'out of memory''
code is .....
static sqlite3 *database = nil;
static sqlite3_stmt *addStmt = nil;
- (BOOL)addUserprofile {
addStmt = nil; // set to force open for testing
database = nil; // set to force creation of addstmt for testing
if (database == nil) { // first time then open database
NSString *databaseName = #"UserProfile.db";
// Use editable database paths
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
NSLog(#"path = %#",databasePath);
NSLog(#"opening Database");
sqlite3 *database;
// Open the database from the users filessytem
if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSLog(#"Database Open");
}
else {
NSLog(#"Database did not open");
}
}
if(addStmt == nil) {
NSLog(#"Creating add stmt");
const char *sql = "INSERT INTO Profile (ProfileName) VALUES(?)";
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK) {
NSAssert1(0, #"** Error while creating add statement. '%s'", sqlite3_errmsg(database));
success = NO;
return success;
}
}
sqlite3_bind_text(addStmt, 1, [ProfileName UTF8String], -1, SQLITE_TRANSIENT);
Sometime, your database is being SQLITE_BUSY or SQLITE_LOCKED.
You can refer this framework to know how to do:
https://github.com/ccgus/fmdb
Good luck!:)