为什么我得到一个SQLITE_MISUSE:内存不足错误?

我正在写一个直接访问SQLiteiOS应用程序。 我在Android上多次做了这样的事情,所以我很努力地看到我的错误在哪里 – 但是我的插入正在返回SQLITE_MISUSE错误(代码21),消息“内存不足”。 以下是我已经采取的步骤来引导我这个插入。

首先, 创build表格

 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"); } } 

接下来, 插入 (当前使用用户ID的电子邮件地址):

 INSERT INTO UsersTable (id,lastName,firstName,email) VALUES ("jsmith@foobar.com","Smith","John","jsmith@foobar.com") 

我为所有的数据库交互使用了一个select器,所以上面的文本在这里传递:

 -(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; } 

我究竟做错了什么?

如果数据库不存在,则打开的例程只是创build/打开数据库。 你的数据库可能已经存在,因此你的例程甚至没有打开它。

底线,如果您尝试在不打开数据库的情况下调用SQLite函数,则会得到SQLITE_MISUSE返回码(表示SQLite函数未按正确顺序调用), sqlite3_errmsg将返回隐含的“内存不足”错误。


其他一些无关的观察:

  1. 你真的应该检查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; } 

    根据我的经验,许多常见的开发问题与SQL本身有关,通过检查sqlite3_prepare_v2语句的返回码来识别。

  2. 你真的不应该在NSStringbuild立你的SQL语句。 你打开自己的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; } 

    你可以这样调用它:

     [self insertIdentifier:@"jsmith@foobar.com" lastName:@"Smith" firstName:@"John" email:@"jsmith@foobar.com"]; 
  3. 正如你所看到的,当你开始编写代码的时候,你正在适当地检查每一个返回值,绑定每个variables等等,你的SQLite代码变得非常快速。 我build议你考虑一下FMDB 。 它是SQLite函数的一个很好的简洁的包装,它极大地简化了在Objective-C中编写SQLite代码的练习。

你没有检查sqlite3_prepare_v2语句的值。 如果它不是SQLITE_OK那么就有一个问题。

另外,数据库文件是否已经存在? 如果没有,您需要创build它或从包中加载它。