为什么我得到一个SQLITE_MISUSE:内存不足错误?
我正在写一个直接访问SQLite
的iOS应用程序。 我在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
将返回隐含的“内存不足”错误。
其他一些无关的观察:
-
你真的应该检查
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
语句的返回码来识别。 -
你真的不应该在
NSString
build立你的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"];
-
正如你所看到的,当你开始编写代码的时候,你正在适当地检查每一个返回值,绑定每个variables等等,你的SQLite代码变得非常快速。 我build议你考虑一下FMDB 。 它是SQLite函数的一个很好的简洁的包装,它极大地简化了在Objective-C中编写SQLite代码的练习。
你没有检查sqlite3_prepare_v2
语句的值。 如果它不是SQLITE_OK
那么就有一个问题。
另外,数据库文件是否已经存在? 如果没有,您需要创build它或从包中加载它。