Bug in DataSet-Filter?

Discussion of open issues, suggestions and bugs regarding ODAC (Oracle Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
a-s-z
Posts: 106
Joined: Wed 03 Dec 2008 06:01

Re: Bug in DataSet-Filter?

Post by a-s-z » Wed 25 Sep 2013 14:31

Hi Alex,

unfortunatly there are errors in the behavior of the current implementation (since 9.1.3).
The handling of the escape char is not correct, since a backslash at the end of the mask will lead to access of Mask with MaskIndex > Length(Mask) and having '\\_' in the mask won't show the expected results.
In addition, I have improved the performance with masks containing many following wildcards ('foo%%%%%').

Setting OldFilterAsteriskBehavior will restore the behavior of versions before 9.1.3 (no escaping too).

Here is the current patch:

Code: Select all

diff -ur NewFilterBehavior.orig/Source/MemData.pas ODAC for RAD Studio XE2/Source/MemData.pas
--- NewFilterBehavior.orig/Source/MemData.pas	2013-09-12 19:48:14.000000000 +0200
+++ ODAC for RAD Studio XE2/Source/MemData.pas	2013-09-25 16:05:58.000000000 +0200
@@ -1432,6 +1432,9 @@
 function AddCRUnicode(Source, Dest: IntPtr; Count: integer): integer; overload;
 function RemoveCRUnicode(Source, Dest: IntPtr; DestLen, Count: integer): integer; overload;
 
+var
+  OldFilterAsteriskBehavior: Boolean = True;
+
 implementation
 
 uses
@@ -5296,18 +5299,62 @@
     WildcardAst = '*';
     WildcardPct = '%';
     WildcardOne = '_';
+    EscapeChar  = '\';
   type
     TMatchesResult = (mrFalse,mrTrue,mrEnd);
 
+    function IsWildcardMany(MaskIndex: integer): Boolean;
+    begin
+      case Mask[MaskIndex] of
+        WildcardAst:
+        begin
+          if OldFilterAsteriskBehavior then
+            Result := True
+          else if FilterNoPartialCompare then
+            Result := False
+          else if Node.NodeType in [ntLike, ntNotLike] then
+            Result := False
+          else
+            Result := MaskIndex = Length(Mask);
+        end;
+        WildcardPct:
+        begin
+          if OldFilterAsteriskBehavior then
+            Result := True
+          else
+            Result := Node.NodeType in [ntLike, ntNotLike];
+        end
+      else
+        Result := False;
+      end;
+    end;
+    function IsWildcardOne(MaskIndex: integer): Boolean;
+    begin
+      case Mask[MaskIndex] of
+        WildcardOne:
+        begin
+          if OldFilterAsteriskBehavior then
+            Result := True
+          else
+            Result := Node.NodeType in [ntLike, ntNotLike];
+        end
+      else
+        Result := False;
+      end;
+    end;
     function SubMatchesMask(StIndex, MaskIndex: integer): TMatchesResult;
+    var
+      Escaped: Boolean;
     begin
       while (MaskIndex <= Length(Mask)) and
-        ((StIndex <= Length(St)) or
-        ((Mask[MaskIndex] = WildcardAst) or (Mask[MaskIndex] = WildcardPct))) do begin
-        if (Mask[MaskIndex] = WildcardAst) or (Mask[MaskIndex] = WildcardPct) then begin
+        ((StIndex <= Length(St)) or IsWildcardMany(MaskIndex)) do begin
+        if IsWildcardMany(MaskIndex) then begin
+          while MaskIndex < Length(Mask) do
+            if IsWildcardMany(MaskIndex+1) then
+              Inc(MaskIndex); // Speed up with multiple '%'
           if MaskIndex = Length(Mask) then begin  //-
             Result := mrTrue;                     // Speed up
-            Exit;                                 // with mask '*'
+            Exit;                                 // with mask ending with '*'.
           end                                     //-
           else
             case SubMatchesMask(StIndex, MaskIndex + 1) of
@@ -5329,9 +5376,10 @@
             end;
         end
         else begin
-          if Mask[MaskIndex] = '\' then
+          Escaped := not OldFilterAsteriskBehavior and (MaskIndex < Length(Mask)) and (Mask[MaskIndex] = EscapeChar);
+          if Escaped then
             Inc(MaskIndex);
-          if (St[StIndex] = Mask[MaskIndex]) or ((Mask[MaskIndex] = WildcardOne) and (Mask[MaskIndex - 1] <> '\'))
+          if (St[StIndex] = Mask[MaskIndex]) or (IsWildcardOne(MaskIndex) and not Escaped)
           then begin
             Inc(StIndex);
             Inc(MaskIndex); 
Best regards,
Andre

Post Reply