Mi succede un fatto assai strano. Nel mio programma ho inserito la seguente istruzione di inserimento dati in una tabella, definita con "Primary key", composta da due colonne contigue, la prima e la seconda di ciascuna riga:
DB_Connection.EXEC("INSERT INTO Movimgg VALUES(" & Val(Colonna1_Key1) & ", '" & Colonna2_Key2 & "', '" & Colonna3 & "', '" & Colonna4 & "', '" & Colonna5 & "', '" & Colonna6 & "', '" & Colonna7 & "', '" & Colonna8 "')")
DB_Connection.Commit
Ebbene il programma sembra eseguire l'istruzione EXEC senza dare errori e va avanti come se tutto fosse andato bene, ma in effetti non ha inserito il record. Detta istruzione è copiata da un'altra simile che svolge il lavoro di inserimento dati in una tabella diversa, in un altro passo del programma. Lì il lavoro viene svolto veramente e bene, tanto che stavo cominciando a fare amicizia con SQLite3. È da ieri che sbatto il muso su codesta istruzione e non riesco a venirne fuori. Oggi ho fatto un'altro tentativo: ho scritto un programmino semplicissimio che cerca la tabella "movimgg" se la trova la cancella e la ricrea, inserendovi dopo un solo record.
Risultato: nessun problema la tabella è validimante valorizzata col record inserito con la stessa istruzione scritta sopra.
Ritornando al problema, la connessione è aperta bene; ho guardato in debug la finestra DB_Connection ed ho visto che il DB è puntato come dovuto.
Debbo anche dire alcune istruzioni prima interrogo un'altra tabella del DB, da cui prelevo un codice che devo trascrivere nella tabella "Movimgg" per realizzare il collegamento fra le due tabelle; quella lettura si svolge con successo. Ma allora che succede?
Spero che mi possiate accendere la lampadina.
Ciao a tutti.
Ho notato che spesso le funzioni di gestione dei DB di Gambas sono un pò capricciose.
Hai provat a riaprire la connessione proprio prima di eseguire l'istruzione incriminata?
Non so se hai notato le istruzioni, riportate come commento, subito prima dell'istruzione INSERT
'--------------------------------------------------------------------- istruzioni aggiunte in prova, ma poi tolte perchè la open viene ignorata ------------------------------
'DB_Connection.CLOSE 'chiude il DB
'WITH DB_Connection
' .Name = DBname
' .Open 'Riapro il DB
'END WITH
'--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
È una prova che ho eseguito, ma ho dovuto abbandonarle subito perchè il programma si comporta come se non eseguisse la open del DB; infatti produce il seguente errore:
Query failed: the database file is locked
:o
Ciao.
Riguardando il tuo codice ed alcuni miei programmi vedo che io opero in maniera differente.
Non mi affido alle query SQL lanciate con Connection.EXEC ma preferisco usare i metodi di Gambas e poi, anche a costo di sembrare ripetitivo, inserisco una ben precisa sequenza di istruzioni.
Io riscriverei il pezzo incriminato così:
DIM Connessione as NEW Connection
DIM Risultato as Result
'-- apre il DB
WITH Connessione
.Name = NOME_DB
.Type = "sqlite3"
.Open
END WITH
Connessione.Begin
Risultato = Connessione.Create("mivimgg")
Risultato[CAMPO1]=DATO1
Risultato[CAMPO2]=DATO2
......
Risultato[CAMPOn]=DATOn
Risultato.Update
Connessione.Commit
Connessione.CLOSE
@Leo:
Supponiamo che la tua idea pratica, ma non rispondente ai miei disegni, sia da applicare, perchè l'unica presumibile funzionante, vorrei invitarti a ragionare sul comportamento strano del programma anche a livello delle seguenti istruzioni:
DB_Connection.Begin
TRY RecTab = DB_Connection.EXEC("SELECT * FROM piancont WHERE NomeVoce LIKE '%" & $_VoceConto & "%'") «« funziona benissimo
DB_Connection.CLOSE «« funziona benissimo
WITH
DB_Connection
.Type = "sqlite3"
.Host = FMain.DB_path
.Login = ""
.Password = ""
.Name = FMain.DBname
.Open 'Riapro il DB «« Non funziona .................... pur essendo un'istruzione SQL
END WITH
Io non riesco a spiegarmelo, perchè in altre parti del programma utilizzo sequenze di quel tipo, cioè con Close ed Open in successione e funzionano sempre a meraviglia. Quindi se c'è un'anomalia in quel punto, la spiegazione è: commetto io un errore in quel passo di programma, oppure qualche meccanismo di Gambas non funziona.
Ti ho espresso il mio pensiero da modestissimo programmatore, inesperto di tecnicismi costruttivi di linguaggi di programmazione; spero solo che debba io aggiustare qualcosa; solo che, se è così, non ho capito ancora cosa.
Ciao
non utilizzare la connessione come variabile globale ma inizializzarla in ogni funzione.
1) se in qualche parte del codice in una funzione ti sei dimenticato di chiudere il db questo viene chiuso automaticamente alla chiusura della funzione
Quindi tui dici di dichiarala all'interno di ciascuna SUB così:
DIM DB_Connection AS NEW Connection
in modo tale ogni uscita da una sub qualsiasi, a chiudere il DB, eventualmente dimenticato aperto, ci pensa automaticamente Gambas.
Spero di avere capito e procedo così. Vi farò sapere.
Ciao :)
È successo quello che immaginavo, cioè non è cambiato niente, o quasi: Infatti l'errore che mi dava e che mi da non fa pensare ad un close non eseguita, bensì ad una open mancante. Il messaggio di ERRORE è cambiato ed è cambiato pure il punto dove si manfesta:
Unable to commit transaction: The database file is locked
Ecco il codice della Form2.class modificato
PUBLIC SUB MovDigOk_Click()
DIM DB_Connection AS NEW Connection 'inizializza la nuova connessione
DIM b_nupro AS Byte
DIM f_ImpMov AS Float
DIM i_Som AS Integer
DIM i_CoVoContab AS Integer
DIM i_data AS Integer
DIM i_ImpMov AS Integer
DIM i_orario AS Integer
DIM i_RgGriMov AS Integer
DIM $_Benef AS String
DIM $_Como AS String
DIM $_Data AS String
DIM $_Descr AS String
DIM $_GG AS String
DIM $_MM AS String
DIM $_AA AS String
DIM $_orario AS String
DIM $_ora AS String
DIM $_minuti AS String
DIM $_secondi AS String
DIM $_Moneta AS String
WITH
DB_Connection
.Type = "sqlite3"
.Host = FMain.DB_path
.Name = FMain.DBname
.OPEN 'Apro il DB
END WITH
IF $_DescrUlt <> "" THEN
$_TabNewDescr.Add($_DescrUlt)
$_DescrUlt = ""
ENDIF
IF ImpMovDig.Text = "" THEN
ImpMovDig.SetFocus
ELSE
IF DescrMovDig.Text = "" THEN
DescrMovDig.SetFocus
ELSE
IF SegnoEU.Text = "" THEN
SegnoEU.SetFocus
ELSE
i_RgGriMov = 0
DO UNTIL GriMovv[i_RgGriMov, 1].text = ""
INC i_RgGriMov
IF i_RgGriMov > GriMovv.Rows.count THEN
BREAK
ENDIF
LOOP
SELECT CASE SegnoEU.Text
CASE "E", "U"
GriMovv[i_RgGriMov, 1].text = VoContMoDig.Text
GriMovv[i_RgGriMov, 5].text = BenefMovG.Text
CASE ELSE
GriMovv[i_RgGriMov, 1].text = CreDebMovG.text
END SELECT
GriMovv[i_RgGriMov, 2].text = DescrMovDig.Text
'$_StriMia = Modulivari.LevEditing($_StriMia)
$_Como = ModuliVari.LevEditing(ImpMovDig.Text)
i_Posiz = InStr($_Como, ",")
IF i_Posiz <> 0 THEN
$_Como = Left($_Como, i_Posiz - 1) & "." & Right($_Como, 2)
ENDIF
f_ImpMov = CFloat($_Como)
SELECT CASE SegnoEU.Text
CASE "E", "D"
GriMovv[i_RgGriMov, 3].text = ImpMovDig.Text
i_TotEntrate += i_ImpMov
CASE ELSE
GriMovv[i_RgGriMov, 4].text = ImpMovDig.Text
i_TotUscite += i_ImpMov
END SELECT
'---------------------------- rilevo il codice di Voce contabile dalla Tabella piancont ---------------------------------------
i_Posiz = RInStr(VoContMoDig.Text, " » ") + 3
i_LuFix = Len(VoContMoDig.Text) - i_Posiz
PRINT "«" & VoContMoDig.Text & "»"
PRINT Len(VoContMoDig.Text)
PRINT "«" & Left(VoContMoDig.Text, 17) & "»"
PRINT "«" & Right(VoContMoDig.Text, i_LuFix) & "»"
$_VoceConto = Right(VoContMoDig.Text, i_LuFix)
DB_Connection.Begin
TRY RecTab = DB_Connection.EXEC("SELECT * FROM piancont WHERE NomeVoce LIKE '%" & $_VoceConto & "%'")
IF ERROR THEN
Message.ERROR("Attenzione! -> " & ERROR.Text & Chr(10) & Chr(10) & "durante la lettura della Tabella ContabFam.db!piancont'" & Chr(10) & Chr(10) & " il programma verrà chiuso")
FMain.Close
ENDIF
i_CoVoContab = RecTab!NumVoce
i_data = Val(ModuliVari.$_DataCont)
'--------
'--------------------------------------- routinetta di conversione dell'orario corrente in hhmmss (2 crt per ciascun sottocampo
$_ora = Hour(Now)
IF Len($_ora) = 1 THEN $_ora = "0" & $_ora
$_minuti = Minute(Now)
IF Len($_minuti) = 1 THEN $_minuti = "0" & $_minuti
$_secondi = Second(Now)
IF Len($_secondi) = 1 THEN $_secondi = "0" & $_secondi
$_Data = $_AA & $_MM & $_GG
$_orario = $_ora & $_minuti & $_secondi
i_orario = Val($_orario)
b_nupro = CByte(GriMovv[i_RgGriMov, 0].text)
SELECT CASE SegnoEU.Text
CASE "U", "A"
f_ImpMov = f_ImpMov * (-1)
i_Totel = BenefMovG.Count
FOR i_Som = 0 TO i_Totel - 1
IF BenefMovG.List[i_Som] = BenefMovG.Text THEN
$_Benef = Str(i_Som + 1)
BREAK
ENDIF
NEXT
'---------------------------------------------------------------------------------------------------------------------------------------
'--------
$_Descr = DescrMovDig.Text
$_Moneta = ModuliVari.$_TipoValuta
TRY DB_Connection.EXEC("INSERT INTO movimgg VALUES(" & i_data & ", '" & i_orario & "', '" & b_nupro & "', '" & i_CoVoContab & "', '" & $_Descr & "', '" & $_Moneta & "', '" & f_ImpMov & "', '" & $_Benef & "')") '»» Istruzione superata come se fosse stata eseguita bene
IF ERROR THEN
Message.ERROR("Attenzione! -> " & ERROR.Text & Chr(10) & Chr(10) & "durante l'inserimento record nella Tabella ContabFam.db!movimgg'" & Chr(10) & Chr(10) & " il programma verrà chiuso")
FMain.Close
ELSE
DB_Connection.Commit '»» Istruzione dove si manifesta l'errore
ENDIF
ME.ResetAreaDigMov()
ENDIF
ENDIF
ENDIF
END
Come puoi vedere non esiste alcuna close, eppure, sempre più stranamente , la "INSERT INTO movimgg" non produce errore, ma lo produce la "Commit", come se fra la "Insert" e la "Commit" ci fosse una "CLOSE"
Io non so più che cosa fare ..... :'(
Mi resta da provare una cosa sola: svuotatre tutta la Form2.class delle istruzioni presenti; poi rimetterle piano piano tutte, partendo da valori precostituiti e dalle sole "INSERT INTO" e "COMMIT". Se questa non dovesse funzionare, posso solo prendere l'aliscafo per Marettimo e buttare tutto il prgramma in alto mare! ... Sig! sig!
Ciao a tutti.
togli il connection.begin, lascia solo l' open , fai la tua lettura, quando hai finito di leggere tutti i dati prova a dare un close e poi prima di inserire la tabella dai un open, cerca di racchiudere operazioni di diverso genere su un db tra un open e un close, se modifichi la struttura o i dati devi dare anche un commit e in alcuni casi anche ub update del result
Ho fatto tutto come mi hai detto ed è tornato l' errore sull'istruzione "INSERT INTO":
Query failed: the database file is locked
Ho allora posto prima di quell'istruzione un'istruzione di test sulla tabella:
IF NOT DB_Connection.Tables.Exist("movimgg") THEN ' Verifica l'esistenza della Tabella "PIanCont"
Message.ERROR("Attenzione! -> ERRORE" & Chr(10) & Chr(10) & " '" & ERROR.Text & "'" & Chr(10) & Chr(10) & "La Tabella ContabFam.db!movimgg' è inesistente")
ENDIF
Ebbene il risultato non è cambiato; il programma esegue il test senza dare errore e poi da errore sempre alla stessa istruzione:
DB_Connection.EXEC("INSERT INTO movimgg VALUES(" & i_data & ", '" & i_orario & "', '" & b_nupro & "', '" & i_CoVoContab & "', '" & $_Descr & "', '" & $_Moneta & "', '" & f_ImpMov & "', '" & $_Benef & "')")
Sicuramente il problema à lì dentro, ma come superare l'ostacolo?
Come avrai visto in qualche post precedente e nel sorgente che ti ho fatto pervenire, le colonne riportate nell'INSERT sono tutte quelle della tabella.
Secondo te quell'istruzione è scritta bene? Io non so più cosa fare....... :'( :'( :'(
Ciao.
Vediamo se l'ho beccato!
Allora... tu inserisci i dati creando una concatenazione di stringhe con il comando &... però penso che ti dia l'errore perché vuoi concatenare ad una stringa un intero, ad esempio i_data, o un byte, ad esempio b_nupro.
Prova a convertirli prima tutti in stringa.
Cioè:
..... VALUES(" & trim(str(i_data)) & ", '" & trim(str(i_orario)) & "', '" & trim(str(b_nupro)) & "......
@fsurfing:
Stamattina ho provato a spostare l'INSERT INTO in una nuova classe, ma il risultato, purtroppo non cambia. Ecco l'esito delle prove (ho riportato solo le istruzioni essenziali):
DB_Connection.Type = "sqlite3"
DB_Connection.Host = FMain.DB_path
DB_Connection.Name = FMain.DBname
DB_Connection.Open
DB_Connection.Begin
DB_Connection.EXEC(sql)
DB_Connection.CLOSE
Cioè, ripetendo le istruzioni preparate da te (con Begin e senza Commit), il programma procede senza dare errori, ma non registra il record nella tabella.
DB_Connection.Type = "sqlite3"
DB_Connection.Host = FMain.DB_path
DB_Connection.Name = FMain.DBname
DB_Connection.Open
DB_Connection.Begin
DB_Connection.EXEC(sql)
DB_Connection.Commit
DB_Connection.CLOSE
Inserendo la Commit provoca Errore di DB chiuso alla Commit.
DB_Connection.Type = "sqlite3"
DB_Connection.Host = FMain.DB_path
DB_Connection.Name = FMain.DBname
DB_Connection.Open
DB_Connection.EXEC(sql)
DB_Connection.Commit
DB_Connection.CLOSE
Togliendo la Begin e lasciando la Commit, l'Errore di DB chiuso lo da già alla .EXEC(sql).
E veramente diventato un percorso senza via d'uscita. Ora provo a trasformare la classe in modulo, anche se con molto scetticismo. Dopo di che, resta solo la possibilità di chiamare un'altro programma o forse una funzione shell. Intanto sono già trascorsi 6 giorni dalla prima manifestazione di errore ed il mio programma è ancora fermo, mentre dovrei essere alle fasi di prova del Form5.class. Però non mi sto lamentando con nessuno di Voi che state cercando di darmi veramente una grossa mano, ma delle stranezze che riscontro. :(
Ciao.