Phi*_*hil 2 sqlite objective-c ios
我正在编写一个直接访问的iOS应用程序SQLite.我在Android上已经做了很多次这样的事情,所以我很难看到我的错误在哪里 - 但是我的插入返回SQLITE_MISUSE错误(代码21),消息"内存不足".以下是我采取的引导我插入的步骤.
一,表创建:
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");
}
}
Run Code Online (Sandbox Code Playgroud)
接下来,插入(当前使用用户ID的电子邮件地址):
INSERT INTO UsersTable (id,lastName,firstName,email) VALUES ("jsmith@foobar.com","Smith","John","jsmith@foobar.com")
Run Code Online (Sandbox Code Playgroud)
我正在为所有数据库交互使用一个选择器,因此上面的文本在这里传递:
-(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;
}
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
Rob*_*Rob 16
如果数据库不存在,您的打开例程仅创建/打开数据库.您的数据库可能已经存在,因此您的例程甚至没有打开它.
最重要的是,如果您尝试在不打开数据库的情况下调用SQLite函数,您将获得SQLITE_MISUSE返回代码(表示未以正确的顺序调用SQLite函数),并且sqlite3_errmsg将返回神秘的"内存不足"错误.
其他一些不相关的观察结果:
你真的应该检查一下返回代码sqlite3_prepare:
- (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;
}
Run Code Online (Sandbox Code Playgroud)
根据我的经验,许多常见的开发问题都与SQL本身有关,这是通过检查sqlite3_prepare_v2语句的返回代码来识别的.
你真的不应该在一个构建你的SQL语句NSString.你打开自己的SQL注入攻击,或者考虑到更好的情况,如果有人的名字中有一个引号,只是一个SQL错误,例如The "Destroyer".您应该使用?占位符,然后使用sqlite3_bind_xxx函数绑定值.就像是:
- (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;
}
Run Code Online (Sandbox Code Playgroud)
然后您可以这样调用:
[self insertIdentifier:@"jsmith@foobar.com"
lastName:@"Smith"
firstName:@"John"
email:@"jsmith@foobar.com"];
Run Code Online (Sandbox Code Playgroud)正如您所看到的,当您开始编写代码时,您正在适当地检查每个返回值,绑定每个变量等,您的SQLite代码会很快变得毛茸茸.我建议你考虑看FMDB.它是围绕SQLite函数的一个很好的,薄的包装器,它极大地简化了在Objective-C中编写SQLite代码的练习.