FMDB: добавить новый столбец и вставить данные

В моем приложении я использую FMDatabase. Я пытаюсь добавить новые column к существующим table, а затем insert данным в этом столбце. Когда я добавил столбец с помощью Alter Table, у меня не было ошибок, но когда я пытался вставить данные в таблицу, я получил сообщение об ошибке, жалуясь на недавно добавленный столбец, которого не существует.

Вот мой код

NSString *databasePath = [myDB getPlacesDBPath];

FMDatabase *db = [FMDatabase databaseWithPath:databasePath];

if (![db open])
{
    return ;
}

if (![db columnExists:@"placeName" inTableWithName:@"MYPLACES"])
{
    [db executeQuery:@"ALTER TABLE MYPLACES ADD COLUMN placeName TEXT"];
    // I tried to set the result of this query in "BOOL Success" and print the results and I got YES    
}

//Note: I have more than 12 columns but I didn't post all of them here
NSString *insertSQL = [NSString stringWithFormat: @"INSERT INTO  MYPLACES  ( placeID ,  placeName)  VALUES (\"%@\", \"%@\")", placeIDValue, placeNameValue ];

[db executeUpdate:insertSQL];

if ([db hadError]) {
    NSLog(@"error : %@",[db lastError]);
}

[db close];

Я получил следующую ошибку:

error : Error Domain=FMDatabase Code=1 "table MYPLACES has no column named placeName" UserInfo=0xe340920 {NSLocalizedDescription=table MYPLACES has no column named placeName}

В чем проблема? как узнать, почему новый столбец не добавляется?


person Sawsan    schedule 01.01.2014    source источник


Ответы (3)


Я не вижу ничего в приведенном выше упрощенном примере кода, чтобы объяснить ошибку, о которой вы сообщаете. Проблема может заключаться в другом (или, возможно, в процессе упрощения примера кода вы устранили источник проблемы).

На это у меня было несколько реакций:

  1. #P3# <блочная цитата> #P4# #P5#
  2. Я не понимаю, почему вы убрали проверку ошибок. Это лучший способ выявить проблемы.

  3. Совершенно не связано, но вы никогда не должны использовать stringWithFormat при построении SQL. Вы подвергаете себя сбоям SQL из-за неожиданного ввода (например, что, если одно из ваших значений содержит двойные кавычки). Хуже того, вы подвергаете себя атакам SQL-инъекций. Вместо этого используйте заполнители ? в SQL, а затем просто передайте значения в качестве параметров методу executeUpdate (или executeQuery).

Итак, следующий код работал нормально для меня:

BOOL success;

FMDatabase *db = [FMDatabase databaseWithPath:databasePath];

if (![db open])
{
    NSLog(@"open failed");
    return;
}

if (![db columnExists:@"placeName" inTableWithName:@"MYPLACES"])
{
    success = [db executeUpdate:@"ALTER TABLE MYPLACES ADD COLUMN placeName TEXT"];
    NSAssert(success, @"alter table failed: %@", [db lastErrorMessage]);
}

NSString *insertSQL = @"INSERT INTO  MYPLACES  (placeID, placeName)  VALUES (?, ?)";
success = [db executeUpdate:insertSQL, placeIDValue, placeNameValue];
NSAssert(success, @"insert failed: %@", [db lastErrorMessage]);

[db close];

Поскольку я не вижу, что может вызвать описанную вами проблему, я могу только предложить вам выполнить один шаг по этому коду в вашем отладчике и убедиться, что он следует по пути, который вы думаете.

person Rob    schedule 01.01.2014
comment
Спасибо за четкий, структурированный и простой ответ. Я не знаю, в чем именно была проблема, но использование executeUpdate вместо executeQuery решило проблему. - person Sawsan; 02.01.2014

Свифт 3 код:

 let db = FMDatabase(path: Util.getPath(databasePath)
    guard db != nil else { return }

    db!.open()
    if !(db!.columnExists("tableName", columnName: "USERID")) {

        let alterTable = "ALTER TABLE tableName ADD COLUMN USERID TEXT"
        if db!.executeUpdate(alterTable, withArgumentsIn: nil) {
            printf(“new column added”)
    }
    else {
        printf(“issue in operation”)
    }
    db!.close()

Может поможет кому. Продолжайте кодировать..

person Mayuri R Talaviya    schedule 21.12.2017

Проблема в том, что -[FMDatabase executeQuery:] не выполняет отправленные инструкции, а только подготавливает оператор.

Для их выполнения нужно выполнить «шаг».

В FMDB это делается с помощью -[FMResultSet next], внутри - с помощью вызова sqlite3_step().

Поскольку -executeUpdate: (в отличие от -executeQuery:) делает это за вас и завершает оператор, он может быть более подходящим для этой цели.

Итак, если вам действительно нужно использовать -executeQuery:

FMResultSet *rs = [db executeQuery:@"ALTER TABLE MYPLACES ADD COLUMN placeName TEXT"];
[rs nextWithError:&error]; // error handling is recommended here
[rs close];

Но -executeUpdate: более лаконичен.

BOOL success = [db executeUpdate:@"ALTER TABLE MYPLACES ADD COLUMN placeName TEXT"];
person Yaro Povetsky    schedule 04.07.2018