【问题标题】:sqlite3_step(statement) == SQLITE_DONE returning false all the timesqlite3_step(statement) == SQLITE_DONE 一直返回 false
【发布时间】:2014-10-25 15:00:40
【问题描述】:

伙计们,我的 sn-p 有问题。我还必须说我是新手。我正在尝试将数据插入到 sqlite。但我一直失败,因为 sqlite_step == sqlite_done 一直返回 false 。我在这里做错什么了吗。我以前做过类似的事情,而且效果很好。以下是代码

sqlite3_stmt *statement;
const char *dbpath = [_databasePath UTF8String];

if(sqlite3_open(dbpath, &_db) == SQLITE_OK){
    NSString *insertSQL = [NSString stringWithFormat:@"INSERT INTO userInfo (name, email, username, password) VALUES (\"%@\",\"%@\",\"%@\",\"%@\")", self.txtName.text, self.txtEmail.text, self.txtUsername.text, self.txtPassword.text];
    if([self validateRegistration])
    {
        const char *insert_statement = [insertSQL UTF8String];
        sqlite3_prepare_v2(_db, insert_statement, -1, &statement, NULL);

        if(sqlite3_step(statement) == SQLITE_DONE){
            [self showUIAlertWithMessage:@"User added to the database" andTitle:@"Message"];
            self.txtName.text = @"";
            self.txtEmail.text = @"";
            self.txtUsername.text = @"";
            self.txtPassword.text = @"";
            self.txtConfirmPassword.text = @"";
        }else{
            [self showUIAlertWithMessage:@"Failed to add the user" andTitle:@"Error"];
        }
        sqlite3_finalize(statement);
        sqlite3_close(_db);
    }
}

【问题讨论】:

  • 捕获返回码并记录“坏”的值,不要简单地测试它们。并捕获其中的所有。然后在收到错误的返回码时记录来自 sqlite3_errmsg 的值。
  • 使用 +[NSString stringWithFormat:] 构造 SQLite 语句是个坏主意。最好的情况是,当用户输入双引号字符或类似字符时,您会遇到莫名其妙的错误。在最坏的情况下,它可能会让您对来自恶意用户的 SQL 注入持开放态度。您应该改用占位符和sqlite3_bind_* API 来安全地执行此操作。

标签: ios objective-c iphone sqlite ios8.1


【解决方案1】:

必须检查sqlite3_prepare_v2的返回值。

如果sqlite3_prepare_v2sqlite3_step 失败,您必须通过sqlite3_errmsg 获得实际错误消息。

【讨论】:

  • 谢谢@CL。我对此有点陌生!你能向我解释一下我该怎么做吗?我的意思是实际的错误信息?我似乎从 sqlite_prepare_v2 得到的结果代码为 1
【解决方案2】:

如果您检查sqlite3_prepare_v2 的结果,几乎可以肯定它不是SQLITE_OK。如果您查看sqlite3_errmsg,它会准确地告诉您问题所在:

if (sqlite3_prepare_v2(_db, insert_statement, -1, &statement, NULL) != SQLITE_OK) {
    NSLog(@"insert failed: %s", sqlite3_errmsg(_db));

无关,但您不应该使用stringWithFormat 来构建您的SQL。您应该在 SQL 中使用 ? 占位符,然后手动将值与 sqlite3_bind_text()(或其他)绑定。

const char *insert_statement = "INSERT INTO userInfo (name, email, username, password) VALUES (?, ?, ?, ?)";

if (sqlite3_prepare_v2(_db, insert_statement, -1, &statement, NULL) != SQLITE_OK) {
    NSLog(@"prepare failed: %s", sqlite3_errmsg(_db));

if (sqlite3_bind_text(statement, 1, [self.txtName.text UTF8String], -1, NULL) != SQLITE_OK) 
    NSLog(@"bind 1 failed: %s", sqlite3_errmsg(_db));

if (sqlite3_bind_text(statement, 2, [self.txtEmail.text UTF8String], -1, NULL) != SQLITE_OK) 
    NSLog(@"bind 2 failed: %s", sqlite3_errmsg(_db));

if (sqlite3_bind_text(statement, 3, [self.txtUsername.text UTF8String], -1, NULL) != SQLITE_OK) 
    NSLog(@"bind 3 failed: %s", sqlite3_errmsg(_db));

if (sqlite3_bind_text(statement, 4, [self.txtPassword.text UTF8String], -1, NULL) != SQLITE_OK) 
    NSLog(@"bind 4 failed: %s", sqlite3_errmsg(_db));

if(sqlite3_step(statement) == SQLITE_DONE) {
    [self showUIAlertWithMessage:@"User added to the database" andTitle:@"Message"];
    self.txtName.text = @"";
    self.txtEmail.text = @"";
    self.txtUsername.text = @"";
    self.txtPassword.text = @"";
    self.txtConfirmPassword.text = @"";
}else{
    NSLog(@"step failed: %s", sqlite3_errmsg(_db));
    [self showUIAlertWithMessage:@"Failed to add the user" andTitle:@"Error"];
}

如果您觉得这很麻烦,我建议您考虑 FMDB,这是一个 SQLite 包装器,它可以为您将所有值适当地绑定到 ? 占位符。

【讨论】:

    【解决方案3】:

    我遇到了这个问题,因为我没有根据我的插入语句更新我的 create table 语句,因为我已经更改了一些我正在插入的值。

    【讨论】:

      【解决方案4】:

      您可以为此使用sqlite3_exec()

      char *err;
      int code = sqlite3_exec(_db,insert_statement,NULL,NULL,&err);
      if (code != SQLITE_OK) {
          NSLog(@"something went wrong: %s", err);
      }
      

      然后你倾向于使用准备函数来读取这样的数据:

      sqlite3_stmt *stmt;
      int code = sqlite3_prepare_v2(_db,_query,-1,&stmt,NULL);
      if (code == SQLITE_OK) {
          while (sqlite3_step(stmt) == SQLITE_ROW) {
              // Retrieve data here e.g.
              // int num = sqlite3_column_int(stmt, 0);
          }
      }
      

      有关sqlite3_exec(),请参阅文档here

      【讨论】:

      • 谢谢@RASS 我明白了。但是您能在我提供的代码中发现任何错误吗?因为我有同样的工作!
      • 我看不出您的代码有任何明显错误,但我一直使用sqlite3_exec() 将数据插入数据库。您应该始终检查 sqlite3_prepare_v2() 是否返回 SQLITE_OK 以确保您的 insert_statement 正常。您还可以查看sqlite3_step() 是否正在重新调整SQLITE_OK 而不是SQLITE_DONE
      • 你是否运行过create table语句?
      • 不,建议sqlite3_exec 绝对是错误的方向。他不仅应该使用sqlite3_prepare_v2,而且还应该使用(a)使用? 占位符作为值的SQL 退出stringWithFormat; (b) 使用 sqlite3_bind_xxx() 函数将值绑定到 SQL 中的 ? 占位符。使用sqlite3_exec 会使 Sr.Novato 无法在这里做正确的事情。
      • sqlite3_bind_xxx() 据我了解,它适用于您希望运行多个语句而无需多次准备的情况,这很昂贵。由于Mr.Noob只是添加一组数据,sqlite3_exec()有什么问题?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      • 1970-01-01
      • 2014-04-10
      相关资源
      最近更新 更多