Salvataggio dei dati nel database sqlite3 in Swift

Oct 16 2020

Sto lavorando a un'app che utilizza PencilKit. Sto cercando di salvare il disegno PK sotto forma di dati in un database sqlite3 ma non viene salvato. Presumo che il problema sia con la funzione di salvataggio, non quella che recupera i dati del disegno da visualizzare perché la riga del disegno nel database è vuota quando eseguo una query direttamente nel terminale.

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)

    }
}

Risposte

2 Rob Oct 16 2020 at 13:01

Alcune osservazioni:

  1. Con sqlite3_bind_blob, il quarto parametro è la dimensione, che è richiesta e non deve essere negativa. Con sqlite3_bind_text, puoi fornire un -1valore perché le stringhe C hanno terminazione null e può capire dove finisce la stringa, ma non può farlo con un BLOB.

    Come dice la documentazione :

    Se il quarto parametro sqlite3_bind_blob()è negativo, il comportamento non è definito.

    Quindi, forse:

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

    E poi:

    sqlite3_bind_blob(statement, 1, blob, count, nil)
    
  2. Inoltre, se una chiamata SQLite fallisce, dovresti stampare l'errore, altrimenti stai andando alla cieca, ad es

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

    Dovresti farlo ogni volta che controlli un codice di ritorno SQLite. Spesso questo renderà molto più facile diagnosticare il motivo per cui una chiamata non è riuscita.