Browse Source

fcl-db: parse IN (A..B)

mattias 4 weeks ago
parent
commit
4f2cb10848

+ 19 - 4
packages/fcl-db/src/sql/fpsqlparser.pas

@@ -2400,6 +2400,8 @@ Var
   S : TSQLSelectExpression;
   L : TSQLListExpression;
   Done : Boolean;
+  Expr: TSQLExpression;
+  Bin: TSQLBinaryExpression;
 
 begin
   // On entry, we're on the first token after IN token, which is the ( token.
@@ -2407,6 +2409,7 @@ begin
   try
     If (CurrentToken=tsqlSelect) then
       begin
+      // IN (SELECT...
       S:=TSQLSelectExpression(CreateElement(TSQLSelectExpression,APArent));
       Result:=S;
       S.Select:=ParseSelectStatement(AParent,[sfSingleton]);
@@ -2414,13 +2417,25 @@ begin
       end
     else
       begin
+      // IN (A,B..C,D,...)
       L:=TSQLListExpression(CreateElement(TSQLListExpression,AParent));
       Result:=L;
       Repeat
-         L.List.Add(ParseExprLevel1(L,[eoListValue]));
-         Expect([tsqlBraceClose,tsqlComma]);
-         Done:=(CurrentToken=tsqlBraceClose);
-         GetNextToken;
+        Expr:=ParseExprLevel1(L,[eoListValue]);
+        if CurrentToken=tsqlDotDot then
+          begin
+          Bin:=TSQLBinaryExpression(CreateElement(TSQLBinaryExpression,AParent));
+          Bin.Operation:=boDotDot;
+          Bin.Left:=Expr;
+          L.List.Add(Bin);
+          GetNextToken;
+          Bin.Right:=ParseExprLevel1(Bin,[eoListValue]);
+          end
+        else
+          L.List.Add(Expr);
+        Expect([tsqlBraceClose,tsqlComma]);
+        Done:=(CurrentToken=tsqlBraceClose);
+        GetNextToken;
       until Done;
 
       end;

+ 69 - 63
packages/fcl-db/src/sql/fpsqlscanner.pp

@@ -50,7 +50,7 @@ type
    tsqlIntegerNumber,tsqlFloatNumber,tsqlComment,
    tsqlBraceOpen,tsqlBraceClose,tsqlSquareBraceOpen,tsqlSquareBraceClose,
    tsqlPlaceHolder {question mark},
-   tsqlCOMMA,tsqlCOLON,tsqlDOT,tsqlSEMICOLON,tsqlTerminator,
+   tsqlCOMMA,tsqlCOLON,tsqlDOT,tsqlDotDot,tsqlSEMICOLON,tsqlTerminator,
    tsqlGT,tsqlLT,tsqlPLUS,tsqlMINUS,tsqlMUL,tsqlDIV,tsqlConcatenate,
    tsqlEQ,tsqlGE,tsqlLE,tsqlNE,
    { Reserved words/keywords start here. They must be last }
@@ -96,7 +96,7 @@ const
        'symbol string',
        'integer number','float number', 'comment',
        '(',')', '[',']',
-       '?',',',':','.',';','',
+       '?',',',':','.','..',';','',
        '>','<',
        '+','-','*','/','||',
        '=','>=','<=','<>',
@@ -733,68 +733,68 @@ begin
     FCurTokenColumn:=CurColumn;
     FCurTokenString := '';
     case TokenStr[0] of
-      #0:         // Empty line
-        begin
-        FetchLine;
-        Result := tsqlWhitespace;
-        end;
-      '/' :
-         Result:=CommentDiv;
-      #9, ' ',#10,#13:
-         Result := DoWhiteSpace;
-      '''':
-        begin
-        Result:=DoStringLiteral;
-        if (soSingleQuoteIdentifier in Options) then
-          result:=tsqlIdentifier;
-        end;
-      '"':
-        begin
-        Result:=DoStringLiteral;
-        If (soDoubleQuoteStringLiteral in options) then
-          Result:=tsqlString
-        else
-          Result:=tsqlIdentifier;
-        end;
-      '`':
-        begin
-        Result:=DoStringLiteral;
-        If (soBackQuoteIdentifier in options) then
-          Result:=tsqlIdentifier
-        else
-          Error(SErrUnknownToken,['`']);
-        end;
-      '0'..'9':
-         Result:=DoNumericLiteral;
-      '?':
-         begin
-         Inc(TokenStr);
-         Result:=tsqlPlaceHolder;
-         end;
-      '!':
+    #0:         // Empty line
+      begin
+      FetchLine;
+      Result := tsqlWhitespace;
+      end;
+    '/' :
+      Result:=CommentDiv;
+    #9, ' ',#10,#13:
+      Result := DoWhiteSpace;
+    '''':
+      begin
+      Result:=DoStringLiteral;
+      if (soSingleQuoteIdentifier in Options) then
+        Result:=tsqlIdentifier;
+      end;
+    '"':
+      begin
+      Result:=DoStringLiteral;
+      If (soDoubleQuoteStringLiteral in options) then
+        Result:=tsqlString
+      else
+        Result:=tsqlIdentifier;
+      end;
+    '`':
+      begin
+      Result:=DoStringLiteral;
+      If (soBackQuoteIdentifier in options) then
+        Result:=tsqlIdentifier
+      else
+        Error(SErrUnknownToken,['`']);
+      end;
+    '0'..'9':
+       Result:=DoNumericLiteral;
+    '?':
+       begin
+       Inc(TokenStr);
+       Result:=tsqlPlaceHolder;
+       end;
+    '!':
+      begin
+      Inc(TokenStr);
+      If TokenStr[0]='>' then
+        Result:=tsqlLE
+      else if (TokenStr[0]='<') then
+        Result:=tsqlGE
+      else if (TokenStr[0]='=') then
+        Result:=tsqlNE
+      else
+        Result:=tsqlUnknown;
+      Inc(TokenStr);
+      end;
+    '|':
+      begin
+      Inc(TokenStr);
+      If Tokenstr[0]='|' then
         begin
         Inc(TokenStr);
-        If TokenStr[0]='>' then
-          Result:=tsqlLE
-        else if (TokenStr[0]='<') then
-          Result:=tsqlGE
-        else if (TokenStr[0]='=') then
-          Result:=tsqlNE
-        else
-          Result:=tsqlUnknown;
-        Inc(TokenStr);
-        end;
-     '|':
-         begin
-         Inc(TokenStr);
-         If Tokenstr[0]='|' then
-           begin
-           Inc(TokenStr);
-           Result := tsqlConcatenate
-           end
-         else
-           Error(SBarExpected);
-         end;
+        Result := tsqlConcatenate
+        end
+      else
+        Error(SBarExpected);
+      end;
     '(':
       begin
       Inc(TokenStr);
@@ -858,7 +858,13 @@ begin
     '.':
       begin
       Inc(TokenStr);
-      Result := tsqlDot;
+      if TokenStr^='.' then
+        begin
+        Inc(TokenStr);
+        Result := tsqlDotDot;
+        end
+      else
+        Result := tsqlDot;
       end;
     ':':
       begin

+ 2 - 2
packages/fcl-db/src/sql/fpsqltree.pp

@@ -336,7 +336,7 @@ Type
   end;
 
   TSQLBinaryOperation = (boAnd, boOr, boEQ, boLT, boGT, boLE, boGE, boNE,
-                         boConcat,boAdd, boSubtract, boMultiply, boDivide, boIn,
+                         boConcat,boAdd, boSubtract, boMultiply, boDivide, boIn, boDotDot,
                          boIs, boIsNot, boLike, boContaining, boStarting);
 
   { TSQLBinaryExpression }
@@ -2676,7 +2676,7 @@ function TSQLBinaryExpression.GetAsSQL(Options: TSQLFormatOptions;
 Const
   OpCodes : Array[TSQLBinaryOperation] of string =
           ('AND', 'OR', '=', '<', '>', '<=', '>=', '<>',
-           '||','+', '-', '*', '/', 'IN',
+           '||','+', '-', '*', '/', 'IN', '..',
            'IS', 'IS NOT', 'LIKE', 'CONTAINING','STARTING WITH');
 
 Var

+ 5 - 0
packages/fcl-db/tests/tcparser.pas

@@ -496,6 +496,7 @@ type
     procedure TestWhereAll;
     procedure TestWhereAny;
     procedure TestWhereSome;
+    procedure TestWhereInRange;
     procedure TestParam;
     procedure TestParam_Underscore;
     procedure TestParamExpr;
@@ -5325,6 +5326,10 @@ begin
   AssertTable(S.Tables[0],'D','');
 end;
 
+procedure TTestSelectParser.TestWhereInRange;
+begin
+  TestSelect('SELECT A FROM B WHERE A IN (4..6)');
+end;
 
 procedure TTestSelectParser.TestParam;