2015-04-30 10 views
5

Ho il seguente pezzo di codice che utilizza Sqlite3 su Ubuntu (C++):C++ sqlite3_exec in grado di chiudere a causa di dichiarazioni non finalizzati

void test_function(dbHandler) 
{ 
    char *retError = 0; 

    std::string sql("INSERT INTO LOG (LAST_CHANGED_DATE_TIME) VALUES ('TEST');"); 

    int returnStatus = sqlite3_exec(dbHandler, sql.c_str(), 0, 0, &retError); 

    std::cout << "RetStatus = " << returnStatus << "; " << retError << s 

    if (returnStatus == SQLITE_OK) 
     return sqlite3_changes(dbHandler); 
    else 
    { 
     sqlite3_free(retError); 
     sqlite3_close(dbHandler); 
    } 
} 

Il sqlite3_exec dichiarazione sql è fatto male per testare il suo comportamento failture (in quel caso il nome del campo non corrisponde). Ottengo uno stato corretto da sqlite3_exec come:

Status = 1; table Log has no column named last_changed_date_time 

Come è un errore, ho bisogno di liberare il messaggio di errore (retError) e chiudere la connessione al database. E qui è dove ho un problema:

Quando si chiama sqlite3_close, sto ottenendo il seguente messaggio di eccezione:

unable to close due to unfinalized statements or unfinished backups 

Ive sfogliati intorno sqlite3 docs e non poteva scoprire che cosa io non sono liberando qui ...

sulla base di che ho bisogno di aiuto per:

a) Fissare il codice di cui sopra.

b) Comprendere il modo corretto per ripristinare da sqlite3_exec in caso di errore.

Grazie per l'aiuto.

+1

Mostra tutte le altre chiamate DB eseguite tra l'apertura del database e questa funzione. –

+0

L'unica cosa che faccio è emettere un 'SELECT COUNT (*) FROM LOG' usando la stessa struttura' sql_exec' ... Sto pensando che questo potrebbe essere il problema ... – Mendes

+0

Le istruzioni non finalizzate sono finalizzate con ['sqlite3_finalize (sqlite3_stmt *)'] (https://www.sqlite.org/capi3ref.html#sqlite3_finalize) e i backup non finiti sono terminati con ['sqlite3_backup_finish()'] (https: // www.sqlite.org/capi3ref.html#sqlite3backupfinish). Ci si può aspettare che finisca in questo stato da una precedente chiamata 'sqlite3_'. Si prega di fornire un [mcve] (http://stackoverflow.com/help/mcve). – YSC

risposta

1

a) La linea di uscita che dovrebbe terminare con std::endl;. L'argomento dbHandler deve avere un tipo. Una funzione void non può non restituire un valore. Tuttavia, per quanto riguarda l'uso di sqlite3 api, il codice pubblicato è corretto.

b) In caso di errore, sqlite3_exec eseguirà il ripristino. Hai solo bisogno di liberare la memoria indicata da retError, usando sqlite3_free, che stai già facendo.

Di seguito è riportato un esempio di funzionamento minimo con i 3 errori descritti. Mostra che è corretto (l'output della "routine di libreria chiamata fuori sequenza" è perché non è possibile chiamare sqlite3_errmsg su un handle di database chiuso), poiché non produce l'errore che si descrive. Quindi, se sqlite3_close fallisce, è a causa di un errore altrove nel tuo programma.

L'errore che si descrive può essere riprodotto decommentando le 3 righe commentate. La dichiarazione che verrà quindi creata da sqlite3_prepare non verrà eliminata da una chiamata a sqlite3_finalize e pertanto sqlite3_close causerà l'errore "Impossibile chiudere a causa di istruzioni non finalizzate o backup incompleti". Il tuo errore è probabilmente causato da qualcosa di simile.

#include <iostream> 
#include <sqlite3.h> 

void test_function(sqlite3 * dbHandler) 
{ 
    char *retError = 0; 

    std::string sql("INSERT INTO LOG (LAST_CHANGED_DATE_TIME) VALUES ('TEST');"); 

    int returnStatus = sqlite3_exec(dbHandler, sql.c_str(), 0, 0, &retError); 

    std::cout << "RetStatus = " << returnStatus << "; " << retError << std::endl; 

    if (returnStatus == SQLITE_OK) 
     return; // sqlite3_changes(dbHandler); 
    else 
    { 
     sqlite3_free(retError); 
     sqlite3_close(dbHandler); 
    } 
} 

int main() 
{ 
    sqlite3 * dbHandler; 
    sqlite3_open("test.sqlite", &dbHandler); 
    sqlite3_exec(dbHandler, "CREATE TABLE LOG (DUMMY);", 0, 0, 0); 

    // sqlite3_stmt * test; 
    // const char * sql = "INSERT INTO LOG (DUMMY) VALUES ('TEST');"; 
    // sqlite3_prepare(dbHandler, sql, -1, &test, 0); 

    test_function(dbHandler); 

    std::cout << "Last error: " << sqlite3_errmsg(dbHandler) << std::endl; 
    return 0; 
} 
+0

Lo prenderò (non sono OP), tuttavia vorrei dire che è possibile premere 'impossibile chiudere 'senza una chiamata esplicita a' sqlite3_prepare() 'in qualsiasi punto del programma; il mio utilizzo era completamente diverso, eppure questa domanda era la più vicina a cercare su questo codice di errore. Quindi la taglia. Forse si tratta di "preparare" qualcosa per te quando non te lo aspetti? –

1

Dal momento che sto rivisitando sqlite3 in quanto l'aggiornamento dopo 10 anni sono riuscito ad ottenere il messaggio di cui sopra. Ho fatto uno sqlite3_open_v2 e poi uno sqlite3_close e ho ricevuto lo stesso messaggio. sqlite3_close_v2 evita il messaggio.

Piccolo errore idiota, ma forse utile a qualcuno.

Problemi correlati