title image


Smiley Re: Anwendung
Hi, habe ich doch schon.

Aber hier mal Step by Step:



1. Sql3.dll auf die Aktuelle sqlite3.dll "aufsetzen" (sql3.dll behandelt die sqlite3 nämlich wie ein PlugIn).





'Vorausetzung/Deklaration:



Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" ( _

ByVal lpLibFileName As String) As Long



Private Declare Function FreeLibrary Lib "kernel32" ( _

ByVal hLibModule As Long) As Long



Private Declare Function SetModuleFilename Lib "sql3.dll" ( _

ByVal sFileName As String) As Long



Private Declare Function GetModuleFileName Lib "kernel32.dll" Alias "GetModuleFileNameA" ( _

ByVal hModule As Long, _

ByVal lpFileName As String, _

ByVal nSize As Long) As Long





'Anwendung

Dim hModule As Long

Dim sFBuffer As String * 256



hModule = LoadLibrary(sqlite3.dll")

If hModule = 0 Then

'Error -> sqlite3.dll nicht installiert!

End If



GetModuleFileName hModule, sFBuffer, Len(sFBuffer)

SetModuleFilename Trim(sFBuffer)



FreeLibrary hModule



2. Öffnen der Datenbank. Existiert die Datenbank, wird sie geöffnet und ein

Handle darauf zurückgegeben. Existiert die Datenbank nicht, wird einfach eine

Neue Datenbank erstellt. Wird die Datenbank so benannt: ":MEMORY:" Kommt ein

geniales Feature zum Einsatz: Eine Datenbank die nur im Speicher exisitert!

Das Handle muss man sich merken, deshalb ist es global.



'Voraussetzung/Deklaration

Private Declare Function SqlOpen Lib "sql3.dll" ( _

ByVal sFileName As String, _

pSql As Long) As Long



Private Declare Function SqlClose Lib "sql3.dll" ( _

ByVal pSql As Long) As Long



'In einem Modul

Public hDBase As Long



If hDBase Then SqlClose hDBase

SqlOpen "Name_Pfad_der_Datenbank_oder_eine_Neue", VarPtr(hDBase)



Es bietet sich an, hDBase in einer Klasse zu beaufsichtigen um ggf. einen

Verlust des Handle zu kontrollieren. Ist hDBase 0 sie hat man Zugriff auf die

Datenbank.



3. Bau einer DBExecute-Methode



Was kommt ist eine Designfrage: Habe ich einen FileServer oder Client?! Sqlite3 ist

nämlich ein Server, den kann ich via Callback steuern oder multible Zugriffe einfach

in einem Do ... Loop fahren. Ich gehe immer von einem FileServer aus und steuere die

Zugriffe in einer einfachen Schleife. Grund: sqlite3 verwendet intern Threadzugriffe,

die besonders Resourcenschonend die CPU-Last behandeln.

So kann man sich eine Funktion nachbauen, die der Methode: DBExecute entspricht. Genau das Szenario wrappt auch die sql3.dll. Sprich: Über diese Funktion läuft alles, was keinen Recordset erzeugt, wie: CREATE Table, Drop Table, Update, Insert, u.s.w.,

nicht SELECT! dafür gibt es was ganz besonderes ;)





'Voraussetzung/Deklaration:

Private Const SQLITE3_DONE As Long = 101



Private Declare Function SqlPrepare Lib "sql3.dll" ( _

ByVal pSql As Long, _

ByVal sSQL As String, _

hStmt As Long) As Long



Private Declare Function SqlStep Lib "sql3.dll" ( _

ByVal hStmt As Long) As Long



Private Declare Function SqlExec Lib "sql3.dll" ( _

ByVal ppHD As Long, ByVal sSQL As String, _

ByVal ppAdr As Long, sarg As Long, err As String) As Long



Public Function DBExecute (Byval sSQL As String) As Boolean

Dim rVal As Long

Dim hStmt As Long

Dim f As Integer



If hDBase = 0 Then Exit Function



'Das SQL-Kommand wird auf Syntax geprüft und in ein Byteaarray geformelt

rVal = SqlPrepare(hDBase, sSQL, VarPtr(hStmt))



If rVal = 0 Then

'Warten bis DB "unbusy" ist ;)

Do

rVal = SqlStep(hStmt)

Loop While rVal SQLITE3_DONE

'Den Käse wieder aufräumen ...

SqlFinalize hStmt

Else

MsgBox sSQL, vbExclamation, "Fehler in der SQL-Anweisung!"

Exit Function

End If



DBExecute = True

End Function



4. Anlegen einer einfachen Tabelle mit Primary Key. Beachte: Sqlite3.dll hat

einige geschützte Begriffe die nie als Tabellenamen verwendet werden dürfen!





'Voraussetzung keine, wenn die DBExecute - Funktion angelegt wurde

Dim SQL As String



SQL = "CREATE TABLE " & sFileName & " (ID INTEGER PRIMARY KEY, "

SQL = SQL & "FName varchar(200), " 'Ein String mit 200 Bytes

SQL = SQL & "VName varchar(100), "

SQL = SQL & "GDatum varchar(10), " 'Keine Datetime Vars! wenn dann Doubles

SQL = SQL & "Bericht text)" 'jop, ein BLOB, kann riesen groß werden



DBExecute SQL



5. Die Tabelle füllen. Kleiner Trick: Da man mit ID einen primary Key angelegt

hat muss die DB ja checken, ob dieser unique ist. Da das sqlite3 immer tut und

vor allem was macht, wenn man das vergessen haben sollte, so erhält man hier

über einen Umweg einen AUTOINCREMENT-Counter!





'Voraussetzung keine, wenn die DBExecute - Funktion angelegt wurde

DIM SQL As String



SQL = "INSERT INTO DieTabelle (ID, FName, VName, GDatum, Bericht) Values("

SQL = SQL & "NULL, " 'also NULL an ID Incrementcounter wird erhöht.

SQL = SQL & "'Wayne', "

SQL = SQL & "'John', "

SQL = SQL & "'', "

SQL = SQL & "'Weite Prärie, heiße Sonne, warmer Hengst, wen juckts?')"



DBExecute SQL



6. Queries -> Das Kabinettstückchen von sqlite3. Im Gegensatz zu anderen DB's kann

squilte3 Recordsets auf mehrere Arten zurückgeben. Von sql3 wird unterstützt: Der

Callback. Irgend ein SQL-Befehl durchsucht die DB und gibt Datensätze zurück. Sqlite3.dll wartet aber nicht darauf, sondern fetzt durch die DB und wirft gefundenes sofort an den Aufrufer und kümmert sich nicht darum, was der Aufrufer damit macht.

Datenzeile um Datenzeile fetzen also an eine Routine, die der Caller definiert und haben immer den gleichen Aufbau:





Private Function Foo(ByVal ownerFlag As Long, _

ByVal nCol As Long, _

pValues As Long, _

pFields As Long) As Long



Mit ownderFlag kann ich dem Callback einen beliebigen nummerischen Parameter mitgeben. nCol ist die Anzahl der zurückgebenen Felder. pValues ist der Zeiger auf

ein Array aus Strings das die zurückgegebenen Werte beinhaltet und pFields ist ein zeiger auf ein Array aus Strings, das die Feldnamen der zurückgebenen Felder behinhaltet.



Die Variable pValues und pFields entsprechen: char** pValues bzw. char* pValues[]

Unter VB hat man nun ein riesiges Problem: Ein nichtexistentes Array; sprich es muss

erstmal ein Array erzeugt werden, bevor man mit VB darauf zugreifen kann, aber zu diesem Zeitpunkt liegt nur ein Pointer auf eine Struktur vor,die dynamische Strings beinhalten könnte - in VB macht es einfach nur Crash wenn man darauf zugreift.

sql3.dll hat deshalb eine Supportfunktion, die diese Arrays für VB nachkaut.



Gibt die Callback-Funktion einen Wert ungleich 0 zurück, wird der Prozess sofort abgebrochen.





Private Declare Sub GetCharArray Lib "sql3.dll" ( _

ByVal nCol As Long, _

c As Long, _

d As Long, _

ar() As String, _

br() As String)



Unter nCol gibt man den nCol Parameter ein, der an der Callback ankommt. Unter c und d die beiden Zeiger auf das Value-Array und das Field-Array, die an der Callback ankommen. Dann lässt man aufgrund dem Wert aus nCol zwei Arrays in VB erzeugen:





Dim arVal() As String

Dim arField() As String



und initialisiert sie mit nCol:





Redim arVal(nCol)

Redim arField(nCol)



Die Abfrage:





'Voraussetzung/Deklaration



Private Declare Function SqlExec Lib "sql3.dll" ( _

ByVal ppHD As Long, ByVal sSQL As String, _

ByVal ppAdr As Long, sarg As Long, err As String) As Long



Private Declare Sub GetCharArray Lib "sql3.dll" ( _

ByVal nCol As Long, _

c As Long, _

d As Long, _

ar() As String, _

br() As String)



Private Function MyCallBack(ByVal ownerFlag As Long, _

ByVal nCol As Long, _

pValues As Long, _

pFields As Long) As Long

Dim arVal() As String

Dim arField() As String



Redim arVal(nCol)

Redim arField(nCol)



GetCharArray nCol, pValues, pFields, arVal(), arField()

Msgbox arVal(0)

MyCallBack = 0

End Function



'Anfeuern des Callbacks:



DIM SQL As String

SQL = "SELECT * From Die_Tabelle Where Bericht Like '%wen%'"



SQLExec hDBase, SQL, AddressOf MyCallBack, 0, ""



Unter AddressOf wird klar, dass alle Callbacks in einem Modul laufen müssen.

SQLExec läuft im Gegensatz zur Rückgabe der Datensätze nicht asynchron, sondern die

Funktion kehrt erst dann zurück, wenn die Abfrage beendet wurde. Unter VB laufen aber tatsächlich in diesem Fall zwei Threads! SQLExec ist blocking während es in der Callback u.U. mächtig zur Sache geht.



SQLITE3 kann auch "normale" Recordsets, das wird aber mom von sql3.dll nicht unterstützt (wozu auch? - ist doch viel zu langsam, kannst ja gleich Access nehmen).



Jo. Die Messagebox wird eine schlichte 1 anzeigen ;) Warum?

Weil das erste zurückgegebene Feld ID ist und das ist der Autoincrement-Counter,

der automatisch auf 1 erhöht wurde. Hätte ich arVal(1) abgefragt, wäre "Wayne"

gekommen arVal(2), "John" u.s.w.


Programmierst Du noch frei oder wirst Du schon von Microsoft verwaltet ( .NET)?



geschrieben von

Login

E-Mail:
  

Passwort:
  

Beitrag anfügen

Symbol:
 
 
 
 
 
 
 
 
 
 
 
 
 

Überschrift: