Как вставить строку в базу данных SQLite с помощью swift? - PullRequest
0 голосов
/ 02 марта 2020

У меня есть база данных SQLITE3 с двумя таблицами, основной и действиями. Я пытаюсь вставить строку в основную таблицу, просто чтобы проверить, работает ли она, используя команду sql на терминале, который я могу вставить, но не через swift. База данных подключена и позволяет мне читать из базы данных, используя swift, но не записывать в нее.

let insertStatementString = "INSERT INTO main (DATE) VALUES (?);"

func insert() {
    var insertStatement: OpaquePointer?
    //1
    if sqlite3_prepare_v2(mySQLDB,insertStatementString, -1, &insertStatement, nil) == SQLITE_OK {
        let date: NSString = "14071999"
        sqlite3_bind_text(insertStatement,1,date.utf8String, -1, nil)

        if sqlite3_step(insertStatement) == SQLITE_DONE {
            print("\nSuccessfully inserted row")
        } else
        { print("\nCould not insert a row")
        }
    }
    else
    { print("\nInsert statement not prepared")
    }
    sqlite3_finalize(insertStatement)
}

Когда программа достигает «if sqlite3_step (insertStatement) == SQLITE_DONE», она затем переходит к «Не удалось» вставить строку '. Кто-нибудь может понять, почему это идет не так?

1 Ответ

0 голосов
/ 03 марта 2020

Если ваша вставка не удалась, вы должны напечатать сообщение об ошибке sqlite3_errmsg, которое точно скажет вам, что пошло не так.

FWIW, ваш код сработал для меня, так что это Возможно, что-то не входит в ваш вопрос, например, как вы открыли базу данных и / или как была определена таблица. Возможные проблемы включают в себя:

  • вставка в базу данных только для чтения (например, открытая база данных в пакете, доступном только для чтения, явно открытая с помощью sqlite3_open_v2 в режиме только для чтения и т. Д. c .);
  • ваш оператор связывания завершился неудачно (вам действительно тоже следует проверить его на успех);
  • с уникальным ключом в этом столбце и уже имеющим это значение где-то; или
  • с другими необходимыми (NOT NULL) столбцами, которые не были предоставлены.

Независимо от того, регистрация сообщения об ошибке устранит любую неопределенность.

Например

func insert() {
    var insertStatement: OpaquePointer?

    guard sqlite3_prepare_v2(mySQLDB, insertStatementString, -1, &insertStatement, nil) == SQLITE_OK else {
        printError(with: "INSERT statement not prepared")
        return
    }

    defer { sqlite3_finalize(insertStatement) }

    let date = "14071999"
    guard sqlite3_bind_text(insertStatement, 1, date.cString(using: .utf8), -1, SQLITE_TRANSIENT) == SQLITE_OK else {
        printError(with: "Bind for INSERT failed")
        return
    }

    guard sqlite3_step(insertStatement) == SQLITE_DONE else {
        printError(with: "Could not insert a row")
        return
    }

    print("Successfully inserted row")
}

func printError(with message: String) {
    let errmsg = sqlite3_errmsg(mySQLDB).flatMap { String(cString: $0) } ?? "Unknown error"
    print(message, errmsg)
}

Где

internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)

Хотя я структурировал это с помощью операторов guard, даже если вы остаетесь с вашим шаблоном if, убедитесь, что вы только sqlite3_finalize, если оператор подготовки завершился успешно , Нет смысла завершать финализацию, если подготовка не удалась.

Также целесообразно использовать SQLITE_TRANSIENT для связанных параметров.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...