123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- {$mode objfpc}
- {$h+}
- unit SQLitedb;
- interface
- uses Classes,strings,sqlite;
- type
- TSQLiteExecCallback = function(Sender: pointer; Columns: Integer; ColumnValues: ppchar; ColumnNames: ppchar): integer of object; cdecl;
- TSQLiteBusyCallback = function(Sender: TObject; ObjectName: PChar; BusyCount: integer): integer of object; cdecl;
- TOnData = Procedure(Sender: TObject; Columns: Integer; ColumnNames, ColumnValues: String) of object;
- TOnBusy = Procedure(Sender: TObject; ObjectName: String; BusyCount: integer; var Cancel: Boolean) of object;
- TOnQueryComplete = Procedure(Sender: TObject) of object;
- TSQLite = class(TObject)
- private
- fSQLite: Pointer;
- fMsg: String;
- fIsOpen: Boolean;
- fBusy: Boolean;
- fError: Integer;
- fVersion: String;
- fEncoding: String;
- fTable: TStrings;
- fLstName: TStringList;
- fLstVal: TStringList;
- fOnData: TOnData;
- fOnBusy: TOnBusy;
- fOnQueryComplete: TOnQueryComplete;
- fBusyTimeout: integer;
- fPMsg: PChar;
- fChangeCount: integer;
- fNb_Champ : Integer;
- fList_FieldName : TStringList;
- fList_Field : TList;
- procedure SetBusyTimeout(Timeout: integer);
- public
- constructor Create(DBFileName: String);
- destructor Destroy; override;
- function Query(Sql: String; Table: TStrings ): boolean;
- function ErrorMessage(ErrNo: Integer): string;
- function IsComplete(Sql: String): boolean;
- function LastInsertRow: integer;
- function Cancel: boolean;
- function DatabaseDetails(Table: TStrings): boolean;
- property LastErrorMessage: string read fMsg;
- property LastError: Integer read fError;
- property Version: String read fVersion;
- property Encoding: String read fEncoding;
- property OnData: TOnData read fOnData write fOnData;
- property OnBusy: TOnBusy read fOnBusy write fOnBusy;
- property OnQueryComplete: TOnQueryComplete read fOnQueryComplete write fOnQueryComplete;
- property BusyTimeout: Integer read fBusyTimeout write SetBusyTimeout;
- property ChangeCount: Integer read fChangeCount;
- property List_FieldName: TStringList read fList_FieldName write fList_FieldName;
- property List_Field: TList read fList_Field write fList_Field;
- property Nb_Champ: integer read fNb_Champ write fNb_Champ;
- procedure SQLOnData(Sender: TObject; Columns: Integer; ColumnNames, ColumnValues: String);
- end;
- function Pas2SQLStr(const PasString: string): string;
- function SQL2PasStr(const SQLString: string): string;
- function QuoteStr(const s: string; QuoteChar: Char ): string;
- function UnQuoteStr(const s: string; QuoteChar: Char ): string;
- procedure ValueList(const ColumnNames, ColumnValues: String; NameValuePairs: TStrings);
- implementation
- Const
- DblQuote: Char = '"';
- SngQuote: Char = #39;
- Crlf: String = #13#10;
- Tab: Char = #9;
- var
- MsgNoError: String;
- function QuoteStr(const s: string; QuoteChar: Char ): string;
- begin
- Result := Concat(QuoteChar, s, QuoteChar);
- end;
- function UnQuoteStr(const s: string; QuoteChar: Char ): string;
- begin
- Result := s;
- if length(Result) > 1 then
- begin
- if Result[1] = QuoteChar then
- Delete(Result, 1, 1);
- if Result[Length(Result)] = QuoteChar then
- Delete(Result, Length(Result), 1);
- end;
- end;
- function Pas2SQLStr(const PasString: string): string;
- var
- n: integer;
- begin
- Result := SQL2PasStr(PasString);
- n := Length(Result);
- while n > 0 do
- begin
- if Result[n] = SngQuote then
- Insert(SngQuote, Result, n);
- dec(n);
- end;
- Result := QuoteStr(Result,#39);
- end;
- function SQL2PasStr(const SQLString: string): string;
- const
- DblSngQuote: String = #39#39;
- var
- p: integer;
- begin
- Result := SQLString;
- p := pos(DblSngQuote, Result);
- while p > 0 do
- begin
- Delete(Result, p, 1);
- p := pos(DblSngQuote, Result);
- end;
- Result := UnQuoteStr(Result,#39);
- end;
- procedure ValueList(const ColumnNames, ColumnValues: String; NameValuePairs: TStrings);
- var
- n: integer;
- lstName, lstValue: TStringList;
- begin
- if NameValuePairs <> nil then
- begin
- lstName := TStringList.Create;
- lstValue := TStringList.Create;
- lstName.CommaText := ColumnNames;
- lstValue.CommaText := ColumnValues;
- NameValuePairs.Clear;
- if lstName.Count = LstValue.Count then
- if lstName.Count > 0 then
- for n := 0 to lstName.Count - 1 do
- NameValuePairs.Append(Concat(lstName.Strings[n], '=', lstValue.Strings[n]));
- lstValue.Free;
- lstName.Free;
- end;
- end;
- function SystemErrorMsg(ErrNo: Integer ): String;
- var
- buf: PChar;
- size: Integer;
- MsgLen: Integer;
- begin
- { size := 256;
- GetMem(buf, size);
- If ErrNo = - 1 then
- ErrNo := GetLastError;
- MsgLen := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil, ErrNo, 0, buf, size, nil);
- if MsgLen = 0 then
- Result := 'ERROR'
- else
- Result := buf;}
- end;
- function BusyCallback(Sender: pointer; ObjectName: PChar; BusyCount: integer): integer; cdecl;
- var
- sObjName: String;
- bCancel: Boolean;
- begin
- Result := -1;
- with TObject(Sender) as TSQLite do
- begin
- if Assigned(fOnBusy) then
- begin
- bCancel := False;
- sObjName := ObjectName;
- fOnBusy(Tobject(Sender), sObjName, BusyCount, bCancel);
- if bCancel then
- Result := 0;
- end;
- end;
- end;
- function ExecCallback(Sender: Pointer; Columns: Integer; ColumnValues: PPChar; ColumnNames: PPchar): integer; cdecl;
- var
- PVal, PName: ^PChar;
- n: integer;
- sVal, sName: String;
- begin
- Result := 0;
- with TObject(Sender) as TSQLite do
- begin
- if (Assigned(fOnData) or Assigned(fTable)) then
- begin
- fLstName.Clear;
- fLstVal.Clear;
- if Columns > 0 then
- begin
- PName := ColumnNames;
- PVal := ColumnValues;
- for n := 0 to Columns - 1 do
- begin
- fLstName.Append(PName^);
- fLstVal.Append(PVal^);
- inc(PName);
- inc(PVal);
- end;
- end;
- sVal := fLstVal.CommaText;
- sName := fLstName.CommaText;
- if Assigned(fOnData) then
- fOnData(TObject(Sender), Columns, sName, sVal);
- if Assigned(fTable) then
- begin
- if fTable.Count = 0 then
- fTable.Append(sName);
- fTable.Append(sVal);
- end;
- end;
- end;
- end;
- procedure TSQLite.SQLOnData(Sender: TObject; Columns: Integer; ColumnNames, ColumnValues: String);
- Var i : Integer;
- InterS,val : String;
- Field : TStringList;
- function Pos1(a: String ; s : char) : integer;
- var i,j : Integer;
- begin
- j:=-1;
- for i:=1 to length(a) Do
- begin
- if a[i] = s then
- begin
- j:=i;
- break;
- end;
- end;
- result:=j;
- end;
- begin
- If Nb_Champ = -1 Then
- Begin // Put the fields name in List_FieldName
- Nb_Champ:=Columns;
- InterS:=ColumnNames;
- While (Pos1(InterS,',') > 0) do
- begin
- val:=copy(InterS,1,Pos1(InterS,',')-1);
- InterS:=copy(InterS,Pos1(InterS,',')+1,length(InterS));
- List_FieldName.add(val);
- end;
- if length(InterS) > 0 then List_FieldName.add(InterS);
- end;
- // Put the list of TStringList of value
- Field :=TStringList.Create;
- InterS:=ColumnValues;
- While (Pos1(InterS,',') > 0) do
- begin
- val:=copy(InterS,1,Pos1(InterS,',')-1);
- InterS:=copy(InterS,Pos1(InterS,',')+1,length(InterS));
- Field.add(val);
- end;
- if length(InterS) > 0 then Field.add(InterS);
- List_Field.add(Field);
- end;
- constructor TSQLite.Create(DBFileName: String);
- var
- fPMsg1: PChar;
- name : pchar;
- begin
- inherited Create;
- List_FieldName := TStringList.Create;
- List_Field := TList.Create;
- fError := SQLITE_ERROR;
- fIsOpen := False;
- fLstName := TStringList.Create;
- fLstVal := TStringList.Create;
- fOnData := nil;
- fOnBusy := nil;
- fOnQueryComplete := nil;
- fChangeCount := 0;
- name:=StrAlloc (length(DBFileName)+1);
- strpcopy(name,DBFileName);
- OnData:=@SQLOnData;
- fSQLite := SQLite_Open(name, 1, @fPMsg);
- SQLite_FreeMem(fPMsg);
- if fSQLite <> nil then
- begin
- //fVersion := String(SQLite_Version);
- //fEncoding := SQLite_Encoding;
- fIsOpen := True;
- fError := SQLITE_OK;
- end;
- fMsg := ErrorMessage(fError);
- end;
- destructor TSQLite.Destroy;
- begin
- if fIsOpen then
- SQLite_Close(fSQLite);
- fIsOpen := False;
- fLstName.Free;
- fLstVal.Free;
- fSQLite := nil;
- fOnData := nil;
- fOnBusy := nil;
- fOnQueryComplete := nil;
- fLstName := nil;
- fLstVal := nil;
- List_FieldName.destroy;
- List_Field.destroy;
- inherited Destroy;
- end;
- function TSQLite.Query(Sql: String; Table: TStrings ): boolean;
- //var
- // fPMsg: PChar;
- //var Psql : pchar;
- begin
- fError := SQLITE_ERROR;
- if fIsOpen then
- begin
- fPMsg := nil;
- fBusy := True;
- fTable := Table;
- if fTable <> nil then
- fTable.Clear;
- List_FieldName.clear;
- List_Field.clear;
- Nb_Champ:=-1;
- fError := SQLite_Exec(fSQLite, PChar(sql), @ExecCallback, Self, @fPMsg);
- SQLite_FreeMem(fPMsg);
- fChangeCount := SQLite_Changes(fSQLite);
- fTable := nil;
- fBusy := False;
- if Assigned(fOnQueryComplete) then
- fOnQueryComplete(Self);
- end;
- fMsg := ErrorMessage(fError);
- Result := (fError = SQLITE_OK);
- end;
- function TSQLite.Cancel: boolean;
- begin
- Result := False;
- if fBusy and fIsOpen then
- begin
- do_SQLite_interrupt(fSQLite);
- fBusy := false;
- Result := True;
- end;
- end;
- procedure TSQLite.SetBusyTimeout(Timeout: Integer);
- begin
- fBusyTimeout := Timeout;
- if fIsOpen then
- begin
- SQLite_Busy_Timeout(fSQLite, fBusyTimeout);
- if fBusyTimeout > 0 then
- SQLite_Busy_Handler(fSQLite, @BusyCallback, Self)
- else
- SQLite_Busy_Handler(fSQLite, nil, nil);
- end;
- end;
- function TSQLite.LastInsertRow: integer;
- begin
- if fIsOpen then
- Result := SQLite_Last_Insert_RowID(fSQLite)
- else
- Result := -1;
- end;
- function TSQLite.ErrorMessage(ErrNo: Integer): string;
- begin
- if ErrNo = 0 then
- Result := MsgNoError
- else
- Result := SQLite_Error_String(ErrNo);
- end;
- function TSQLite.IsComplete(Sql: String): boolean;
- var Psql : pchar;
- begin
- Psql:=StrAlloc (length(Sql)+1);
- strpcopy(Psql,Sql);
- Writeln('Testing: ',psql);
- Result := SQLite_Complete(Psql)<>0;
- strdispose(Psql);
- end;
- function TSQLite.DatabaseDetails(Table: TStrings): boolean;
- begin
- Result := Query('SELECT * FROM SQLITE_MASTER;', Table);
- end;
- initialization
- finalization
- end.
|