Próbka kodu, z jakim się zmagałem przez dłuższy czas:

[mysz@urzenia ~/p/python/mtalog]% python2.5
Python 2.5.1 (r251:54863, May  2 2007, 16:56:35)
[GCC 4.1.2 (Ubuntu 4.1.2-0ubuntu4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sqlite3
>>> db = sqlite3.connect(':memory:')
>>> cur = db.cursor()
>>> cur.execute('BEGIN')
<sqlite3.Cursor object at 0x40201f80>
>>> cur.execute('CREATE TABLE `test` (`id` INTEGER PRIMARY KEY, data TEXT)')
<sqlite3.Cursor object at 0x40201f80>
>>> cur.execute('COMMIT')
<sqlite3.Cursor object at 0x40201f80>
>>> cur.execute('BEGIN')
<sqlite3.Cursor object at 0x40201f80>
>>> cur.execute('INSERT INTO `test` (`data`) VALUES ("asd")')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
sqlite3.OperationalError: SQL logic error or missing database
>>> 

Co bym nie zrobił, wysypywało się albo z powyższym wiele mówiącym błędem, albo też chodziło czysto, a po zakmnięciu połączenia (oczywiście nie mówię tutaj o bazie testowej założonej w ramie, jak w przykładzie) baza była pusta. Nawalczyłem się z tym nieco… a rozwiązanie, jak to w życiu, jest banalne.

pysqlite działa natywnie w takim pseudo-trybie autocommita. Nieco próba automatyzacji. Generalnie polega to mniej więcej na tym, że sam zaczyna transakcję jeśli trafi na polecenie INSERT/UPDATE/DELETE/REPLACE, ale w sumie nie doczytałem kiedy ją kończy. Mało mnie to interesuje, bo ja chcę ręcznie zaczynać i kończyć transakcje, a automatyzacja w/w zawiodła (jak pisałem: po zakończeniu połączenia danych w bazie niet :/ ).

Aby kontrolować tryb w jakim pysqlite rozpoczyna i kończy transakcje, potrzeba zmienić wartość właściwości isolation_level naszego połączenia z bazą. W moim przypadku najbardziej pasująca wartość to None, w związku z czym nawiązanie połączenia z bazą będzie wyglądało w ten sposób:

[...]
        self.db.connect ( '/path/to/db.sqlite3' )
        self.db.isolation_level = None
[...]

Od tego momentu sqlite czyna tańczyć jak mu każemy, czyli możemy ręcznie rozpoczynać transakcję, wybierać jej rodzaj, kończyć transakcję czy też ją ROLLBACKnąć etc. W końcu…

A niniejszy wpis dedykuję wszystkim którzy podobnie jak ja walczyli przez kilka/kilkanaście godzin nad taką głupotą :/


Zacząłem się bawić trochę w prostą aplikację wykorzystującą sqlite. Powody 2:

  1. chciałem poznać co nieco sqlite;
  2. muszę sobie wymyślać jakieś zadania jeśli chcę się tego języka jako tako nauczyć :)

No i wczoraj miałem niezłą zagwozdkę. W pliku .cpp stało jak byk:

#include <sqlite3.h>

a ten przy kompilacji gotowca z dokumentacji sqlite wywala błędy, że nie znajduje funkcji sqlite3_open() i innych. Porażka. Spędziłem nad tym ponad godzinę dzień wcześniej, i dopiero wczoraj wieczorem udalo mi sie dojść do tego, że poza dodaniem pliku nagłówkowego w żródłach, trzeba powiedzieć kompilatorowi (w moim przypadku gcc), że ma użyć biblioteki, w której zawarte są potrzebne funkcje. Wywołanie kompilatora wobec tego wyglądało tak:

% g++ t1.cpp -o t1 -lsqlite3

i od tego momentu zaczęło działać jak należy.

Dziś, uzbrojony w nową wiedzę, spróbowałem tego samego na Windowsie w Sądzie więzieniu. Do diabła, znów spędziłem godzinę na tym, żeby sie doszukać jak tam ma to wyglądać. Najpierw buszując w opcjach używanego przeze mnie IDE (co mi się w końcu udało), a później ręcznie, wykorzystując wspomniane wczesniej gcc. Teoretycznie proste, nie ? W domu się udało, też gcc, więc co za problem ? Heheh, w sumie proste, jak sie już wie… najpierw trzeba zapodać mu gdzie szukać pliku nagłówkowego do sqlite (w moim wypadku było to: c:\Programy\Dev-Cpp\include\M), a później, oczywiście innym parametrem niż pod Linuksem (bo jakżeż by to mogłoby być inaczej) wskazać ścieżkę do .dll sqlite3. W sumie całość, wrzucona przeze mnie do .bata, wygląda mniej więcej tak:

g++ note.cpp -o note.exe -Ic:\Programy\Dev-Cpp\include\M -Wl,lsqlite3

albo podobnie, mam to w pracy, więc nie mogę teraz podejrzeć jak to tam wygląda ;) jeśli nakłamałem, to postaram się jutro to uaktualnić.

PS. W gotowcu, którego adres dałem powyżej, jest jeden błąd: brakuje odwołania do pliku nagłówkowego stdlib.h, który zawiera definicję funkcji exit(). Bez tego kompilator, oczywiście słusznie, wywala błędy. Linijka, którą trzeba dodać, wygląda tak:

#include <stdlib.h>