| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 | {$mode objfpc}{$h+}{*************************************************************SQLite3 Object Oriented handleO. Rinaudo - 2005 - [email protected]G. Marcou  - 2007 - [email protected]*************************************************************}unit SQLite3db;interfaceuses  Classes,strings,sqlite3;{*************************************************************}{*************************************************************}type   TSQLiteExecCallback = function(Sender: pointer; Columns: Integer; ColumnValues: ppchar; ColumnNames: ppchar): integer of object; cdecl;   TSQLiteBusyCallback = function(Sender: TObject; BusyCount: integer): longint of object; cdecl;   TOnData = Procedure(Sender: TObject; Columns: Integer; ColumnNames, ColumnValues: String)  of object;   TOnBusy = Procedure(Sender: TObject; BusyCount: integer; var Cancel: Boolean) of object;   TOnQueryComplete = Procedure(Sender: TObject) of object;   TSQLite = class(TObject){*************************************************************}{*************************************************************}      private   fPSQlite: PPsqlite3;   fSQLite:Psqlite3;   fMsg: String;   fIsOpen: Boolean;   fBusy: Boolean;   fError: longint;   fVersion: String;   fEncoding: String;   fTable: TStrings;   fLstName: TStringList;   fLstVal: TStringList;   fOnData: TOnData;   fOnBusy: TOnBusy;   fOnQueryComplete: TOnQueryComplete;   fBusyTimeout: longint;   fPMsg: PChar;   fChangeCount: longint;   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: longint 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: longint read fBusyTimeout write SetBusyTimeout;   property ChangeCount: longint 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);{*************************************************************}{*************************************************************}implementationConst   DblQuote: Char      = '"';   SngQuote: Char      = #39;   DblSngQuote: String = #39#39;   Crlf: String	       = #13#10;   Tab: Char	       = #9;var   MsgNoError : String;{*************************************************************}{*************************************************************}function QuoteStr(const s: string; QuoteChar: Char ): string;{*************************************************************SQlite3 enclosing string with quotesG. Marcou*************************************************************}begin   Result := Concat(QuoteChar, s, QuoteChar);end;{*************************************************************}function UnQuoteStr(const s: string; QuoteChar: Char ): string;{*************************************************************SQlite3 Remove enclosing quotes from stringG. Marcou*************************************************************}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;{*************************************************************SQlite3 SQL string are use double quotes, Pascal string usesingle quote.G. Marcou*************************************************************}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,SngQuote);end;{*************************************************************}function SQL2PasStr(const SQLString: string): string;{*************************************************************SQlite3 SQL string are use double quotes, Pascal string usesingle quote.G. Marcou*************************************************************}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,SngQuote);end;{*************************************************************}procedure ValueList(const ColumnNames, ColumnValues : String;NameValuePairs					    : TStrings);{*************************************************************SQlite3 build (name=value) pair listG. Marcou*************************************************************}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;BusyCount		     : integer): longint; cdecl;{*************************************************************SQlite3 busy callback G. Marcou*************************************************************}var  bCancel: Boolean;begin  Result := -1;  with TObject(Sender) as TSQLite do  begin    if Assigned(fOnBusy) then    begin      bCancel := False;      fOnBusy(Tobject(Sender), BusyCount, bCancel);      if bCancel then        Result := 0;    end;  end;end;{*************************************************************}function ExecCallback(Sender : Pointer;Columns			     : Integer;ColumnValues		     : PPChar;ColumnNames		     : PPchar): integer; cdecl;{*************************************************************SQlite3 Build table and data from callbackG. Marcou*************************************************************}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);{*************************************************************SQlite3 Fill up field list names and field list valuesG. Marcou*************************************************************}Var   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; { Pos1 }   {*************************************************}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);{*************************************************************SQlite3 constructorG. Marcou*************************************************************}var   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;   writeln('Try to open');   sqlite3_open(name,@fSQLite);   writeln('Open success');   sqlite3_free(fPMsg);   writeln('Free memory');   if fSQLite <> nil then   begin      //fVersion := String(SQLite_Version);      //fEncoding := SQLite_Encoding;      fIsOpen := True;      fError := SQLITE_OK;   end;   fMsg := sqlite3_errmsg(fSQLite);end;{*************************************************************}destructor TSQLite.Destroy;{*************************************************************SQLite3 destructorG. Marcou*************************************************************}begin   if fIsOpen then      fError:=sqlite3_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;{*************************************************************SQLite3 query the databaseG. Marcou*************************************************************}//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 := sqlite3_exec(fSQLite, PChar(sql), @ExecCallback, Self, @fPMsg);      sqlite3_free(fPMsg);      fChangeCount := sqlite3_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;{*************************************************************SQLite3 interrupt databaseG. Marcou*************************************************************}begin   Result := False;   if fBusy and fIsOpen then   begin      sqlite3_interrupt(fSQLite);      fBusy := false;      Result := True;   end;end;{*************************************************************}procedure TSQLite.SetBusyTimeout(Timeout: Integer);{*************************************************************SQLite3 busy timeoutG. Marcou*************************************************************}begin   fBusyTimeout := Timeout;   if fIsOpen then   begin      fError:=sqlite3_busy_timeout(fSQLite, fBusyTimeout);      if fBusyTimeout > 0 then	 sqlite3_busy_handler(fSQLite, @BusyCallback, Self)      else	 sqlite3_busy_handler(fSQLite, nil, nil);   end;end;{*************************************************************}function TSQLite.LastInsertRow: longint;{*************************************************************SQLite3 Get ID of the last inserted rowG. Marcou*************************************************************}begin  if fIsOpen then    Result := sqlite3_last_insert_rowid(fSQLite)  else    Result := -1;end;{*************************************************************}function TSQLite.ErrorMessage(ErrNo: Integer): string;{*************************************************************SQLite3 Return comprehensive error messageG. Marcou*************************************************************}begin  if ErrNo = 0 then    Result := MsgNoError  else    Result := sqlite3_errmsg(fSQLite);end;{*************************************************************}function TSQLite.IsComplete(Sql: String): boolean;{*************************************************************SQLite3 Return true when completeG. Marcou*************************************************************}var Psql : pchar;begin   Psql:=StrAlloc (length(Sql)+1);   strpcopy(Psql,Sql);//   Writeln('Testing: ',psql);   Result := sqlite3_complete(Psql)<>0;   strdispose(Psql);end;{*************************************************************}function TSQLite.DatabaseDetails(Table: TStrings): boolean;{*************************************************************SQLite3 Query the databaseG. Marcou*************************************************************}begin  Result := Query('SELECT * FROM SQLITE_MASTER;', Table);end;{*************************************************************}{*************************************************************}initializationfinalizationend.
 |