在iOS sqlite中获取html字符串的插入错误

时间:2014-02-12 13:47:12

标签: html ios sqlite

我需要在SQLite数据库中保存html字符串。运行insert查询时,我在HTML文件的style标记附近出现语法错误。

以下是代码:

-(BOOL)insertAttendees{
    sqlite3_stmt    *statement;

    NSString *insertSQL;
    BOOL var=NO;
    if (sqlite3_open(dbpath, &db) == SQLITE_OK)
    {
        //work only for the 1st event
        for (int i=0; i<[attendeeCount[0]integerValue];i++)
        {

           insertSQL = [NSString stringWithFormat:@"INSERT INTO ATTENDEE (A_NAME,A_IMAGE,A_EMAIL,A_PHONE,A_BIO) VALUES (\"%@\",\"%@\", \"%@\",\"%@\",\"%@\")",arrayOf_AName[0][i],arrayOf_AImage[0][i],arrayOf_AEmail[0][i],arrayOf_APhone[0][i],arrayOf_ABio[0][i]];

            const char *insert_stmt = [insertSQL UTF8String];
            sqlite3_prepare_v2(db, insert_stmt,-1, &statement, NULL);
            if (sqlite3_step(statement) == SQLITE_DONE)
            {
                var=YES;
            }
            else
            {
                NSLog(@"sqlite insertion error %s", sqlite3_errmsg(db));
                var=NO;
            }
            sqlite3_finalize(statement);
        }
        sqlite3_close(db);
        return var;
    }
    return var;
}

2 个答案:

答案 0 :(得分:0)

这里有很多问题:

  1. 问题的根源在于您使用stringWithFormat构建SQL,这是您不应该做的。如果您的值中包含引号(例如可能在HTML中的style标记附近),则您的SQLite代码将失败。相反,你应该:

    • 您的SQL应该使用?占位符(注意,SQL中也没有引号):

      const char *insert_stmt = "INSERT INTO ATTENDEE (A_NAME,A_IMAGE,A_EMAIL,A_PHONE,A_BIO) VALUES (?,?,?,?,?)";
      
    • 然后,您应该使用以下内容绑定值:

      if (sqlite3_bind_text(statement, 1, [string UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
          NSLog(@"%s: bind column 1 failed: %s", __FUNCTION__, sqlite3_errmsg(db));
      }
      

      其中string是您要插入的NSString值,而第二个参数(1,在上例中)是?占位符的索引你绑定到文本值(最左边的占位符的索引为1)。

    • 只有在您为五个sqlite3_bind_xxxx()占位符中的每一个调用?后,才可以通过调用sqlite3_step()等来继续

  2. 第二个问题是您没有检查sqlite3_prepare_v2是否成功。这很重要,因为如果在prepare语句失败后立即调用sqlite3_errmsg,您将看到的有意义的错误消息现在已丢失。您无视任何潜在的准备错误,无论如何继续sqlite3_step,因此有意义的错误消息将被替换为有效(但隐密地)表示您在没有先成功调用{{sqlite3_step的情况下调用sqlite3_prepare_v2的错误消息1}}。

    因此,请检查以确保sqlite3_prepare_v2成功,如果失败,请在执行任何其他SQLite调用之前立即检查sqlite3_errmsg

  3. 解决上述两个问题后,您可能会考虑优化代码。值得注意的是,如果您在所有BEGIN TRANSACTION语句之前执行INSERT,而在完成所有插入操作后执行COMMIT TRANSACTION,则会更快。如果您只插入几条记录,则可能无法观察到,但如果插入大量记录,性能提升可能会非常惊人。

  4. 作为进一步的优化,让我们假设您解决了我的上述观点(特别是,消除了stringWithFormat的SQL并使用了?占位符)并且你有类似下面的伪代码(但显然检查所有的sqlite3函数返回值并正确处理错误):

    sqlite3_exec("begin transaction");
    
    for (i = 0; i < whatever; i++) {
        sqlite3_prepare(...);
    
        sqlite3_bind(...);
        sqlite3_bind(...);
        sqlite3_bind(...);
        sqlite3_bind(...);
        sqlite3_bind(...);
    
        sqlite3_step();
    
        sqlite3_finalize();
    }
    
    sqlite3_exec("commit transaction");
    

    不是多次准备相同的SQL,而是可以准备一次,绑定值,执行步骤,然后重置绑定,以便再次执行:

    sqlite3_exec("begin transaction");
    
    sqlite3_prepare(...);
    
    for (i = 0; i < whatever; i++) {
    
        sqlite3_bind(...);
        sqlite3_bind(...);
        sqlite3_bind(...);
        sqlite3_bind(...);
        sqlite3_bind(...);
    
        sqlite3_step();
    
        sqlite3_reset();
    }
    
    sqlite3_finalize();
    
    sqlite3_exec("commit transaction");
    
  5. 就个人而言,我建议你专注于上面的第1点和第2点,只有在你解决了基本问题时,你应该考虑第3点和第4点的优化。确保在你需要优化之前让它工作它

    最后,如果我没有指出你真的应该考虑围绕SQLite C接口的精彩的第三方FMDB Objective-C包装器,那将是我的疏忽。当您编写正确的SQLite代码,即绑定每个值,检查每个返回代码等时,它会很快变得难以处理。 FMDB极大地简化了您的代码。

答案 1 :(得分:0)

如果您确实想在sqlite数据库中插入HTML,请在执行查询之前将所有"替换为\"

(你没有提到你是否要替换特殊字符。)

假设你正在这样做..

"SELECT * FROM table WHERE someColume = <div style="width:25px"></div>"

style =“之后它会失败,因为sqlite会尝试执行"SELECT * FROM table WHERE someColume = <div style="

但如果您将"替换为\",那么您的最终查询将如下所示 -

"SELECT * FROM table WHERE someColume = <div style=\"width:25px\"></div>"
祝你好运。