Objective-C中的参数化SQLite查询

时间:2014-01-21 14:12:46

标签: ios objective-c cocoa-touch sqlite

我有一个接受3个参数的函数,这些参数用于构造SQL查询,这些查询对我数据库中的各个表执行各种操作。我已经尝试转换当前代码,它只是在查询字符串中使用标准的NSString替换,但是在查看几个简单的导航后出现了问题。

这就是我之前所拥有的:

NSString *queryStrInsert = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@)", tableName, columns, values];

这就是我现在所拥有的:

NSString *queryStrInsert = [NSString stringWithFormat:@"INSERT INTO ? (?) VALUES (?)"];

const char *sqlInsert = [queryStrInsert UTF8String];
if ((sqlite3_open([[self filePath] UTF8String], &congressDB)==SQLITE_OK))
{
    if (sqlite3_prepare_v2(congressDB, sqlInsert, -1, &stmtInsert, NULL)==SQLITE_OK)
    {

        if(sqlite3_bind_text(stmtInsert, 0, [tableName UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
        {
            NSLog(@"Binding 0 did not work");
        } 
        if(sqlite3_bind_text(stmtInsert, 1, [columns UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
        {
            NSLog(@"Binding 1 did not work");
        } 
        if(sqlite3_bind_text(stmtInsert, 2, [values UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
        {
            NSLog(@"Binding 2 did not work");
        }
    }
} 

我的代码在sqlite3_prepare_v2(也尝试过sqlite3_prepare)时遇到问题:

near "?": syntax error

3个绑定语句永远不会触发。我已尝试在准备之上移动,但SLITE_OK也为每个返回false。

之前的代码工作正常(没有参数化查询)但希望它更安全并处理撇号等。

感谢。

编辑:

似乎问题的一部分是表和列名称不能只参数值才能参数化。

更新的代码:

NSString *queryStrInsert = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (?)", tableName, columns];

[self openDB];

const char *sqlInsert = [queryStrInsert UTF8String];
if ((sqlite3_open([[self filePath] UTF8String], &congressDB)==SQLITE_OK))
{
    if (sqlite3_prepare_v2(congressDB, sqlInsert, -1, &stmtInsert, NULL)==SQLITE_OK)
    {
        if(sqlite3_bind_text(stmtInsert, 1, [values UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
        {
            NSLog(@"Binding 2 did not work");
        } else {
            NSLog(@"Binding 2 worked - ,%@", stmtInsert);
        }
    }
}

现在出现错误:

1 values for 6 columns

我认为我在这里有一个更大的问题,我试图在这里生成相当动态的SQL查询,而不是有很多很多静态插入查询。您可以从我的原始代码中看到,我正在尝试构建一个灵活的查询,该查询可以根据运行查询的表来获取不同数量的列/值。我已经有效地为列列表及其值创建了一个变量字符串,但我现在很确定这种方法不适用于参数。例如,在这种情况下,值的参数是:

'8ffed886-5f7c-e311-a863-000c29beef51','','','','1389623548','Rick Sanchez'

AS参数化后,整个字符串被视为一个值。不要以为有一个很好的方式来做我在这里尝试的东西吗?如果不是,我将不得不恢复到原来的方法,只是执行一个基本的NSString替换为'是'等...

2 个答案:

答案 0 :(得分:3)

if ((sqlite3_open([[self filePath] UTF8String], &congressDB) == SQLITE_OK)) {
    if (sqlite3_prepare_v2(congressDB, sqlInsert, -1, &stmtInsert, NULL) == SQLITE_OK) {
        if (sqlite3_bind_text(stmtInsert, 1, [tableName UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
            NSLog(@"Binding 1 did not work");
        } 

        if (sqlite3_bind_text(stmtInsert, 2, [columns UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
            NSLog(@"Binding 2 did not work");
        } 

        if (sqlite3_bind_text(stmtInsert, 3, [values UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
            NSLog(@"Binding 3 did not work");
        }
    }
} 

一:您无法参数化表名或列,只能参数值。
二:1

开始绑定索引

答案 1 :(得分:0)

所以你要插入表名,表列名和值,接下来是我接近它的方法:

-(void)insertSpecial:(NSString *)tblNm colNames:(NSArray *)colNms  colVals:(NSArray *)colVls{
sqlite3 *database;
if(sqlite3_open([pathToYourDbHere UTF8String], &database) == SQLITE_OK) {
    NSString *cols=@"";
    NSString *vals=@"";
        for(int i=0;i<colNms.count;i++){
            cols=[cols stringByAppendingString:[colNms objectAtIndex:i]];
            vals=[vals stringByAppendingString:@"?"];
            if(i<colNms.count-1) {
                vals=[vals stringByAppendingString:@","];
                cols=[cols stringByAppendingString:@","];
            }
        }
        const char *sqlStatement3=[[NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES(%@)",tblNm,cols,vals] UTF8String];
        sqlite3_stmt *compiledStatement3;
        if(sqlite3_prepare_v2(database, sqlStatement3, -1, &compiledStatement3, NULL) == SQLITE_OK) {
            for (int i=0; i<colVls.count; i++) {
                sqlite3_bind_text(compiledStatement3, i+1, [[colVls objectAtIndex:i] UTF8String], -1, SQLITE_TRANSIENT);
            }

            if(sqlite3_step(compiledStatement3) != SQLITE_DONE ) {
                NSLog( @"Error: ins records %s", sqlite3_errmsg(database) );
            }else{
                NSLog( @"Insert into records row id = %lld", sqlite3_last_insert_rowid(database));
            }
        }
        sqlite3_finalize(compiledStatement3);
    }

sqlite3_close(database);
database =nil;
}