Browse Source

- Fixed bug #4121
- Implemented filtering for sqldb

git-svn-id: trunk@615 -

joost 20 năm trước cách đây
mục cha
commit
5355abf860
2 tập tin đã thay đổi với 160 bổ sung95 xóa
  1. 3 2
      fcl/db/sqldb/interbase/ibconnection.pp
  2. 157 93
      fcl/db/sqldb/sqldb.pp

+ 3 - 2
fcl/db/sqldb/interbase/ibconnection.pp

@@ -424,7 +424,8 @@ begin
       CheckError('FreeStatement', Status);
     Statement := nil;
     end;
-  reAllocMem((cursor as tibcursor).SQLDA,0);
+//  reAllocMem((cursor as tibcursor).SQLDA,0);
+// ^=bug moet nog ergens anders komen...
 end;
 
 procedure TIBConnection.PrepareStatement(cursor: TSQLCursor;ATransaction : TSQLTransaction;buf : string; AParams : TParams);
@@ -436,7 +437,7 @@ var dh    : pointer;
     i     : integer;
 
 begin
-  ObtainSQLStatementType(cursor,buf);
+//  ObtainSQLStatementType(cursor,buf);
   with cursor as TIBcursor do
     begin
     dh := GetHandle;

+ 157 - 93
fcl/db/sqldb/sqldb.pp

@@ -51,7 +51,7 @@ const
                   'create', 'get', 'put', 'execute',
                   'start','commit','rollback', '?'
                  );
- SQLDelimiterCharacters = [',',' ','(',')',#13,#10,#9];
+ SQLDelimiterCharacters = [';',',',' ','(',')',#13,#10,#9];
 
 
 { TSQLConnection }
@@ -159,6 +159,10 @@ type
     FUpdateMode          : TUpdateMode;
     FParams              : TParams;
     FusePrimaryKeyAsKey  : Boolean;
+    FSQLBuf              : String;
+    FFromPart            : String;
+    FWhereStartPos       : integer;
+    FWhereStopPos        : integer;
 //    FSchemaInfo          : TSchemaInfo;
 
     procedure CloseStatement;
@@ -173,6 +177,7 @@ type
     procedure OnChangeSQL(Sender : TObject);
 
     procedure Execute;
+    Procedure ParseSQL(var SQL : string);
   protected
     // abstract & virtual methods of TBufDataset
     function Fetch : boolean; override;
@@ -191,6 +196,8 @@ type
     Function IsPrepared : Boolean; virtual;
     function GetFieldData(Field: TField; Buffer: Pointer; NativeFormat: Boolean): Boolean; overload; override;
     procedure SetFieldData(Field: TField; Buffer: Pointer; NativeFormat: Boolean); overload; override;
+    procedure SetFiltered(Value: Boolean); override;
+    procedure SetFilterText(const Value: string); override;
   public
     procedure Prepare; virtual;
     procedure UnPrepare; virtual;
@@ -202,8 +209,8 @@ type
   published
     // redeclared data set properties
     property Active;
-//    property Filter;
-//    property Filtered;
+    property Filter;
+    property Filtered;
 //    property FilterOptions;
     property BeforeOpen;
     property AfterOpen;
@@ -531,16 +538,57 @@ begin
   SetFieldData(Field, Buffer);
 end;
 
+procedure TSQLQuery.SetFilterText(const Value: string);
+
+begin
+  if Filtered then
+    begin
+    end;
+  Inherited SetFilterText(Value);
+end;
+
+procedure TSQLQuery.SetFiltered(Value: Boolean);
+
+var S : String;
+
+begin
+  if (Filtered <> Value) and Active then
+    begin
+    CloseStatement;
+    FIsEOF := False;
+    inherited internalclose;
+
+    s := FSQLBuf;
+
+    if Value then
+      begin
+      if FWhereStartPos = 0 then
+        s := s + ' where (' + Filter + ')'
+      else if FWhereStopPos > 0 then
+        system.insert(' and ('+Filter+') ',S,FWhereStopPos+1)
+      else
+        system.insert(' where ('+Filter+') ',S,FWhereStartPos);
+      end;
+      
+    (Database as tsqlconnection).PrepareStatement(Fcursor,(transaction as tsqltransaction),S,FParams);
+
+    
+    Execute;
+    inherited InternalOpen;
+    First;
+
+    inherited SetFiltered(Value);
+    end;
+end;
+
 procedure TSQLQuery.Prepare;
 var
-  Buf   : string;
   db    : tsqlconnection;
   sqltr : tsqltransaction;
 
 begin
   if not IsPrepared then
     begin
-
     db := (Database as tsqlconnection);
     sqltr := (transaction as tsqltransaction);
     if not assigned(Db) then
@@ -554,12 +602,14 @@ begin
     if assigned(fcursor) then FreeAndNil(fcursor);
     FCursor := Db.AllocateCursorHandle;
 
-    buf := TrimRight(FSQL.Text);
+    FSQLBuf := TrimRight(FSQL.Text);
+    
+    ParseSQL(FSQLBuf);
 
-    Db.PrepareStatement(Fcursor,sqltr,buf,FParams);
+    Db.PrepareStatement(Fcursor,sqltr,FSQLBuf,FParams);
 
     if (FCursor.FStatementType = stSelect) and not ReadOnly then
-      InitUpdates(Buf);
+      InitUpdates(FSQLBuf);
     end;
 end;
 
@@ -632,98 +682,117 @@ begin
   end;
 end;
 
-procedure TSQLQuery.InitUpdates(SQL : string);
-
-Var
-  L       : Integer;
-  P,PP    : PChar;
-  PS: PChar;
-  S       : string;
-
-  function GetStatement(var StartP : PChar) : PChar;
+procedure TSQLQuery.ParseSQL(var SQL : string);
 
-  var p        : pchar;
-      Cmt, Stm : boolean;
+type TParsePart = (ppStart,ppSelect,ppWhere,ppFrom,ppOrder,ppComment,ppBogus);
 
-  begin
-    p := StartP;
-    Cmt := false;
-    Stm := False;
-    While ((P-PP)<L) do
-      begin
-      if Cmt then
-        begin
-        end
-      else if (p^ in SQLDelimiterCharacters) then
-        begin
-        if stm then break;
-        end
-      else if not stm then
-        begin
-        StartP := p;
-        stm := true;
-        end;
-      inc(p);
-      end;
-    Result := P;
-  end;
+Var
+  PSQL,CurrentP,
+  PhraseP, PStatementPart : pchar;
+  S                       : string;
+  ParsePart               : TParsePart;
+  StrLength               : Integer;
 
 begin
-  FUpdateable := False;
-
-  L:=Length(SQL);
-
-  PP:=Pchar(SQL);
-  P := pp;
-  PS := pp;
-
-// select-keyword
-  P := GetStatement(PS);
+  PSQL:=Pchar(SQL);
+  ParsePart := ppStart;
 
-  Setlength(S,P-PS);
-  Move(PS^,S[1],(P-PS));
-  S:=Lowercase(S);
+  CurrentP := PSQL-1;
+  PhraseP := PSQL;
+  
+  FWhereStartPos := 0;
+  FWhereStopPos := 0;
 
-  if (S) <> 'select' then exit;
-
-// select-part
-
-  While ((P-PP)<L) and  (S <> 'from') do
+  repeat
     begin
-    repeat
-    PS := P;
-    P := GetStatement(PS);
-    until P^ <> ',';
-
-    Setlength(S,P-PS);
-    Move(PS^,S[1],(P-PS));
-    S:=Lowercase(S);
+    inc(CurrentP);
 
+    if CurrentP^ in [' ',#13,#10,#9,#0,'(',')',';'] then
+      begin
+      if (CurrentP-PhraseP > 0) or (CurrentP^ in [';',#0]) then
+        begin
+        strLength := CurrentP-PhraseP;
+        Setlength(S,strLength);
+        if strLength > 0 then Move(PhraseP^,S[1],(strLength));
+        s := uppercase(s);
+        
+        case ParsePart of
+          ppStart  : begin
+                     FCursor.FStatementType := (Database as tsqlconnection).StrToStatementType(s);
+                     if FCursor.FStatementType = stSelect then ParsePart := ppSelect
+                       else break;
+                     PStatementPart := CurrentP;
+                     end;
+          ppSelect : begin
+                     if s = 'FROM' then
+                       begin
+                       ParsePart := ppFrom;
+                       PhraseP := CurrentP;
+                       PStatementPart := CurrentP;
+                       end;
+                     end;
+          ppFrom   : begin
+                     if (s = 'WHERE') or (s = 'ORDER') or (CurrentP^=#0) or (CurrentP^=';') then
+                       begin
+                       if (s = 'WHERE') then
+                         begin
+                         ParsePart := ppWhere;
+                         StrLength := PhraseP-PStatementPart;
+                         end
+                       else if (s = 'ORDER') then
+                         begin
+                         ParsePart := ppOrder;
+                         StrLength := PhraseP-PStatementPart
+                         end
+                       else
+                         begin
+                         ParsePart := ppBogus;
+                         StrLength := CurrentP-PStatementPart;
+                         end;
+                       Setlength(FFromPart,StrLength);
+                       Move(PStatementPart^,FFromPart[1],(StrLength));
+                       FFrompart := trim(FFrompart);
+                       FWhereStartPos := PStatementPart-PSQL+StrLength+1;
+                       PStatementPart := CurrentP;
+                       end;
+                     end;
+          ppWhere  : begin
+                     if (s = 'ORDER') or (CurrentP^=#0) or (CurrentP^=';') then
+                       begin
+                       ParsePart := ppBogus;
+                       FWhereStartPos := PStatementPart-PSQL;
+                       if s = 'ORDER' then
+                         FWhereStopPos := PhraseP-PSQL+1
+                       else
+                         FWhereStopPos := CurrentP-PSQL+1;
+                       end;
+                     end;
+        end; {case}
+        end;
+      PhraseP := CurrentP+1;
+      end
     end;
-
-// from-part
-
-  PS := P;
-  P := GetStatement(PS);
-
-  Setlength(FTableName,P-PS);
-  Move(PS^,FTableName[1],(P-PS));
-
-  While ((P-PP)<L)  do
+  until CurrentP^=#0;
+  if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
     begin
-    PS := P;
-    P := GetStatement(PS);
+    system.insert('(',SQL,FWhereStartPos+1);
+    inc(FWhereStopPos);
+    system.insert(')',SQL,FWhereStopPos);
+    end
+end;
 
-    if P^ = ',' then exit; // select-statements from more then one table are not updateable
+procedure TSQLQuery.InitUpdates(SQL : string);
 
-    Setlength(S,P-PS);
-    Move(PS^,S[1],(P-PS));
-    S:=Lowercase(S);
 
-    if (s = 'where') or (s='order') then break;
+begin
+  if pos(',',FFromPart) > 0 then
+    FUpdateable := False // select-statements from more then one table are not updateable
+  else
+    begin
+    FUpdateable := True;
+    FTableName := FFromPart;
     end;
 
-  FUpdateable := True;
 end;
 
 procedure TSQLQuery.InternalOpen;
@@ -837,7 +906,6 @@ end;
 function TSQLQuery.ApplyRecUpdate(UpdateKind : TUpdateKind) : boolean;
 
 var
-    sql_tables : string;
     s : string;
 
   procedure UpdateWherePart(var sql_where : string;x : integer);
@@ -860,7 +928,6 @@ var
       sql_where  : string;
 
   begin
-    sql_tables := FTableName;
     sql_set := '';
     sql_where := '';
     for x := 0 to Fields.Count -1 do
@@ -876,7 +943,7 @@ var
 
     setlength(sql_set,length(sql_set)-1);
     setlength(sql_where,length(sql_where)-5);
-    result := 'update ' + sql_tables + ' set ' + sql_set + ' where ' + sql_where;
+    result := 'update ' + FTableName + ' set ' + sql_set + ' where ' + sql_where;
 
   end;
 
@@ -887,7 +954,6 @@ var
       sql_values : string;
 
   begin
-    sql_tables := FTableName;
     sql_fields := '';
     sql_values := '';
     for x := 0 to Fields.Count -1 do
@@ -901,7 +967,7 @@ var
     setlength(sql_fields,length(sql_fields)-1);
     setlength(sql_values,length(sql_values)-1);
 
-    result := 'insert into ' + sql_tables + ' (' + sql_fields + ') values (' + sql_values + ')';
+    result := 'insert into ' + FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
   end;
 
   function DeleteRecQuery : string;
@@ -910,15 +976,13 @@ var
       sql_where  : string;
 
   begin
-    sql_tables := FTableName;
-
     sql_where := '';
     for x := 0 to Fields.Count -1 do
       UpdateWherePart(sql_where,x);
 
     setlength(sql_where,length(sql_where)-5);
 
-    result := 'delete from ' + sql_tables + ' where ' + sql_where;
+    result := 'delete from ' + FTableName + ' where ' + sql_where;
   end;
 
 begin