【问题标题】:sqlite3 prepared statement fails if fk is null. It should not如果 fk 为空,sqlite3 准备好的语句将失败。它不应该
【发布时间】:2014-01-15 09:44:43
【问题描述】:

我在我的 iOS 应用程序中使用 Sqlite3。 如果我尝试从控制台运行命令:

 INSERT INTO documents (name,fk_1) VALUES ('pluto','')

一切都很好。 但是当通过准备好的语句执行此操作时,同样会失败:

INSERT INTO documents (name,fk_1) VALUES (?,?)

说“外键约束失败”。fk_1 = ''的值。

表格文件是

CREATE TABLE "documents" ("id" integer   PRIMARY KEY AUTOINCREMENT NOT NULL ,"name" varchar,"attivita_id" integer NULL REFERENCES attivita(id) ON DELETE CASCADE)

我假设我可以使用NULL 值作为 FK,我确实可以,因为从命令行(第一个查询)它可以工作。准备好的语句不可能吗? 执行写入的代码是:

-(NSInteger)writeData:(NSDictionary* )data table:(NSString* )table
{
    sqlite3_stmt    *sqlStatement;
    NSMutableArray  *columns   = [[NSMutableArray alloc] init];
    NSMutableArray  *values    = [[NSMutableArray alloc] init];
    NSMutableDictionary *temp = [[NSMutableDictionary alloc] initWithDictionary:data];
    @try {
        assert([data count] != 0);
        if ([[data allKeys] count] == 0) return 1;
        // Names/Values for INSERT
        //  id is AUTOINCREMENT
        [temp removeObjectForKey:@"id"];
        [columns addObjectsFromArray:[temp allKeys]];
        NSString        *cols      = [columns componentsJoinedByString:@","];
        NSMutableString *colNames  = [[NSMutableString alloc] initWithString:
                                      [NSString stringWithFormat:@"INSERT INTO %s (",[table UTF8String]]];

        [colNames appendString:cols];
        [colNames appendString:@")"];

        // Values for INSERT
        [values addObjectsFromArray:[temp allValues] ];

        // Prepare the ? marks for bindings
        NSMutableArray * marks = [NSMutableArray new];
        for (int i=0 ; i < [values count]; i++)
             [marks addObject:@"?"];

        NSMutableString *s = [[NSMutableString alloc] init];
        NSMutableString *valNames   = [[NSMutableString alloc] initWithString:@" VALUES ("];
        [valNames appendString:[marks componentsJoinedByString:@","]];
        [valNames appendString:@")"];
        [colNames appendString:valNames];
        const char *sql = [colNames UTF8String];
#ifdef DEBUG
        // NSLog(@"avvDB writeDATA insert string %@",colNames);
#endif

        if(sqlite3_prepare_v2(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
        {
            NSLog(@"DB:Problem with prepare statement write %s, data: %@",sqlite3_errmsg(db),data);
            NSLog(@"DB:Query %@",colNames);
            return 0;

        }
        // binding

    for(int i = 0; i < [values count]; i++)
    {
    // According to the doc, if the 3rd value is a null pointer, the effect is similar to 
   // sqlite3_bind_null
          if ([[values objectAtIndex:i] length] == 0 || [values objectAtIndex:i] == nil)
            sqlite3_bind_text(sqlStatement, i+1, nil,-1, SQLITE_TRANSIENT);
        else
        {
            [s setString:[NSString stringWithFormat:@"%@",[values objectAtIndex:i]]];

            const char* currentValue = [s UTF8String];

            sqlite3_bind_text(sqlStatement, i+1, currentValue,-1, SQLITE_TRANSIENT);
        }

    }
    if (sqlite3_step(sqlStatement) == SQLITE_DONE) {
       // NSLog(@"Location  inserted on database");
    }
    else {
        NSLog(@"DB:Error on write: %i %s %@",sqlite3_errcode(db),sqlite3_errmsg(db),data);
        NSLog(@"DB:Query %@",colNames);
    }
   // if (sqlite3_exec(db, sql, NULL, NULL, NULL) == SQLITE_OK)
   // {
   //     NSLog(@"Last id %llu %s",sqlite3_last_insert_rowid(db),sqlite3_errmsg(db));
   //  }
//    NSLog(@"Ecexecuted  write %@",colNames);
    valNames = nil;
    colNames = nil;
    marks    = nil;
    s        = nil;


}// end try
@catch(NSException* e)
{
    NSLog(@"Eccezione in write %@",[e reason]);
}
@finally {

    sqlite3_finalize(sqlStatement);
    sqlStatement = nil;
    return sqlite3_last_insert_rowid(db);
}

}

【问题讨论】:

  • 如何传递空值?因为您应该为参数使用 [NSNull null] 对象而不是 nil 或 NULL
  • 对一列使用参数不应更改另一列的处理。您确定这是您使用的确切查询吗?请显示准备好的语句的完整代码。
  • 我用准备好的语句添加了写入的完整代码。
  • @Luca 我添加了 NSNull 但注意到更改(从数据库的角度来看,空字符串表现为 nil。
  • 我找到了一个我不喜欢的解决方案:如果 FK 受到约束,当它为 NULL 时,它必须不在查询中。但这很难处理,尤其是对于远程接收的数据。

标签: ios sqlite foreign-keys


【解决方案1】:

空字符串与 NULL 相同。

要将参数设置为 NULL,请使用 sqlite3_bind_null。 或者,不要在 INSERT 语句中提及空参数。

【讨论】:

  • 我编辑了代码并插入了 sqlite3_bind_null。没有任何变化(参见代码)。要保存的数据来自服务器:不能修改数据,否则处理起来会很复杂。
  • -1 看起来不是一个有效的参数号。
  • 你推荐哪一个?无论如何阅读文档,我修改了代码:将第三个参数设置为 nil 是等效的。
  • 参数号应该是相同的i+1
猜你喜欢
  • 2019-06-15
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 2010-11-05
  • 2014-01-29
  • 1970-01-01
  • 2011-02-07
  • 2014-03-16
相关资源
最近更新 更多