为什么会出现SQLITE_MISUSE:内存不足错误? [英] Why do I get a SQLITE_MISUSE : Out of Memory error?

查看:215
本文介绍了为什么会出现SQLITE_MISUSE:内存不足错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写直接访问SQLite iOS 应用程序.我已经在 Android 上做了很多这样的事情,所以我努力查看错误的出处-但是我的插入内容返回SQLITE_MISUSE错误(代码21),并显示消息记不清".以下是我带领我完成此插入操作的步骤.

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.

首先,表创建:

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):

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

我在做什么错了?

推荐答案

您的打开例程仅在数据库不存在时创建/打开数据库.您的数据库可能已经存在,因此您的例程甚至都没有打开它.

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.

最重要的是,如果您尝试在不打开数据库的情况下调用SQLite函数,则会得到SQLITE_MISUSE返回代码(表明未按正确的顺序调用SQLite函数),而sqlite3_errmsg将返回隐含的内存不足"错误.

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:

  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语句的返回码来识别.

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.

您实际上不应该在NSString中构建SQL语句.您可以接受SQL注入攻击,或者考虑更温和的情况,如果某人的名字中带有引号(例如,如果有引号),则只会出现SQL错误. The "Destroyer".您应该使用?占位符,然后使用 sqlite3_bind_xxx 函数来绑定值.像这样:

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

您可以这样称呼它:

[self insertIdentifier:@"jsmith@foobar.com"
              lastName:@"Smith"
             firstName:@"John"
                 email:@"jsmith@foobar.com"];

  • 正如您所看到的,当您开始编写代码时,在其中适当地检查每个返回值,绑定每个变量等,您的SQLite代码很快就会变得毛骨悚然.我建议您考虑查看 FMDB .这是一个很好的,精巧的SQLite函数包装器,大大简化了用Objective-C编写SQLite代码的过程.

  • 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.

    这篇关于为什么会出现SQLITE_MISUSE:内存不足错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆