Как обновить столбец в таблице SQLite в программе Swift? - PullRequest
2 голосов
/ 01 апреля 2020

Вот код, который у меня есть, который вылетает во время выполнения при первой привязке:

func update(time: Date) throws {
    let sql = "UPDATE Entrys SET date = ? WHERE id = ?"  //Questionable
    guard let update = try db.prepareStatement(sql: sql) else { throw SQLiteError.prepare }
    sqlite3_finalize(update)

    let iso8601Time = ISO8601Time(date: time)
    guard sqlite3_bind_text(update, 1, iso8601Time.concise(), -1, SQLITE_TRANSIENT) == SQLITE_OK else { throw SQLiteError.bind }  //Throws error here

    guard sqlite3_bind_int(update, 2, Int32(id)) == SQLITE_OK else { throw SQLiteError.bind }

    guard sqlite3_step(update) == SQLITE_ROW else { throw SQLiteError.step }
}

ISO8601Time - это объект для преобразования между Text и Swift.Date, он работает в другом коде, куда я вставляю.

Документы мне не помогают.

Возможно, мой синтаксис SQL неверен. Я не нашел надежного примера в Интернете.

Пожалуйста, сообщите.

=)

Редактировать 1:

Я подтвердил, что работает следующий код в редакторе sqlite терминала. Что похоже на приведенную выше форму

Update Entrys SET date = "test" WHERE id = 1;

Я также подтвердил, что мои sqlite3_bind_text и sqlite3_bind_int работают в других функциях, которые тестируются и проходят модуль. Я не уверен, как перенести этот синтаксис в ОБНОВЛЕНИЕ, и документы не имеют ничего, что я нашел до сих пор.

РЕДАКТИРОВАТЬ 2:

Следующее показывает синтаксис SQLite для вставки, которая работает и имеет несколько параметров и может помочь решить проблему.

func add(date: Date, confirmed: Bool, scale: Int, measurement: SQLMeasurement) throws -> SQLEntry {
    let sql = "INSERT INTO Entrys (date, confirmed, scale, measurementID) VALUES (?,?,?,?);"
    guard let insert = try? db.prepareStatement(sql: sql) else { fatalError() }
    defer { sqlite3_finalize(insert) }

    let iso8601Time = ISO8601Time(date: date)
    guard sqlite3_bind_text(insert, 1, iso8601Time.concise(), -1, SQLITE_TRANSIENT) == SQLITE_OK else { throw SQLiteError.bind }

    var bool: Int    //FIXME: Vars are trouble
    if confirmed { bool = 1 }
    else { bool = 0 }
    guard sqlite3_bind_int(insert, 2, Int32(bool)) == SQLITE_OK else { throw SQLiteError.bind }

    guard sqlite3_bind_int(insert, 3, Int32(scale)) == SQLITE_OK else { throw SQLiteError.bind }
    guard sqlite3_bind_int(insert, 4, Int32(measurement.id)) == SQLITE_OK else { throw SQLiteError.bind }

    guard sqlite3_step(insert) == SQLITE_DONE else { throw SQLiteError.step }
    let lastId = db.lastId()
    return SQLEntry(id: lastId, db: db)
}

Ответы [ 2 ]

2 голосов
/ 09 апреля 2020

Правильный порядок:

  • создать подготовленный оператор
  • привязать значения к параметрам
  • запустить SQL
  • уничтожить объект, чтобы избежать утечек ресурсов (с помощью sqlite3_finalize(stmt))

Вы создаете подготовленный оператор и немедленно удаляете его, но затем получаете доступ к нему, что приводит к взлому sh.

Документация:

Функция sqlite3_finalize () вызывается для удаления подготовленного оператора.

см. https://www.sqlite.org/c3ref/finalize.html

2 голосов
/ 04 апреля 2020

На самом деле вам нужно передать строку utf8 с нулевым символом в конце sqlite3_bind_text. Это можно сделать следующим образом:

let iso8601TimeStr = iso8601Time.concise() as NSString
guard sqlite3_bind_text(update, 1, iso8601TimeStr.UTF8String, -1, SQLITE_TRANSIENT) == SQLITE_OK else { throw SQLiteError.bind }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...