SQLite电话簿插入失败

时间:2013-11-22 17:08:56

标签: ios sqlite

在下面的代码中,注释掉的代码可以正常工作。

但是使用saveData类的DBMgr方法会导致“无法添加联系人”。

我希望看到“联系已添加”。

-(void) saveData{    
    NSString *insSQL = [NSString stringWithFormat:@"INSERT INTO CONTACTS (name,address,phone) VALUES (\"%@\",\"%@\",\"%@\")",name.text,address.text,phone.text];

     DBMgr *dbmgr = [DBMgr alloc];

     if([dbmgr saveData:insSQL]== 0){
     status.text = @"Contact added";
     }else if([dbmgr saveData:insSQL]== 1){
     status.text=@"Failded to add contact";
     }

    /*sqlite3_stmt *statement;
    const char *dbpath = [databasePath UTF8String];

    if(sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
    {
        NSString *insertSQL = [NSString stringWithFormat:@"INSERT INTO CONTACTS (name,address,phone) VALUES (\"%@\",\"%@\",\"%@\")",name.text,address.text,phone.text];

        const char *insert_stmt = [insertSQL UTF8String];
        sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);

        if(sqlite3_step(statement) == SQLITE_DONE)
        {
            status.text = @"Contact added";
            name.text = @"";
            address.text = @"";
            phone.text = @"";
        }else{
            status.text=@"Failded to add contact";
        }
        sqlite3_finalize(statement);
        sqlite3_close(contactDB);

    }*/
}

-(NSInteger) saveData:(NSString *) querySQL{
    NSInteger result;
    sqlite3_stmt *statement;
    const char *dbpath = [databasePath UTF8String];

    if(sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
    {
        NSString *insertSQL = querySQL;

        const char *insert_stmt = [insertSQL UTF8String];

        sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);

        if(sqlite3_step(statement) == SQLITE_DONE)
        {
            result = 0;
        }else{
            result = 1;
        }
        sqlite3_finalize(statement);
        sqlite3_close(contactDB);
    }
    return result;
}

1 个答案:

答案 0 :(得分:1)

您应该检查SQLite调用的所有的结果代码,如果失败,请记录错误:

- (NSInteger) saveData:(NSString *) querySQL{
    NSInteger result = 1;
    sqlite3_stmt *statement;
    const char *dbpath = [databasePath UTF8String];

    if(sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
    {
        NSString *insertSQL = querySQL;

        const char *insert_stmt = [insertSQL UTF8String];

        if (sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL) != SQLITE_OK)
            NSLog(@"%s: prepare failed: %s", __FUNCTION__, sqlite3_errmsg(contactDB));
        else
        {
            if(sqlite3_step(statement) == SQLITE_DONE)
            {
                result = 0;
            }else{
                NSLog(@"%s: step failed: %s", __FUNCTION__, sqlite3_errmsg(contactDB));
            }
            sqlite3_finalize(statement);
        }

        sqlite3_close(contactDB);
    } else {
        NSLog(@"%s: open failed", __FUNCTION__);
    }

    return result;
}

除非你看sqlite3_errmsg,否则你只是在猜测。并检查sqlite3_prepare_v2返回代码,就像我上面所做的那样(因为这更可能是问题的初始指示)。


另外两个不相关的观察结果:

  1. 应初始化DBMgr,例如:

    DBMgr *dbmgr = [[DBMgr alloc] init];
    
  2. 您正在使用INSERT构建stringWithFormat语句。这非常危险,您应该在SQL中使用?占位符:

    const char *insSQL = "INSERT INTO CONTACTS (name,address,phone) VALUES (?, ?, ?)";
    sqlite3_prepare_v2(contactDB, insSQL, -1, &statement, NULL);
    

    然后,在准备该语句之后,您应该使用sqlite3_bind_text函数将值分配给这三个占位符,例如

    sqlite3_bind_text(statement, 1, [name.text    UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(statement, 2, [address.text UTF8String], -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(statement, 3, [phone.text   UTF8String], -1, SQLITE_TRANSIENT);
    

    顺便说一句,如果您想指定NULL,请拨打sqlite3_bind_null而不是sqlite3_bind_text

    显然,请检查每个代码的返回代码,以确保为每个代码返回SQLITE_OK,如果失败则再次记录sqlite3_errmsg

    我很欣赏这种更改需要对您的代码进行一些重构,但使用sqlite3_bind_text来避免SQL注入攻击以及如果用户键入的值会导致错误,这一点非常重要包含引号。

  3. 顺便说一句,如果您正在查看上述内容并意识到需要大量代码才能正确执行此操作,您可能需要考虑使用FMDB来显着简化您的生活。< / p>