Guardar datos en la base de datos sqlite3 en Swift

Oct 16 2020

Estoy trabajando en una aplicación que usa PencilKit. Estoy tratando de guardar el dibujo PK en forma de datos en una base de datos sqlite3 pero no se está guardando. Supongo que el problema es con la función de guardar, no con la que obtiene los datos del dibujo para mostrar porque la fila del dibujo en la base de datos está vacía cuando consulto directamente en la terminal.

func save(canvas: Canvas) {
    // connect to database
    connect()
    
    // canvas.drawing is already in the form of data not PK drawing here
    let drawingData = canvas.drawing
    
    drawingData.withUnsafeBytes { drawingBuffer in
        
        let drawingPtr = drawingBuffer.baseAddress!

        var statement: OpaquePointer!
        
        if sqlite3_prepare_v2(database, "UPDATE drawings SET drawing = ? WHERE rowid = ?", -1, &statement, nil) != SQLITE_OK {
            print("Could not create (update) query")
        }
        
        sqlite3_bind_blob(statement, 1, drawingPtr, -1, nil)
        sqlite3_bind_int(statement, 2, Int32(canvas.id))
        
        if sqlite3_step(statement) != SQLITE_DONE {
            print("Could not execute update statement")
        }
        
        sqlite3_finalize(statement)

    }
}

Respuestas

2 Rob Oct 16 2020 at 13:01

Algunas observaciones:

  1. Con sqlite3_bind_blob, el cuarto parámetro es el tamaño, que se requiere y no debe ser negativo. Con sqlite3_bind_text, puede proporcionar un -1valor porque las cadenas C tienen terminación nula y puede averiguar dónde termina la cadena, pero no puede hacerlo con un blob.

    Como dice la documentación :

    Si el cuarto parámetro sqlite3_bind_blob()es negativo, entonces el comportamiento no está definido.

    Así, quizás:

    guard let blob = drawingBuffer.baseAddress else { return }
    let count = Int32(drawingBuffer.count)
    

    Y entonces:

    sqlite3_bind_blob(statement, 1, blob, count, nil)
    
  2. Además, si falla una llamada SQLite, debe imprimir el error; de lo contrario, está volando a ciegas, por ejemplo

    let errorMessage = sqlite3_errmsg(database).map { String(cString: $0) } ?? "Unknown error"
    print("failure preparing UPDATE statement: \(errorMessage)")
    

    Debe hacerlo siempre que verifique un código de retorno de SQLite. A menudo, esto hará que sea mucho más fácil diagnosticar por qué falló una llamada.