【问题标题】:sqlite_prepare_v2 does not return SQLITE_OKsqlite_prepare_v2 不返回 SQLITE_OK
【发布时间】:2013-08-17 17:04:44
【问题描述】:

我一直在尝试将高分保存到数据库中,但过去一周一直失败,我不知道为什么它不起作用。我不断收到“准备语句问题”并拒绝将信息插入数据库。我已经检查了数据库管理器以确保 sql 语句没有拼写错误,并且当在管理器上运行查询时,它工作正常 - 只是 iphone 给了我这个问题。如果有人可以快速查看并发现有问题并告诉我,我将不胜感激!

- (NSMutableArray *) saveLocal {
    NSLog(@"save local database");
    @try {
        [self checkDB];
        sqlite3_stmt *sqlStatement2;


        NSString *sqlS = [NSString stringWithFormat:@"INSERT INTO localHighscore (difficulty, score, uname, puzzles, multiplier, oneshots, hints) VALUES (%i,%i,\"%@\",%i,%i,%i,%i)",[[MySingleton sharedMySingleton] goDifficulty],[[MySingleton sharedMySingleton] goScore],_player, [[MySingleton sharedMySingleton] goPuzzles], [[MySingleton sharedMySingleton] goMultiplier], [[MySingleton sharedMySingleton] goOneshots], [[MySingleton sharedMySingleton] goHints]];
        NSLog(@"%@",sqlS);
        const char *sql = [sqlS UTF8String];


        if(sqlite3_prepare_v2(localHighscore, sql, -1, &sqlStatement2, NULL) == SQLITE_OK)
        {
            sqlite3_step(sqlStatement2);
            sqlite3_reset(sqlStatement2);
            sqlite3_finalize(sqlStatement2);
            NSLog(@"save complete");
        } else {
            NSLog(@"Problem with prepare statement");
        }  
        sqlite3_close(localHighscore);
    }@catch (NSException *exception) {
        NSLog(@"An exception occured: %@", [exception reason]);
    }@finally{
        NSLog(@"DB Loaded!");
    }
}

这里是 checkDB 方法,它检查数据库是否存在,如果不存在则创建一个

- (void)checkDB {
    NSString *docsDir;
    NSArray *dirPaths;

    // Get the documents directory
    dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    docsDir = [dirPaths objectAtIndex:0];

    // Build the path to the database file
    databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: @"localHighscore.sqlite"]];

    NSFileManager *filemgr = [NSFileManager defaultManager];    
    if ([filemgr fileExistsAtPath: databasePath ] == NO)
    {
    const char *dbpath = [databasePath UTF8String];
        NSLog(@"file was not found");
        if (sqlite3_open(dbpath, &localHighscore) == SQLITE_OK)
        {
            NSLog(@"db open");
            char *errMsg;
            const char *sql_stmt = "CREATE TABLE IF NOT EXISTS localHighscore(pk INTEGER PRIMARY KEY AUTOINCREMENT, difficulty TINYINT, score MEDIUMINT, uname VARCHAR(255), puzzles TINYINT, multiplier TINYINT, oneshots TINYINT, hints TINYINT)";

            if (sqlite3_exec(localHighscore, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
            {
                NSLog(@"Failed to create table");
            }
            sqlite3_close(localHighscore);            
        } else {
            NSLog(@"Failed to open/create database");
        }
    }
    [filemgr release];
}

提前感谢您的帮助!

【问题讨论】:

    标签: objective-c database sqlite prepare


    【解决方案1】:

    一些想法:

    1. 在尝试使用数据库之前,您似乎没有调用sqlite3_open

    2. 每当您遇到错误时,您都应该查看sqlite3_errmsg,例如

      if (sqlite3_exec(localHighscore, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
      {
          NSLog(@"Failed to create table: %s", sqlite3_errmsg(localHighscore));
      }
      
    3. 可能与您的问题无关,但您通常不应使用stringWithFormat 构建 SQL 语句(至少如果您有任何文本字段)。在 SQL 中使用 ? 占位符,然后使用 sqlite3_bind_xxx 函数。

      const char *sql = "INSERT INTO localHighscore (difficulty, score, uname, puzzles, multiplier, oneshots, hints) VALUES (?,?,?,?,?,?,?)";
      
      if(sqlite3_prepare_v2(localHighscore, sql, -1, &sqlStatement2, NULL) == SQLITE_OK)
      {
          if (sqlite3_bind_int(sqlStatement2, 1, [[MySingleton sharedMySingleton] goDifficulty]) != SQLITE_OK) {
              NSLog(@"bind 1 failed: %s", sqlite3_errmsg(localHighscore));
          }
      
          if (sqlite3_bind_int(sqlStatement2, 2, [[MySingleton sharedMySingleton] goScore]) != SQLITE_OK) {
              NSLog(@"bind 2 failed: %s", sqlite3_errmsg(localHighscore));
          }
      
          if (sqlite3_bind_text(sqlStatement2, 3, [_player UTF8String], -1, NULL) != SQLITE_OK) {
              NSLog(@"bind 3 failed: %s", sqlite3_errmsg(localHighscore));
          }
      
          // repeat this bind process for each variable
      
          if (sqlite3_step(sqlStatement2) != SQLITE_DONE) {
              NSLog(@"step failed: %s", sqlite3_errmsg(localHighscore));
          }
      
          // reset not needed (doesn't hurt, but not needed unless you're going to re-use it
          // sqlite3_reset(sqlStatement2);
      
          sqlite3_finalize(sqlStatement2);
          NSLog(@"save complete");
      } else {
          NSLog(@"Problem with prepare statement: %s", sqlite3_errmsg(localHighscore));
      }  
      sqlite3_close(localHighscore);
      

      如果您觉得这种语法笨拙,那么可以考虑使用FMDB,它可以简化您的 SQL 交互。但是要非常小心stringWithFormat 与 SQL (如果插入的字符串有引号,sqlite3_prepare 会失败,理论上,您的应用程序会受到 SQL 注入攻击等)。

    4. 顺便说一句,你不应该[filemgr release],因为你不拥有它。

    【讨论】:

    • 哦哇我傻了!!!非常感谢罗布的详细回答!它是 sqlite_open... 并且 errmsg 现在将为我节省很多时间!再次感谢!
    • sqlite_errmsg 为我节省了几个小时。从字面上看,大概。非常感谢:D(我错过了一个空格,所以当我创建表格时,“Tickable”列被命名为“Tickableinteger”!)
    【解决方案2】:

    我看到“sqlite3_prepare_v2 ()”函数在 SQL 语句包含“booleanfield=false”而不是“booleanfield=0”之类的条件时返回“通用错误”(错误代码 = 1)。在 SQLiteStudio 程序的 SQL 框中执行相同的 SQL 语句,无论使用第一种还是第二种比较形式,都可以得到很好的结果。

    【讨论】:

      猜你喜欢
      • 2012-12-24
      • 2011-12-18
      • 1970-01-01
      • 2011-05-30
      • 1970-01-01
      • 1970-01-01
      • 2013-09-26
      • 2019-04-10
      • 1970-01-01
      相关资源
      最近更新 更多