home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Vcl / dbcommon.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  58KB  |  1,813 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {       Common Database Code                            }
  6. {                                                       }
  7. {       Copyright (c) 1995,99 Inprise Corporation       }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit DBCommon;
  12.  
  13. {$T-,H+,X+,R-}
  14.  
  15. interface
  16.  
  17. uses Windows, Classes, DB;
  18.  
  19. type
  20.   TCANOperator = (
  21.     coNOTDEFINED,                      {                                   }
  22.     coISBLANK,                         { coUnary;  is operand blank.      }
  23.     coNOTBLANK,                        { coUnary;  is operand not blank.  }
  24.     coEQ,                              { coBinary, coCompare; equal.     }
  25.     coNE,                              { coBinary; NOT equal.             }
  26.     coGT,                              { coBinary; greater than.          }
  27.     coLT,                              { coBinary; less than.             }
  28.     coGE,                              { coBinary; greater or equal.      }
  29.     coLE,                              { coBinary; less or equal.         }
  30.     coNOT,                             { coUnary; NOT                     }
  31.     coAND,                             { coBinary; AND                    }
  32.     coOR,                              { coBinary; OR                     }
  33.     coTUPLE2,                          { coUnary; Entire record is operand. }
  34.     coFIELD2,                          { coUnary; operand is field        }
  35.     coCONST2,                          { coUnary; operand is constant     }
  36.     coMINUS,                           { coUnary;  minus. }
  37.     coADD,                             { coBinary; addition. }
  38.     coSUB,                             { coBinary; subtraction. }
  39.     coMUL,                             { coBinary; multiplication. }
  40.     coDIV,                             { coBinary; division. }
  41.     coMOD,                             { coBinary; modulo division. }
  42.     coREM,                             { coBinary; remainder of division. }
  43.     coSUM,                             { coBinary, accumulate sum of. }
  44.     coCOUNT,                           { coBinary, accumulate count of. }
  45.     coMIN,                             { coBinary, find minimum of. }
  46.     coMAX,                             { coBinary, find maximum of. }
  47.     coAVG,                             { coBinary, find average of. }
  48.     coCONT,                            { coBinary; provides a link between two }
  49.     coUDF2,                            { coBinary; invokes a User defined fn }
  50.     coCONTINUE2,                       { coUnary; Stops evaluating records }
  51.     coLIKE,                            { coCompare, extended binary compare        }
  52.     coIN,                              { coBinary field in list of values }
  53.     coLIST2,                           { List of constant values of same type }
  54.     coUPPER,                           { coUnary: upper case }
  55.     coLOWER,                           { coUnary: lower case }
  56.     coFUNC2,                           { coFunc: Function }
  57.     coLISTELEM2,                       { coListElem: List Element }
  58.     coASSIGN                           { coBinary: Field assignment }
  59.   );
  60.  
  61.   NODEClass = (                         { Node Class }
  62.     nodeNULL,                           { Null node                   }
  63.     nodeUNARY,                          { Node is a unary             }
  64.     nodeBINARY,                         { Node is a binary            }
  65.     nodeCOMPARE,                        { Node is a compare           }
  66.     nodeFIELD,                          { Node is a field             }
  67.     nodeCONST,                          { Node is a constant          }
  68.     nodeTUPLE,                          { Node is a record }
  69.     nodeCONTINUE,                       { Node is a continue node     }
  70.     nodeUDF,                            { Node is a UDF node }
  71.     nodeLIST,                           { Node is a LIST node }
  72.     nodeFUNC,                           { Node is a Function node }
  73.     nodeLISTELEM                        { Node is a List Element node }
  74.   );
  75.  
  76. const
  77.   CANEXPRSIZE        = 10; { SizeOf(CANExpr) }
  78.   CANHDRSIZE         = 8;  { SizeOf(CANHdr) }
  79.   CANEXPRVERSION     = 2;
  80.  
  81.  
  82. type
  83.   TExprData = array of Byte;
  84.   TFieldMap = array[TFieldType] of Byte;
  85.  
  86. { TFilterExpr }
  87.  
  88. type
  89.  
  90.   TParserOption = (poExtSyntax, poAggregate, poDefaultExpr, poUseOrigNames,
  91.                    poFieldNameGiven, poFieldDepend);
  92.   TParserOptions = set of TParserOption;
  93.  
  94.   TExprNodeKind = (enField, enConst, enOperator, enFunc);
  95.   TExprScopeKind = (skField, skAgg, skConst);
  96.  
  97.   PExprNode = ^TExprNode;
  98.   TExprNode = record
  99.     FNext: PExprNode;
  100.     FKind: TExprNodeKind;
  101.     FPartial: Boolean;
  102.     FOperator: TCANOperator;
  103.     FData: Variant;
  104.     FLeft: PExprNode;
  105.     FRight: PExprNode;
  106.     FDataType: TFieldType;
  107.     FDataSize: Integer;
  108.     FArgs: TList;
  109.     FScopeKind: TExprScopeKind;
  110.   end;
  111.  
  112.   TFilterExpr = class
  113.   private
  114.     FDataSet: TDataSet;
  115.     FFieldMap: TFieldMap;
  116.     FOptions: TFilterOptions;
  117.     FParserOptions: TParserOptions;
  118.     FNodes: PExprNode;
  119.     FExprBuffer: TExprData;
  120.     FExprBufSize: Integer;
  121.     FExprNodeSize: Integer;
  122.     FExprDataSize: Integer;
  123.     FFieldName: string;
  124.     FDependentFields: TBits;
  125.     function FieldFromNode(Node: PExprNode): TField;
  126.     function GetExprData(Pos, Size: Integer): PChar;
  127.     function PutConstBCD(const Value: Variant; Decimals: Integer): Integer;
  128.     function PutConstBool(const Value: Variant): Integer;
  129.     function PutConstDate(const Value: Variant): Integer;
  130.     function PutConstDateTime(const Value: Variant): Integer;
  131.     function PutConstFloat(const Value: Variant): Integer;
  132.     function PutConstInt(DataType: TFieldType; const Value: Variant): Integer;
  133.     function PutConstNode(DataType: TFieldType; Data: PChar;
  134.       Size: Integer): Integer;
  135.     function PutConstStr(const Value: string): Integer;
  136.     function PutConstTime(const Value: Variant): Integer;
  137.     function PutData(Data: PChar; Size: Integer): Integer;
  138.     function PutExprNode(Node: PExprNode; ParentOp: TCANOperator): Integer;
  139.     function PutFieldNode(Field: TField; Node: PExprNode): Integer;
  140.     function PutNode(NodeType: NodeClass; OpType: TCANOperator;
  141.       OpCount: Integer): Integer;
  142.     procedure SetNodeOp(Node, Index, Data: Integer);
  143.     function PutConstant(Node: PExprNode): Integer;
  144.     function GetFieldByName(Name: string) : TField;
  145.   public
  146.     constructor Create(DataSet: TDataSet; Options: TFilterOptions;
  147.       ParseOptions: TParserOptions; const FieldName: string; DepFields: TBits;
  148.       FieldMap: TFieldMap);
  149.     destructor Destroy; override;
  150.     function NewCompareNode(Field: TField; Operator: TCANOperator;
  151.       const Value: Variant): PExprNode;
  152.     function NewNode(Kind: TExprNodeKind; Operator: TCANOperator;
  153.       const Data: Variant; Left, Right: PExprNode): PExprNode;
  154.     function GetFilterData(Root: PExprNode): TExprData;
  155.     property DataSet: TDataSet write FDataSet;
  156.   end;
  157.  
  158. { TExprParser }
  159.  
  160.   TExprToken = (etEnd, etSymbol, etName, etLiteral,  etLParen, etRParen,
  161.     etEQ, etNE, etGE, etLE, etGT, etLT, etADD, etSUB, etMUL, etDIV,
  162.     etComma, etLIKE, etISNULL, etISNOTNULL, etIN);
  163.  
  164.   TExprParser = class
  165.   private
  166.     FFilter: TFilterExpr;
  167.     FFieldMap: TFieldMap;
  168.     FText: string;
  169.     FSourcePtr: PChar;
  170.     FTokenPtr: PChar;
  171.     FTokenString: string;
  172.     FStrTrue: string;
  173.     FStrFalse: string;
  174.     FToken: TExprToken;
  175.     FPrevToken: TExprToken;
  176.     FFilterData: TExprData;
  177.     FNumericLit: Boolean;
  178.     FDataSize: Integer;
  179.     FParserOptions: TParserOptions;
  180.     FFieldName: string;
  181.     FDataSet: TDataSet;
  182.     FDependentFields: TBits;
  183.     procedure NextToken;
  184.     function NextTokenIsLParen : Boolean;
  185.     function ParseExpr: PExprNode;
  186.     function ParseExpr2: PExprNode;
  187.     function ParseExpr3: PExprNode;
  188.     function ParseExpr4: PExprNode;
  189.     function ParseExpr5: PExprNode;
  190.     function ParseExpr6: PExprNode;
  191.     function ParseExpr7: PExprNode;
  192.     function TokenName: string;
  193.     function TokenSymbolIs(const S: string): Boolean;
  194.     function TokenSymbolIsFunc(const S: string) : Boolean;
  195.     procedure GetFuncResultInfo(Node: PExprNode);
  196.     procedure TypeCheckArithOp(Node: PExprNode);
  197.     procedure GetScopeKind(Root, Left, Right : PExprNode);
  198.   public
  199.     constructor Create(DataSet: TDataSet; const Text: string;
  200.       Options: TFilterOptions; ParserOptions: TParserOptions;
  201.       const FieldName: string; DepFields: TBits; FieldMap: TFieldMap);
  202.     destructor Destroy; override;
  203.     procedure SetExprParams(const Text: string; Options: TFilterOptions;
  204.       ParserOptions: TParserOptions; const FieldName: string);
  205.     property FilterData: TExprData read FFilterData;
  206.     property DataSize: Integer read FDataSize;
  207.   end;
  208.  
  209. { Field Origin parser }
  210.  
  211. type
  212.   TFieldInfo = record
  213.     DatabaseName: string;
  214.     TableName: string;
  215.     OriginalFieldName: string;
  216.   end;
  217.  
  218. function GetFieldInfo(const Origin: string; var FieldInfo: TFieldInfo): Boolean;
  219.  
  220. { SQL Parser }
  221.  
  222. type
  223.   TSQLToken = (stUnknown, stTableName, stFieldName, stAscending, stDescending, stSelect,
  224.     stFrom, stWhere, stGroupBy, stHaving, stUnion, stPlan, stOrderBy, stForUpdate,
  225.     stEnd, stPredicate, stValue, stIsNull, stIsNotNull, stLike, stAnd, stOr,
  226.     stNumber, stAllFields, stComment, stDistinct);
  227.  
  228. const
  229.   SQLSections = [stSelect, stFrom, stWhere, stGroupBy, stHaving, stUnion,
  230.     stPlan, stOrderBy, stForUpdate];
  231.  
  232. function NextSQLToken(var p: PChar; out Token: string; CurSection: TSQLToken): TSQLToken;
  233. function GetIndexForOrderBy(const SQL: string; DataSet: TDataSet): TIndexDef;
  234. function GetTableNameFromSQL(const SQL: string): string;
  235.  
  236. implementation
  237.  
  238. uses SysUtils, DBConsts;
  239.  
  240. { SQL Parser }
  241.  
  242. function NextSQLToken(var p: PChar; out Token: string; CurSection: TSQLToken): TSQLToken;
  243. var
  244.   DotStart: Boolean;
  245.  
  246.   function NextTokenIs(Value: string; var Str: string): Boolean;
  247.   var
  248.     Tmp: PChar;
  249.     S: string;
  250.   begin
  251.     Tmp := p;
  252.     NextSQLToken(Tmp, S, CurSection);
  253.     Result := AnsiCompareText(Value, S) = 0;
  254.     if Result then
  255.     begin
  256.       Str := Str + ' ' + S;
  257.       p := Tmp;
  258.     end;
  259.   end;
  260.  
  261.   function GetSQLToken(var Str: string): TSQLToken;
  262.   var
  263.     l: PChar;
  264.     s: string;
  265.   begin
  266.     if Length(Str) = 0 then
  267.       Result := stEnd else
  268.     if (Str = '*') and (CurSection = stSelect) then
  269.       Result := stAllFields else
  270.     if DotStart then
  271.       Result := stFieldName else
  272.     if (AnsiCompareText('DISTINCT', Str) = 0) and (CurSection = stSelect) then
  273.       Result := stDistinct else 
  274.     if (AnsiCompareText('ASC', Str) = 0) or (AnsiCompareText('ASCENDING', Str) = 0)then
  275.       Result := stAscending else
  276.     if (AnsiCompareText('DESC', Str) = 0) or (AnsiCompareText('DESCENDING', Str) = 0)then
  277.       Result := stDescending else
  278.     if AnsiCompareText('SELECT', Str) = 0 then
  279.       Result := stSelect else
  280.     if AnsiCompareText('AND', Str) = 0 then
  281.       Result := stAnd else
  282.     if AnsiCompareText('OR', Str) = 0 then
  283.       Result := stOr else
  284.     if AnsiCompareText('LIKE', Str) = 0 then
  285.       Result := stLike else
  286.     if (AnsiCompareText('IS', Str) = 0) then
  287.     begin
  288.       if NextTokenIs('NULL', Str) then
  289.         Result := stIsNull else
  290.       begin
  291.         l := p;
  292.         s := Str;
  293.         if NextTokenIs('NOT', Str) and NextTokenIs('NULL', Str) then
  294.           Result := stIsNotNull else
  295.         begin
  296.           p := l;
  297.           Str := s;
  298.           Result := stValue;
  299.         end;
  300.       end;
  301.     end else
  302.     if AnsiCompareText('FROM', Str) = 0 then
  303.       Result := stFrom else
  304.     if AnsiCompareText('WHERE', Str) = 0 then
  305.       Result := stWhere else
  306.     if (AnsiCompareText('GROUP', Str) = 0) and NextTokenIs('BY', Str) then
  307.       Result := stGroupBy else
  308.     if AnsiCompareText('HAVING', Str) = 0 then
  309.       Result := stHaving else
  310.     if AnsiCompareText('UNION', Str) = 0 then
  311.       Result := stUnion else
  312.     if AnsiCompareText('PLAN', Str) = 0 then
  313.       Result := stPlan else
  314.     if (AnsiCompareText('FOR', Str) = 0) and NextTokenIs('UPDATE', Str) then
  315.       Result := stForUpdate else
  316.     if (AnsiCompareText('ORDER', Str) = 0) and NextTokenIs('BY', Str)  then
  317.       Result := stOrderBy else
  318.     if AnsiCompareText('NULL', Str) = 0 then
  319.       Result := stValue else
  320.     if CurSection = stFrom then
  321.       Result := stTableName else
  322.       Result := stFieldName;
  323.   end;
  324.  
  325. var
  326.   TokenStart: PChar;
  327.  
  328.   procedure StartToken;
  329.   begin
  330.     if not Assigned(TokenStart) then
  331.       TokenStart := p;
  332.   end;
  333.  
  334. var
  335.   Literal: Char;
  336.   Mark: PChar;
  337. begin
  338.   TokenStart := nil;
  339.   DotStart := False;
  340.   while True do
  341.   begin
  342.     case p^ of
  343.       '"','''','`':
  344.       begin
  345.         StartToken;
  346.         Literal := p^;
  347.         Mark := p;
  348.         repeat Inc(p) until (p^ in [Literal,#0]);
  349.         if p^ = #0 then
  350.         begin
  351.           p := Mark;
  352.           Inc(p);
  353.         end else
  354.         begin
  355.           Inc(p);
  356.           SetString(Token, TokenStart, p - TokenStart);
  357.           Mark := PChar(Token);
  358.           Token := AnsiExtractQuotedStr(Mark, Literal);
  359.           if DotStart then
  360.             Result := stFieldName else
  361.           if p^ = '.' then
  362.             Result := stTableName else
  363.             Result := stValue;
  364.           Exit;
  365.         end;
  366.       end;
  367.       '/':
  368.       begin
  369.         StartToken;
  370.         Inc(p);
  371.         if p^ in ['/','*'] then
  372.         begin
  373.           if p^ = '*' then
  374.           begin
  375.             repeat Inc(p) until (p = #0) or ((p^ = '*') and (p[1] = '/'));
  376.           end else
  377.             while not (p^ in [#0, #10, #13]) do Inc(p);
  378.           SetString(Token, TokenStart, p - TokenStart);
  379.           Result := stComment;
  380.           Exit;
  381.         end;
  382.       end;
  383.       ' ', #10, #13, ',':
  384.       begin
  385.         if Assigned(TokenStart) then
  386.         begin
  387.           SetString(Token, TokenStart, p - TokenStart);
  388.           Result := GetSQLToken(Token);
  389.           Exit;
  390.         end else
  391.           while (p^ in [' ', #10, #13, ',']) do Inc(p);
  392.       end;
  393.       '.':
  394.       begin
  395.         if Assigned(TokenStart) then
  396.         begin
  397.           SetString(Token, TokenStart, p - TokenStart);
  398.           Result := stTableName;
  399.           Exit;
  400.         end else
  401.         begin
  402.           DotStart := True;
  403.           Inc(p);
  404.         end;
  405.       end;
  406.       '=','<','>':
  407.       begin
  408.         if not Assigned(TokenStart) then
  409.         begin
  410.           TokenStart := p;
  411.           while p^ in ['=','<','>'] do Inc(p);
  412.           SetString(Token, TokenStart, p - TokenStart);
  413.           Result := stPredicate;
  414.           Exit;
  415.         end;
  416.         Inc(p);
  417.       end;
  418.       '0'..'9':
  419.       begin
  420.         if not Assigned(TokenStart) then
  421.         begin
  422.           TokenStart := p;
  423.           while p^ in ['0'..'9','.'] do Inc(p);
  424.           SetString(Token, TokenStart, p - TokenStart);
  425.           Result := stNumber;
  426.           Exit;
  427.         end else
  428.           Inc(p);
  429.       end;
  430.       #0:
  431.       begin
  432.         if Assigned(TokenStart) then
  433.         begin
  434.           SetString(Token, TokenStart, p - TokenStart);
  435.           Result := GetSQLToken(Token);
  436.           Exit;
  437.         end else
  438.         begin
  439.           Result := stEnd;
  440.           Token := '';
  441.           Exit;
  442.         end;
  443.       end;
  444.     else
  445.       StartToken;
  446.       Inc(p);
  447.     end;
  448.   end;
  449. end;
  450.  
  451. function GetTableNameFromSQL(const SQL: string): string;
  452. var
  453.   Start: PChar;
  454.   Token: string;
  455.   SQLToken, CurSection: TSQLToken;
  456. begin
  457.   Result := '';
  458.   Start := PChar(SQL);
  459.   CurSection := stUnknown;
  460.   repeat
  461.     SQLToken := NextSQLToken(Start, Token, CurSection);
  462.     if SQLToken in SQLSections then CurSection := SQLToken;
  463.   until SQLToken in [stEnd, stFrom];
  464.   if SQLToken = stFrom then
  465.   begin
  466.     repeat
  467.       SQLToken := NextSQLToken(Start, Token, CurSection);
  468.       if SQLToken in SQLSections then
  469.         CurSection := SQLToken else
  470.       if SQLToken = stTableName then
  471.       begin
  472.         Result := Token;
  473.         Exit;
  474.       end;
  475.     until (CurSection <> stFrom) or (SQLToken in [stEnd, stTableName]);
  476.   end;
  477. end;
  478.  
  479. function GetIndexForOrderBy(const SQL: string; DataSet: TDataSet): TIndexDef;
  480.  
  481.   function AddField(const Fields, NewField: string): string;
  482.   begin
  483.     Result := Fields;
  484.     if Fields <> '' then
  485.       Result := Fields + ';' + NewField else
  486.       Result := NewField;
  487.   end;
  488.  
  489. var
  490.   Start: PChar;
  491.   Token, LastField: string;
  492.   SQLToken, CurSection: TSQLToken;
  493.   FieldIndex: Integer;
  494. begin
  495.   Result := nil;
  496.   Start := PChar(SQL);
  497.   CurSection := stUnknown;
  498.   repeat
  499.     SQLToken := NextSQLToken(Start, Token, CurSection);
  500.     if SQLToken in SQLSections then CurSection := SQLToken;
  501.   until SQLToken in [stEnd, stOrderBy];
  502.   if SQLToken = stOrderBy then
  503.   begin
  504.     Result := TIndexDef.Create(nil);
  505.     try
  506.       LastField := '';
  507.       repeat
  508.         SQLToken := NextSQLToken(Start, Token, CurSection);
  509.         if SQLToken in SQLSections then
  510.           CurSection := SQLToken else
  511.           case SQLToken of
  512.             stTableName: ;
  513.             stFieldName:
  514.             begin
  515.               LastField := Token;
  516.               Result.Fields := AddField(Result.Fields, LastField);
  517.             end;
  518.             stAscending: ;
  519.             stDescending:
  520.               Result.DescFields := AddField(Result.DescFields, LastField);
  521.             stNumber:
  522.             begin
  523.               FieldIndex := StrToInt(Token);
  524.               if DataSet.FieldCount >= FieldIndex then
  525.                 LastField := DataSet.Fields[FieldIndex - 1].FieldName else
  526.               if DataSet.FieldDefs.Count >= FieldIndex then
  527.                 LastField := DataSet.FieldDefs[FieldIndex - 1].Name else
  528.                 SysUtils.Abort;
  529.               Result.Fields := AddField(Result.Fields, LastField);
  530.             end;
  531.           end;
  532.       until (CurSection <> stOrderBy) or (SQLToken = stEnd);
  533.     except
  534.       Result.Free;
  535.       Result := nil;
  536.     end;
  537.   end;
  538. end;
  539.  
  540. function GetFieldInfo(const Origin: string; var FieldInfo: TFieldInfo): Boolean;
  541. var
  542.   Current: PChar;
  543.   Values: array[0..4] of string;
  544.   I: Integer;
  545.  
  546.   function GetPChar(const S: string): PChar;
  547.   begin
  548.     if S <> '' then Result := PChar(Pointer(S)) else Result := '';
  549.   end;
  550.  
  551.   procedure Split(const S: string);
  552.   begin
  553.     Current := PChar(Pointer(S));
  554.   end;
  555.  
  556.   function NextItem: string;
  557.   var
  558.     C: PChar;
  559.     I: PChar;
  560.     Terminator: Char;
  561.     Ident: array[0..1023] of Char;
  562.   begin
  563.     Result := '';
  564.     C := Current;
  565.     I := Ident;
  566.     while C^ in ['.',' ',#0] do
  567.       if C^ = #0 then Exit else Inc(C);
  568.     Terminator := '.';
  569.     if C^ = '"' then
  570.     begin
  571.       Terminator := '"';
  572.       Inc(C);
  573.     end;
  574.     while not (C^ in [Terminator, #0]) do
  575.     begin
  576.       if C^ in LeadBytes then
  577.       begin
  578.         I^ := C^;
  579.         Inc(C);
  580.         Inc(I);
  581.       end
  582.       else if C^ = '\' then
  583.       begin
  584.         Inc(C);
  585.         if C^ in LeadBytes then
  586.         begin
  587.           I^ := C^;
  588.           Inc(C);
  589.           Inc(I);
  590.         end;
  591.         if C^ = #0 then Dec(C);
  592.       end;
  593.       I^ := C^;
  594.       Inc(C);
  595.       Inc(I);
  596.     end;
  597.     SetString(Result, Ident, I - Ident);
  598.     if (Terminator = '"') and (C^ <> #0) then Inc(C);
  599.     Current := C;
  600.   end;
  601.  
  602.   function PopValue: PChar;
  603.   begin
  604.     if I >= 0 then
  605.     begin
  606.       Result := GetPChar(Values[I]);
  607.       Dec(I);
  608.     end else Result := '';
  609.   end;
  610.  
  611. begin
  612.   Result := False;
  613.   if (Origin = '') then Exit;
  614.   Split(Origin);
  615.   I := -1;
  616.   repeat
  617.     Inc(I);
  618.     Values[I] := NextItem;
  619.   until (Values[I] = '') or (I = High(Values));
  620.   if I = High(Values) then Exit;
  621.   Dec(I);
  622.   FieldInfo.OriginalFieldName := StrPas(PopValue);
  623.   FieldInfo.TableName := StrPas(PopValue);
  624.   FieldInfo.DatabaseName := StrPas(PopValue);
  625.   Result := (FieldInfo.OriginalFieldName <> '') and (FieldInfo.TableName <> '');
  626. end;
  627.  
  628. const
  629.   StringFieldTypes = [ftString, ftFixedChar, ftWideString, ftGuid];
  630.   BlobFieldTypes = [ftBlob, ftMemo, ftGraphic, ftFmtMemo, ftParadoxOle, ftDBaseOle,
  631.     ftTypedBinary, ftOraBlob, ftOraClob];
  632.  
  633. function IsNumeric(DataType: TFieldType): Boolean;
  634. begin
  635.   Result := DataType in [ftSmallint, ftInteger, ftWord, ftFloat, ftCurrency,
  636.     ftBCD, ftAutoInc, ftLargeint];
  637. end;
  638.  
  639. function IsTemporal(DataType: TFieldType): Boolean;
  640. begin
  641.   Result := DataType in [ftDate, ftTime, ftDateTime];
  642. end;
  643.  
  644. { TFilterExpr }
  645.  
  646. constructor TFilterExpr.Create(DataSet: TDataSet; Options: TFilterOptions;
  647.   ParseOptions: TParserOptions; const FieldName: string; DepFields: TBits;
  648.   FieldMap: TFieldMap);
  649. begin
  650.   FFieldMap := FieldMap;
  651.   FDataSet := DataSet;
  652.   FOptions := Options;
  653.   FFieldName := FieldName;
  654.   FParserOptions := ParseOptions;
  655.   FDependentFields := DepFields;
  656. end;
  657.  
  658. destructor TFilterExpr.Destroy;
  659. var
  660.   Node: PExprNode;
  661. begin
  662.   SetLength(FExprBuffer, 0);
  663.   while FNodes <> nil do
  664.   begin
  665.     Node := FNodes;
  666.     FNodes := Node^.FNext;
  667.     if (Node^.FKind = enFunc) and (Node^.FArgs <> nil) then
  668.       Node^.FArgs.Free;
  669.     Dispose(Node);
  670.   end;
  671. end;
  672.  
  673. function TFilterExpr.FieldFromNode(Node: PExprNode): TField;
  674. begin
  675.   Result := GetFieldByName(Node^.FData);
  676.   if not (Result.FieldKind in [fkData, fkInternalCalc]) then
  677.     DatabaseErrorFmt(SExprBadField, [Result.FieldName]);
  678. end;
  679.  
  680. function TFilterExpr.GetExprData(Pos, Size: Integer): PChar;
  681. begin
  682.   SetLength(FExprBuffer, FExprBufSize + Size);
  683.   Move(FExprBuffer[Pos], FExprBuffer[Pos + Size], FExprBufSize - Pos);
  684.   Inc(FExprBufSize, Size);
  685.   Result := PChar(FExprBuffer) + Pos;
  686. end;
  687.  
  688. function TFilterExpr.GetFilterData(Root: PExprNode): TExprData;
  689. begin
  690.   FExprBufSize := CANExprSize;
  691.   SetLength(FExprBuffer, FExprBufSize);
  692.   PutExprNode(Root, coNOTDEFINED);
  693.   PWord(@FExprBuffer[0])^ := CANEXPRVERSION;                { iVer }
  694.   PWord(@FExprBuffer[2])^ := FExprBufSize;                  { iTotalSize }
  695.   PWord(@FExprBuffer[4])^ := $FFFF;                         { iNodes }
  696.   PWord(@FExprBuffer[6])^ := CANEXPRSIZE;                   { iNodeStart }
  697.   PWord(@FExprBuffer[8])^ := FExprNodeSize + CANEXPRSIZE;   { iLiteralStart }
  698.   Result := FExprBuffer;
  699. end;
  700.  
  701. function TFilterExpr.NewCompareNode(Field: TField; Operator: TCANOperator;
  702.   const Value: Variant): PExprNode;
  703. var
  704.   ConstExpr: PExprNode;
  705. begin
  706.   ConstExpr := NewNode(enConst, coNOTDEFINED, Value, nil, nil);
  707.   ConstExpr^.FDataType := Field.DataType;
  708.   ConstExpr^.FDataSize := Field.Size;
  709.   Result := NewNode(enOperator, Operator, Unassigned,
  710.     NewNode(enField, coNOTDEFINED, Field.FieldName, nil, nil), ConstExpr);
  711. end;
  712.  
  713. function TFilterExpr.NewNode(Kind: TExprNodeKind; Operator: TCANOperator;
  714.   const Data: Variant; Left, Right: PExprNode): PExprNode;
  715. var
  716.   Field : TField;
  717. begin
  718.   New(Result);
  719.   with Result^ do
  720.   begin
  721.     FNext := FNodes;
  722.     FKind := Kind;
  723.     FPartial := False;
  724.     FOperator := Operator;
  725.     FData := Data;
  726.     FLeft := Left;
  727.     FRight := Right;
  728.   end;
  729.   FNodes := Result;
  730.   if Kind = enField then
  731.   begin
  732.     Field := GetFieldByName(Data);
  733.     if Field = nil then
  734.       DatabaseErrorFmt(SFieldNotFound, [Data]);
  735.     Result^.FDataType := Field.DataType;
  736.     Result^.FDataSize := Field.Size;
  737.   end;
  738. end;
  739.  
  740. function TFilterExpr.PutConstBCD(const Value: Variant;
  741.   Decimals: Integer): Integer;
  742. var
  743.   C: Currency;
  744.   BCD: TBcd;
  745. begin
  746.   if VarType(Value) = varString then
  747.     C := StrToCurr(string(TVarData(Value).VString)) else
  748.     C := Value;
  749.   CurrToBCD(C, BCD, 32, Decimals);
  750.   Result := PutConstNode(ftBCD, @BCD, 18);
  751. end;
  752.  
  753. function TFilterExpr.PutConstBool(const Value: Variant): Integer;
  754. var
  755.   B: WordBool;
  756. begin
  757.   B := Value;
  758.   Result := PutConstNode(ftBoolean, @B, SizeOf(WordBool));
  759. end;
  760.  
  761. function TFilterExpr.PutConstDate(const Value: Variant): Integer;
  762. var
  763.   DateTime: TDateTime;
  764.   TimeStamp: TTimeStamp;
  765. begin
  766.   if VarType(Value) = varString then
  767.     DateTime := StrToDate(string(TVarData(Value).VString)) else
  768.     DateTime := VarToDateTime(Value);
  769.   TimeStamp := DateTimeToTimeStamp(DateTime);
  770.   Result := PutConstNode(ftDate, @TimeStamp.Date, 4);
  771. end;
  772.  
  773. function TFilterExpr.PutConstDateTime(const Value: Variant): Integer;
  774. var
  775.   DateTime: TDateTime;
  776.   DateData: Double;
  777. begin
  778.   if VarType(Value) = varString then
  779.     DateTime := StrToDateTime(string(TVarData(Value).VString)) else
  780.     DateTime := VarToDateTime(Value);
  781.   DateData := TimeStampToMSecs(DateTimeToTimeStamp(DateTime));
  782.   Result := PutConstNode(ftDateTime, @DateData, 8);
  783. end;
  784.  
  785. function TFilterExpr.PutConstFloat(const Value: Variant): Integer;
  786. var
  787.   F: Double;
  788. begin
  789.   if VarType(Value) = varString then
  790.     F := StrToFloat(string(TVarData(Value).VString)) else
  791.     F := Value;
  792.   Result := PutConstNode(ftFloat, @F, SizeOf(Double));
  793. end;
  794.  
  795. function TFilterExpr.PutConstInt(DataType: TFieldType;
  796.   const Value: Variant): Integer;
  797. var
  798.   I, Size: Integer;
  799. begin
  800.   if VarType(Value) = varString then
  801.     I := StrToInt(string(TVarData(Value).VString)) else
  802.     I := Value;
  803.   Size := 2;
  804.   case DataType of
  805.     ftSmallint:
  806.       if (I < -32768) or (I > 32767) then DatabaseError(SExprRangeError);
  807.     ftWord:
  808.       if (I < 0) or (I > 65535) then DatabaseError(SExprRangeError);
  809.   else
  810.     Size := 4;
  811.   end;
  812.   Result := PutConstNode(DataType, @I, Size);
  813. end;
  814.  
  815. function TFilterExpr.PutConstNode(DataType: TFieldType; Data: PChar;
  816.   Size: Integer): Integer;
  817. begin
  818.   Result := PutNode(nodeCONST, coCONST2, 3);
  819.   SetNodeOp(Result, 0, FFieldMap[DataType]);
  820.   SetNodeOp(Result, 1, Size);
  821.   SetNodeOp(Result, 2, PutData(Data, Size));
  822. end;
  823.  
  824. function TFilterExpr.PutConstStr(const Value: string): Integer;
  825. var
  826.   Str: string;
  827.   Buffer: array[0..255] of Char;
  828. begin
  829.   if Length(Value) >= SizeOf(Buffer) then
  830.     Str := Copy(Value, 1, SizeOf(Buffer) - 1) else
  831.     Str := Value;
  832.   FDataSet.Translate(PChar(Str), Buffer, True);
  833.   Result := PutConstNode(ftString, Buffer, Length(Str) + 1);
  834. end;
  835.  
  836. function TFilterExpr.PutConstTime(const Value: Variant): Integer;
  837. var
  838.   DateTime: TDateTime;
  839.   TimeStamp: TTimeStamp;
  840. begin
  841.   if VarType(Value) = varString then
  842.     DateTime := StrToTime(string(TVarData(Value).VString)) else
  843.     DateTime := VarToDateTime(Value);
  844.   TimeStamp := DateTimeToTimeStamp(DateTime);
  845.   Result := PutConstNode(ftTime, @TimeStamp.Time, 4);
  846. end;
  847.  
  848. function TFilterExpr.PutData(Data: PChar; Size: Integer): Integer;
  849. begin
  850.   Move(Data^, GetExprData(FExprBufSize, Size)^, Size);
  851.   Result := FExprDataSize;
  852.   Inc(FExprDataSize, Size);
  853. end;
  854.  
  855. function TFilterExpr.PutConstant(Node: PExprNode): Integer;
  856. begin
  857.   Result := 0;
  858.   case Node^.FDataType of
  859.     ftSmallInt, ftInteger, ftWord, ftAutoInc:
  860.       Result := PutConstInt(Node^.FDataType, Node^.FData);
  861.     ftFloat, ftCurrency:
  862.       Result := PutConstFloat(Node^.FData);
  863.     ftString, ftWideString, ftFixedChar, ftGuid:
  864.       Result := PutConstStr(Node^.FData);
  865.     ftDate:
  866.       Result := PutConstDate(Node^.FData);
  867.     ftTime:
  868.       Result := PutConstTime(Node^.FData);
  869.     ftDateTime:
  870.       Result := PutConstDateTime(Node^.FData);
  871.     ftBoolean:
  872.       Result := PutConstBool(Node^.FData);
  873.     ftBCD:
  874.       Result := PutConstBCD(Node^.FData, Node^.FDataSize);
  875.     else
  876.       DatabaseErrorFmt(SExprBadConst, [Node^.FData]);
  877.   end;
  878. end;
  879.  
  880. function TFilterExpr.PutExprNode(Node: PExprNode; ParentOp: TCANOperator): Integer;
  881. const
  882.   ReverseOperator: array[coEQ..coLE] of TCANOperator = (coEQ, coNE, coLT,
  883.     coGT, coLE, coGE);
  884.   BoolFalse: WordBool = False;
  885. var
  886.   Field: TField;
  887.   Left, Right, Temp : PExprNode;
  888.   LeftPos, RightPos, ListElem, PrevListElem, I: Integer;
  889.   Operator: TCANOperator;
  890.   CaseInsensitive, PartialLength, L:  Integer;
  891.   S: string;
  892. begin
  893.   Result := 0;
  894.   case Node^.FKind of
  895.     enField:
  896.       begin
  897.         Field := FieldFromNode(Node);
  898.         if (ParentOp in [coOR, coNOT, coAND, coNOTDEFINED]) and
  899.            (Field.DataType = ftBoolean) then
  900.         begin
  901.           Result := PutNode(nodeBINARY, coNE, 2);
  902.           SetNodeOp(Result, 0, PutFieldNode(Field, Node));
  903.           SetNodeOp(Result, 1, PutConstNode(ftBoolean, @BoolFalse, SizeOf(WordBool)));
  904.         end
  905.         else
  906.           Result := PutFieldNode(Field, Node);
  907.       end;
  908.     enConst:
  909.       Result := PutConstant(Node);
  910.     enOperator:
  911.       case Node^.FOperator of
  912.         coIN:
  913.           begin
  914.             Result := PutNode(nodeBINARY, coIN, 2);
  915.             SetNodeOp(Result, 0, PutExprNode(Node^.FLeft,Node^.FOperator));
  916.             ListElem := PutNode(nodeLISTELEM, coLISTELEM2, 2);
  917.             SetNodeOp(Result, 1, ListElem);
  918.             PrevListElem := ListElem;
  919.             for I := 0 to Node^.FArgs.Count - 1 do 
  920.             begin
  921.               LeftPos := PutExprNode(Node^.FArgs.Items[I],Node^.FOperator);
  922.               if I = 0 then 
  923.                 begin
  924.                   SetNodeOp(PrevListElem, 0, LeftPos);
  925.                   SetNodeOp(PrevListElem, 1, 0);
  926.                 end
  927.               else
  928.                 begin
  929.                   ListElem := PutNode(nodeLISTELEM, coLISTELEM2, 2);
  930.                   SetNodeOp(ListElem, 0, LeftPos);
  931.                   SetNodeOp(ListElem, 1, 0);
  932.                   SetNodeOp(PrevListElem, 1, ListElem);
  933.                   PrevListElem := ListElem;
  934.                 end;
  935.               end;
  936.           end;
  937.         coNOT,
  938.         coISBLANK,
  939.         coNOTBLANK:
  940.           begin
  941.             Result := PutNode(nodeUNARY, Node^.FOperator, 1);
  942.             SetNodeOp(Result, 0, PutExprNode(Node^.FLeft,Node^.FOperator));
  943.           end;
  944.         coEQ..coLE,
  945.         coAND,coOR,
  946.         coADD..coDIV,
  947.         coLIKE,
  948.         coASSIGN:
  949.           begin
  950.             Operator := Node^.FOperator;
  951.             Left := Node^.FLeft;
  952.             Right := Node^.FRight;
  953.             if (Operator in [coEQ..coLE]) and (Right^.FKind = enField) and
  954.                (Left^.FKind <> enField) then
  955.             begin
  956.               Temp := Left;
  957.               Left := Right;
  958.               Right := Temp;
  959.               Operator := ReverseOperator[Operator];
  960.             end;
  961.  
  962.             Result := 0;
  963.             if (Left^.FKind = enField) and (Right^.FKind = enConst)
  964.                and ((Node^.FOperator = coEQ)  or (Node^.FOperator = coNE)
  965.                or (Node^.FOperator = coLIKE)) then
  966.             begin
  967.               if VarIsNull(Right^.FData) then
  968.               begin
  969.                 case Node^.FOperator of
  970.                   coEQ: Operator := coISBLANK;
  971.                   coNE: Operator := coNOTBLANK;
  972.                 else
  973.                   DatabaseError(SExprBadNullTest);
  974.                 end;
  975.                 Result := PutNode(nodeUNARY, Operator, 1);
  976.                 SetNodeOp(Result, 0, PutExprNode(Left,Node^.FOperator));
  977.               end
  978.               else if (Right^.FDataType in StringFieldTypes) then
  979.               begin
  980.                 S := Right^.FData;
  981.                 L := Length(S);
  982.                 if L <> 0 then
  983.                 begin
  984.                   CaseInsensitive := 0;
  985.                   PartialLength := 0;
  986.                   if foCaseInsensitive in FOptions then CaseInsensitive := 1;
  987.                   if Node^.FPartial then PartialLength := L else
  988.                     if not (foNoPartialCompare in FOptions) and (L > 1) and
  989.                       (S[L] = '*') then
  990.                     begin
  991.                       Delete(S, L, 1);
  992.                       PartialLength := L - 1;
  993.                     end;
  994.                   if (CaseInsensitive <> 0) or (PartialLength <> 0) then
  995.                   begin
  996.                     Result := PutNode(nodeCOMPARE, Operator, 4);
  997.                     SetNodeOp(Result, 0, CaseInsensitive);
  998.                     SetNodeOp(Result, 1, PartialLength);
  999.                     SetNodeOp(Result, 2, PutExprNode(Left,Node^.FOperator));
  1000.                     SetNodeOp(Result, 3, PutConstStr(S));
  1001.                   end;
  1002.                 end;
  1003.               end;
  1004.             end;
  1005.  
  1006.             if Result = 0 then
  1007.             begin
  1008.               if (Operator = coISBLANK) or (Operator = coNOTBLANK) then
  1009.               begin
  1010.                 Result := PutNode(nodeUNARY, Operator, 1);
  1011.                 LeftPos := PutExprNode(Left,Node^.FOperator);
  1012.                 SetNodeOp(Result, 0, LeftPos);
  1013.               end else
  1014.               begin
  1015.                 Result := PutNode(nodeBINARY, Operator, 2);
  1016.                 LeftPos := PutExprNode(Left,Node^.FOperator);
  1017.                 RightPos := PutExprNode(Right,Node^.FOperator);
  1018.                 SetNodeOp(Result, 0, LeftPos);
  1019.                 SetNodeOp(Result, 1, RightPos);
  1020.               end;
  1021.             end;
  1022.           end;
  1023.       end;
  1024.     enFunc:
  1025.       begin
  1026.         Result := PutNode(nodeFUNC, coFUNC2, 2);
  1027.         SetNodeOp(Result, 0,  PutData(PChar(string(Node^.FData)),
  1028.           Length(string(Node^.FData)) + 1));
  1029.         if Node^.FArgs <> nil then
  1030.         begin
  1031.           ListElem := PutNode(nodeLISTELEM, coLISTELEM2, 2);
  1032.           SetNodeOp(Result, 1, ListElem);
  1033.           PrevListElem := ListElem;
  1034.           for I := 0 to Node^.FArgs.Count - 1 do
  1035.           begin
  1036.             LeftPos := PutExprNode(Node^.FArgs.Items[I],Node^.FOperator);
  1037.             if I = 0 then
  1038.             begin
  1039.               SetNodeOp(PrevListElem, 0, LeftPos);
  1040.               SetNodeOp(PrevListElem, 1, 0);
  1041.             end
  1042.             else
  1043.             begin
  1044.               ListElem := PutNode(nodeLISTELEM, coLISTELEM2, 2);
  1045.               SetNodeOp(ListElem, 0, LeftPos);
  1046.               SetNodeOp(ListElem, 1, 0);
  1047.               SetNodeOp(PrevListElem, 1, ListElem);
  1048.               PrevListElem := ListElem;
  1049.             end;
  1050.           end;
  1051.         end else
  1052.           SetNodeOp(Result, 1, 0);
  1053.       end;
  1054.   end;
  1055. end;
  1056.  
  1057.  
  1058. function TFilterExpr.PutFieldNode(Field: TField; Node: PExprNode): Integer;
  1059. var
  1060.   Buffer: array[0..255] of Char;
  1061. begin
  1062.   if poFieldNameGiven in FParserOptions then
  1063.     FDataSet.Translate(PChar(Field.FieldName), Buffer, True)
  1064.   else
  1065.     FDataSet.Translate(PChar(string(Node^.FData)), Buffer, True);
  1066.   Result := PutNode(nodeFIELD, coFIELD2, 2);
  1067.   SetNodeOp(Result, 0, Field.FieldNo);
  1068.   SetNodeOp(Result, 1, PutData(Buffer, StrLen(Buffer) + 1));
  1069. end;
  1070.  
  1071. function TFilterExpr.PutNode(NodeType: NodeClass; OpType: TCANOperator;
  1072.   OpCount: Integer): Integer;
  1073. var
  1074.   Size: Integer;
  1075.   Data: PChar;
  1076. begin
  1077.   Size := CANHDRSIZE + OpCount * SizeOf(Word);
  1078.   Data := GetExprData(CANEXPRSIZE + FExprNodeSize, Size);
  1079.   PInteger(@Data[0])^ := Integer(NodeType); { CANHdr.nodeClass }
  1080.   PInteger(@Data[4])^ := Integer(OpType);   { CANHdr.coOp }
  1081.   Result := FExprNodeSize;
  1082.   Inc(FExprNodeSize, Size);
  1083. end;
  1084.  
  1085. procedure TFilterExpr.SetNodeOp(Node, Index, Data: Integer);
  1086. begin
  1087.   PWordArray(PChar(FExprBuffer) + (CANEXPRSIZE + Node +
  1088.     CANHDRSIZE))^[Index] := Data;
  1089. end;
  1090.  
  1091. function TFilterExpr.GetFieldByName(Name: string) : TField;
  1092. var
  1093.   I: Integer;
  1094.   F: TField;
  1095.   FieldInfo: TFieldInfo;
  1096. begin
  1097.   Result := nil;
  1098.   if poFieldNameGiven in FParserOptions then
  1099.     Result := FDataSet.FieldByName(FFieldName)
  1100.   else if poUseOrigNames in FParserOptions then
  1101.   begin
  1102.     for I := 0 to FDataset.FieldCount - 1 do
  1103.     begin
  1104.       F := FDataSet.Fields[I];
  1105.       if GetFieldInfo(F.Origin, FieldInfo) and
  1106.          (AnsiCompareStr(Name, FieldInfo.OriginalFieldName) = 0) then
  1107.       begin
  1108.         Result := F;
  1109.         Exit;
  1110.       end;
  1111.     end;
  1112.   end;
  1113.   if Result = nil then
  1114.     Result := FDataSet.FieldByName(Name);
  1115.   if (Result <> nil) and (Result.FieldKind = fkCalculated) and (poAggregate in FParserOptions) then
  1116.     DatabaseErrorFmt(SExprNoAggOnCalcs, [Result.FieldName]);
  1117.   if (poFieldDepend in FParserOptions) and (Result <> nil) and
  1118.      (FDependentFields <> nil) then
  1119.     FDependentFields[Result.FieldNo-1] := True;
  1120. end;
  1121.  
  1122. constructor TExprParser.Create(DataSet: TDataSet; const Text: string;
  1123.   Options: TFilterOptions; ParserOptions: TParserOptions; const FieldName: string;
  1124.   DepFields: TBits; FieldMap: TFieldMap);
  1125. begin
  1126.   FFieldMap := FieldMap;
  1127.   FStrTrue := STextTrue;
  1128.   FStrFalse := STextFalse;
  1129.   FDataSet := DataSet;
  1130.   FDependentFields := DepFields;
  1131.   FFilter := TFilterExpr.Create(DataSet, Options, ParserOptions, FieldName,
  1132.     DepFields, FieldMap);
  1133.   if Text <> '' then
  1134.     SetExprParams(Text, Options, ParserOptions, FieldName);
  1135. end;
  1136.  
  1137. destructor TExprParser.Destroy;
  1138. begin
  1139.   FFilter.Free;
  1140. end;
  1141.  
  1142. procedure  TExprParser.SetExprParams(const Text: string; Options: TFilterOptions;
  1143.   ParserOptions: TParserOptions; const FieldName: string);
  1144. var
  1145.   Root, DefField: PExprNode;
  1146. begin
  1147.   FParserOptions := ParserOptions;
  1148.   if FFilter <> nil then
  1149.     FFilter.Free;
  1150.   FFilter := TFilterExpr.Create(FDataSet, Options, ParserOptions, FieldName,
  1151.     FDependentFields, FFieldMap);
  1152.   FText := Text;
  1153.   FSourcePtr := PChar(Text);
  1154.   FFieldName := FieldName;
  1155.   NextToken;
  1156.   Root := ParseExpr;
  1157.   if FToken <> etEnd then DatabaseError(SExprTermination);
  1158.   if (poAggregate in FParserOptions) and (Root^.FScopeKind <> skAgg) then
  1159.      DatabaseError(SExprNotAgg);
  1160.   if (not (poAggregate in FParserOptions)) and (Root^.FScopeKind = skAgg) then
  1161.      DatabaseError(SExprNoAggFilter);
  1162.   if poDefaultExpr in ParserOptions then
  1163.   begin
  1164.     DefField := FFilter.NewNode(enField, coNOTDEFINED, FFieldName, nil, nil);
  1165.     if (IsTemporal(DefField^.FDataType) and (Root^.FDataType in StringFieldTypes)) or
  1166.        ((DefField^.FDataType = ftBoolean ) and (Root^.FDataType in StringFieldTypes)) then
  1167.       Root^.FDataType := DefField^.FDataType;
  1168.  
  1169.     if not ((IsTemporal(DefField^.FDataType) and IsTemporal(Root^.FDataType))
  1170.        or (IsNumeric(DefField^.FDataType) and IsNumeric(Root^.FDataType))
  1171.        or ((DefField^.FDataType in StringFieldTypes) and (Root^.FDataType in StringFieldTypes))
  1172.        or ((DefField^.FDataType = ftBoolean) and (Root^.FDataType = ftBoolean))) then
  1173.       DatabaseError(SExprTypeMis);
  1174.     Root := FFilter.NewNode(enOperator, coASSIGN, Unassigned, Root, DefField);
  1175.   end;
  1176.  
  1177.   if not (poAggregate in FParserOptions) and not(poDefaultExpr in ParserOptions)
  1178.      and (Root^.FDataType <> ftBoolean ) then
  1179.      DatabaseError(SExprIncorrect);
  1180.  
  1181.   FFilterData := FFilter.GetFilterData(Root);
  1182.   FDataSize := FFilter.FExprBufSize;
  1183. end;
  1184.  
  1185. function TExprParser.NextTokenIsLParen : Boolean;
  1186. var
  1187.   P : PChar;
  1188. begin
  1189.   P := FSourcePtr;
  1190.   while (P^ <> #0) and (P^ <= ' ') do Inc(P);
  1191.   Result := P^ = '(';
  1192. end;
  1193.  
  1194. procedure TExprParser.NextToken;
  1195. type
  1196.   ASet = Set of Char;
  1197. var
  1198.   P, TokenStart: PChar;
  1199.   L: Integer;
  1200.   StrBuf: array[0..255] of Char;
  1201.  
  1202.   function IsKatakana(const Chr: Byte): Boolean;
  1203.   begin
  1204.     Result := (SysLocale.PriLangID = LANG_JAPANESE) and (Chr in [$A1..$DF]);
  1205.   end;
  1206.  
  1207.   procedure Skip(TheSet: ASet);
  1208.   begin
  1209.     while TRUE do
  1210.     begin
  1211.       if P^ in LeadBytes then
  1212.         Inc(P, 2)
  1213.       else if (P^ in TheSet) or IsKatakana(Byte(P^)) then
  1214.         Inc(P)
  1215.       else
  1216.         Exit;
  1217.     end;
  1218.   end;
  1219.  
  1220. begin
  1221.   FPrevToken := FToken;
  1222.   FTokenString := '';
  1223.   P := FSourcePtr;
  1224.   while (P^ <> #0) and (P^ <= ' ') do Inc(P);
  1225.   if (P^ <> #0) and (P^ = '/') and (P[1] <> #0) and (P[1] = '*')then
  1226.   begin
  1227.     P := P + 2;
  1228.     while (P^ <> #0) and (P^ <> '*') do Inc(P);
  1229.     if (P^ = '*') and (P[1] <> #0) and (P[1] =  '/')  then
  1230.       P := P + 2
  1231.     else
  1232.       DatabaseErrorFmt(SExprInvalidChar, [P^]);
  1233.   end;
  1234.   while (P^ <> #0) and (P^ <= ' ') do Inc(P);
  1235.   FTokenPtr := P;
  1236.   case P^ of
  1237.     'A'..'Z', 'a'..'z', '_', #$81..#$fe:
  1238.       begin
  1239.         TokenStart := P;
  1240.         if not SysLocale.FarEast then
  1241.         begin
  1242.           Inc(P);
  1243.           while P^ in ['A'..'Z', 'a'..'z', '0'..'9', '_', '.', '[', ']'] do Inc(P);
  1244.         end
  1245.         else
  1246.           Skip(['A'..'Z', 'a'..'z', '0'..'9', '_', '.', '[', ']']);
  1247.         SetString(FTokenString, TokenStart, P - TokenStart);
  1248.         FToken := etSymbol;
  1249.         if CompareText(FTokenString, 'LIKE') = 0 then   { do not localize }
  1250.           FToken := etLIKE
  1251.         else if CompareText(FTokenString, 'IN') = 0 then   { do not localize }
  1252.           FToken := etIN
  1253.         else if CompareText(FTokenString, 'IS') = 0 then    { do not localize }
  1254.         begin
  1255.           while (P^ <> #0) and (P^ <= ' ') do Inc(P);
  1256.           TokenStart := P;
  1257.           Skip(['A'..'Z', 'a'..'z']);
  1258.           SetString(FTokenString, TokenStart, P - TokenStart);
  1259.           if CompareText(FTokenString, 'NOT')= 0 then  { do not localize }
  1260.           begin
  1261.             while (P^ <> #0) and (P^ <= ' ') do Inc(P);
  1262.             TokenStart := P;
  1263.             Skip(['A'..'Z', 'a'..'z']);
  1264.             SetString(FTokenString, TokenStart, P - TokenStart);
  1265.             if CompareText(FTokenString, 'NULL') = 0 then
  1266.               FToken := etISNOTNULL
  1267.             else
  1268.               DatabaseError(SInvalidKeywordUse);
  1269.           end
  1270.           else if CompareText (FTokenString, 'NULL') = 0  then  { do not localize }
  1271.           begin
  1272.             FToken := etISNULL;
  1273.           end
  1274.           else
  1275.             DatabaseError(SInvalidKeywordUse);
  1276.         end;
  1277.       end;
  1278.     '[':
  1279.       begin
  1280.         Inc(P);
  1281.         TokenStart := P;
  1282.         P := AnsiStrScan(P, ']');
  1283.         if P = nil then DatabaseError(SExprNameError);
  1284.         SetString(FTokenString, TokenStart, P - TokenStart);
  1285.         FToken := etName;
  1286.         Inc(P);
  1287.       end;
  1288.     '''':
  1289.       begin
  1290.         Inc(P);
  1291.         L := 0;
  1292.         while True do
  1293.         begin
  1294.           if P^ = #0 then DatabaseError(SExprStringError);
  1295.           if P^ = '''' then
  1296.           begin
  1297.             Inc(P);
  1298.             if P^ <> '''' then Break;
  1299.           end;
  1300.           if L < SizeOf(StrBuf) then
  1301.           begin
  1302.             StrBuf[L] := P^;
  1303.             Inc(L);
  1304.           end;
  1305.           Inc(P);
  1306.         end;
  1307.         SetString(FTokenString, StrBuf, L);
  1308.         FToken := etLiteral;
  1309.         FNumericLit := False;
  1310.       end;
  1311.     '-', '0'..'9':
  1312.       begin
  1313.         if (FPrevToken <> etLiteral) and (FPrevToken <> etName) and
  1314.            (FPrevToken <> etSymbol)and (FPrevToken <> etRParen) then
  1315.           begin
  1316.             TokenStart := P;
  1317.             Inc(P);
  1318.             while (P^ in ['0'..'9', DecimalSeparator, 'e', 'E', '+', '-']) do
  1319.               Inc(P);
  1320.             if ((P-1)^ = ',') and (DecimalSeparator = ',') and (P^ = ' ') then
  1321.               Dec(P);
  1322.             SetString(FTokenString, TokenStart, P - TokenStart);
  1323.             FToken := etLiteral;
  1324.             FNumericLit := True;
  1325.           end
  1326.         else
  1327.          begin
  1328.            FToken := etSUB;
  1329.            Inc(P);
  1330.          end;
  1331.       end;
  1332.     '(':
  1333.       begin
  1334.         Inc(P);
  1335.         FToken := etLParen;
  1336.       end;
  1337.     ')':
  1338.       begin
  1339.         Inc(P);
  1340.         FToken := etRParen;
  1341.       end;
  1342.     '<':
  1343.       begin
  1344.         Inc(P);
  1345.         case P^ of
  1346.           '=':
  1347.             begin
  1348.               Inc(P);
  1349.               FToken := etLE;
  1350.             end;
  1351.           '>':
  1352.             begin
  1353.               Inc(P);
  1354.               FToken := etNE;
  1355.             end;
  1356.         else
  1357.           FToken := etLT;
  1358.         end;
  1359.       end;
  1360.     '=':
  1361.       begin
  1362.         Inc(P);
  1363.         FToken := etEQ;
  1364.       end;
  1365.     '>':
  1366.       begin
  1367.         Inc(P);
  1368.         if P^ = '=' then
  1369.         begin
  1370.           Inc(P);
  1371.           FToken := etGE;
  1372.         end else
  1373.           FToken := etGT;
  1374.       end;
  1375.     '+':
  1376.       begin
  1377.         Inc(P);
  1378.         FToken := etADD;
  1379.       end;
  1380.     '*':
  1381.       begin
  1382.         Inc(P);
  1383.         FToken := etMUL;
  1384.       end;
  1385.     '/':
  1386.       begin
  1387.         Inc(P);
  1388.         FToken := etDIV;
  1389.       end;
  1390.     ',':
  1391.       begin
  1392.         Inc(P);
  1393.         FToken := etComma;
  1394.       end;
  1395.     #0:
  1396.       FToken := etEnd;
  1397.   else
  1398.     DatabaseErrorFmt(SExprInvalidChar, [P^]);
  1399.   end;
  1400.   FSourcePtr := P;
  1401. end;
  1402.  
  1403. function TExprParser.ParseExpr: PExprNode;
  1404. begin
  1405.   Result := ParseExpr2;
  1406.   while TokenSymbolIs('OR') do
  1407.   begin
  1408.     NextToken;
  1409.     Result := FFilter.NewNode(enOperator, coOR, Unassigned,
  1410.       Result, ParseExpr2);
  1411.     GetScopeKind(Result, Result^.FLeft, Result^.FRight);
  1412.     Result^.FDataType := ftBoolean;
  1413.   end;
  1414. end;
  1415.  
  1416. function TExprParser.ParseExpr2: PExprNode;
  1417. begin
  1418.   Result := ParseExpr3;
  1419.   while TokenSymbolIs('AND') do
  1420.   begin
  1421.     NextToken;
  1422.     Result := FFilter.NewNode(enOperator, coAND, Unassigned,
  1423.       Result, ParseExpr3);
  1424.     GetScopeKind(Result, Result^.FLeft, Result^.FRight);
  1425.     Result^.FDataType := ftBoolean;
  1426.   end;
  1427. end;
  1428.  
  1429. function TExprParser.ParseExpr3: PExprNode;
  1430. begin
  1431.   if TokenSymbolIs('NOT') then
  1432.   begin
  1433.     NextToken;
  1434.     Result := FFilter.NewNode(enOperator, coNOT, Unassigned,
  1435.       ParseExpr4, nil);
  1436.     Result^.FDataType := ftBoolean;
  1437.   end else
  1438.     Result := ParseExpr4;
  1439.   GetScopeKind(Result, Result^.FLeft, Result^.FRight);
  1440. end;
  1441.  
  1442.  
  1443. function TExprParser.ParseExpr4: PExprNode;
  1444. const
  1445.   Operators: array[etEQ..etLT] of TCANOperator = (
  1446.     coEQ, coNE, coGE, coLE, coGT, coLT);
  1447. var
  1448.   Operator: TCANOperator;
  1449.   Left, Right: PExprNode;
  1450. begin
  1451.   Result := ParseExpr5;
  1452.   if (FToken in [etEQ..etLT]) or (FToken = etLIKE)
  1453.      or (FToken = etISNULL) or (FToken = etISNOTNULL)
  1454.      or (FToken = etIN) then
  1455.   begin
  1456.     case FToken of
  1457.       etEQ..etLT:
  1458.         Operator := Operators[FToken];
  1459.       etLIKE:
  1460.         Operator := coLIKE;
  1461.       etISNULL:
  1462.         Operator := coISBLANK;
  1463.       etISNOTNULL:
  1464.         Operator := coNOTBLANK;
  1465.       etIN:
  1466.         Operator := coIN;
  1467.       else
  1468.         Operator := coNOTDEFINED;
  1469.     end;
  1470.     NextToken;
  1471.     Left := Result;
  1472.     if Operator = coIN then
  1473.     begin
  1474.       if FToken <> etLParen then 
  1475.         DatabaseErrorFmt(SExprNoLParen, [TokenName]); 
  1476.       NextToken;
  1477.       Result := FFilter.NewNode(enOperator, coIN, Unassigned,
  1478.                  Left, nil);
  1479.       Result.FDataType := ftBoolean;
  1480.       if FToken <> etRParen then
  1481.       begin
  1482.         Result.FArgs := TList.Create;
  1483.         repeat
  1484.           Right := ParseExpr;
  1485.           if IsTemporal(Left.FDataType) then
  1486.             Right.FDataType := Left.FDataType;
  1487.           Result.FArgs.Add(Right);
  1488.           if (FToken <> etComma) and (FToken <> etRParen) then
  1489.             DatabaseErrorFmt(SExprNoRParenOrComma, [TokenName]);
  1490.           if FToken = etComma then NextToken;
  1491.         until (FToken = etRParen) or (FToken = etEnd);
  1492.         if FToken <> etRParen then
  1493.           DatabaseErrorFmt(SExprNoRParen, [TokenName]);
  1494.         NextToken;
  1495.       end else
  1496.         DatabaseError(SExprEmptyInList);
  1497.     end else
  1498.     begin
  1499.       if (Operator <> coISBLANK) and (Operator <> coNOTBLANK) then
  1500.         Right := ParseExpr5
  1501.       else
  1502.         Right := nil;
  1503.       Result := FFilter.NewNode(enOperator, Operator, Unassigned,
  1504.         Left, Right);
  1505.       if Right <> nil then
  1506.       begin
  1507.         if (Left^.FKind = enField) and (Right^.FKind = enConst) then
  1508.           begin
  1509.             Right^.FDataType := Left^.FDataType;
  1510.             Right^.FDataSize := Left^.FDataSize;
  1511.           end
  1512.         else if (Right^.FKind = enField) and (Left^.FKind = enConst) then
  1513.           begin
  1514.             Left^.FDataType := Right^.FDataType;
  1515.             Left^.FDataSize := Right^.FDataSize;
  1516.           end;
  1517.       end;
  1518.       if (Left^.FDataType in BlobFieldTypes) and (Operator = coLIKE) then
  1519.       begin
  1520.         if Right^.FKind = enConst then Right^.FDataType := ftString;
  1521.       end
  1522.       else if (Operator <> coISBLANK) and (Operator <> coNOTBLANK)
  1523.          and ((Left^.FDataType in (BlobFieldTypes + [ftBytes])) or
  1524.          ((Right <> nil) and (Right^.FDataType in (BlobFieldTypes + [ftBytes])))) then
  1525.         DatabaseError(SExprTypeMis);
  1526.       Result.FDataType := ftBoolean;
  1527.       if Right <> nil then
  1528.       begin
  1529.         if IsTemporal(Left.FDataType) and (Right.FDataType in StringFieldTypes) then
  1530.           Right.FDataType := Left.FDataType
  1531.         else if IsTemporal(Right.FDataType) and (Left.FDataType in StringFieldTypes) then
  1532.           Left.FDataType := Right.FDataType;
  1533.       end;
  1534.       GetScopeKind(Result, Left, Right);
  1535.     end;
  1536.   end;
  1537. end;
  1538.  
  1539. function TExprParser.ParseExpr5: PExprNode;
  1540. const
  1541.   Operators: array[etADD..etDIV] of TCANOperator = (
  1542.     coADD, coSUB, coMUL, coDIV);
  1543. var
  1544.   Operator: TCANOperator;
  1545.   Left, Right: PExprNode;
  1546. begin
  1547.   Result := ParseExpr6;
  1548.   while FToken in [etADD, etSUB] do
  1549.   begin
  1550.     if not (poExtSyntax in FParserOptions) then
  1551.       DatabaseError(SExprNoArith);
  1552.     Operator := Operators[FToken];
  1553.     Left := Result;
  1554.     NextToken;
  1555.     Right := ParseExpr6;
  1556.     Result := FFilter.NewNode(enOperator, Operator, Unassigned, Left, Right);
  1557.     TypeCheckArithOp(Result);
  1558.     GetScopeKind(Result, Left, Right);
  1559.   end;
  1560. end;
  1561.  
  1562. function TExprParser.ParseExpr6: PExprNode;
  1563. const
  1564.   Operators: array[etADD..etDIV] of TCANOperator = (
  1565.     coADD, coSUB, coMUL, coDIV);
  1566. var
  1567.   Operator: TCANOperator;
  1568.   Left, Right: PExprNode;
  1569. begin
  1570.   Result := ParseExpr7;
  1571.   while FToken in [etMUL, etDIV] do
  1572.   begin
  1573.     if not (poExtSyntax in FParserOptions) then
  1574.       DatabaseError(SExprNoArith);
  1575.     Operator := Operators[FToken];
  1576.     Left := Result;
  1577.     NextToken;
  1578.     Right := ParseExpr7;
  1579.     Result := FFilter.NewNode(enOperator, Operator, Unassigned, Left, Right);
  1580.     TypeCheckArithOp(Result);
  1581.     GetScopeKind(Result, Left, Right);
  1582.   end;
  1583. end;
  1584.  
  1585.  
  1586. function TExprParser.ParseExpr7: PExprNode;
  1587. var
  1588.   FuncName: string;
  1589. begin
  1590.   case FToken of
  1591.     etSymbol:
  1592.       if (poExtSyntax in FParserOptions)
  1593.          and  NextTokenIsLParen and TokenSymbolIsFunc(FTokenString) then
  1594.         begin
  1595.           Funcname := FTokenString;
  1596.           NextToken;
  1597.           if FToken <> etLParen then 
  1598.             DatabaseErrorFmt(SExprNoLParen, [TokenName]); 
  1599.           NextToken;
  1600.           if (CompareText(FuncName,'count') = 0) and (FToken = etMUL) then 
  1601.           begin
  1602.             FuncName := 'COUNT(*)';
  1603.             NextToken;
  1604.           end;
  1605.           Result := FFilter.NewNode(enFunc, coNOTDEFINED, FuncName,
  1606.                     nil, nil);
  1607.           if FToken <> etRParen then
  1608.           begin
  1609.             Result.FArgs := TList.Create;
  1610.             repeat
  1611.               Result.FArgs.Add(ParseExpr);
  1612.               if (FToken <> etComma) and (FToken <> etRParen) then
  1613.                 DatabaseErrorFmt(SExprNoRParenOrComma, [TokenName]); 
  1614.               if FToken = etComma then NextToken;
  1615.             until (FToken = etRParen) or (FToken = etEnd);
  1616.           end else 
  1617.             Result.FArgs := nil;
  1618.  
  1619.           GetFuncResultInfo(Result);
  1620.         end
  1621.       else if TokenSymbolIs('NULL') then
  1622.         begin
  1623.           Result := FFilter.NewNode(enConst, coNOTDEFINED, System.Null, nil, nil);
  1624.           Result.FScopeKind := skConst;
  1625.         end
  1626.       else if TokenSymbolIs(FStrTrue) then
  1627.         begin
  1628.           Result := FFilter.NewNode(enConst, coNOTDEFINED, 1, nil, nil);
  1629.           Result.FScopeKind := skConst;
  1630.         end
  1631.       else if TokenSymbolIs(FStrFalse) then
  1632.         begin
  1633.           Result := FFilter.NewNode(enConst, coNOTDEFINED, 0, nil, nil);
  1634.           Result.FScopeKind := skConst;
  1635.         end
  1636.       else
  1637.         begin
  1638.           Result := FFilter.NewNode(enField, coNOTDEFINED, FTokenString, nil, nil);
  1639.           Result.FScopeKind := skField;
  1640.         end;
  1641.     etName:
  1642.       begin
  1643.         Result := FFilter.NewNode(enField, coNOTDEFINED, FTokenString, nil, nil);
  1644.         Result.FScopeKind := skField;
  1645.       end;
  1646.     etLiteral:
  1647.       begin
  1648.         Result := FFilter.NewNode(enConst, coNOTDEFINED, FTokenString, nil, nil);
  1649.         if FNumericLit then Result^.FDataType := ftFloat else
  1650.            Result^.FDataType := ftString;
  1651.         Result.FScopeKind := skConst;
  1652.       end;
  1653.     etLParen:
  1654.       begin
  1655.         NextToken;
  1656.         Result := ParseExpr;
  1657.         if FToken <> etRParen then DatabaseErrorFmt(SExprNoRParen, [TokenName]);
  1658.       end;
  1659.   else
  1660.     DatabaseErrorFmt(SExprExpected, [TokenName]);
  1661.     Result := nil;
  1662.   end;
  1663.   NextToken;
  1664. end;
  1665.  
  1666. procedure  TExprParser.GetScopeKind(Root, Left, Right : PExprNode);
  1667. begin
  1668.   if (Left = nil) and (Right = nil) then Exit;
  1669.   if Right = nil then
  1670.   begin
  1671.     Root.FScopeKind := Left.FScopeKind;
  1672.     Exit;
  1673.   end;
  1674.   if ((Left^.FScopeKind = skField) and (Right^.FScopeKind = skAgg))
  1675.      or ((Left^.FScopeKind = skAgg) and (Right^.FScopeKind = skField)) then
  1676.     DatabaseError(SExprBadScope);
  1677.   if (Left^.FScopeKind = skConst) and (Right^.FScopeKind = skConst) then
  1678.     Root^.FScopeKind := skConst
  1679.   else if (Left^.FScopeKind = skAgg) or (Right^.FScopeKind = skAgg) then
  1680.     Root^.FScopeKind := skAgg
  1681.   else if (Left^.FScopeKind = skField) or (Right^.FScopeKind = skField) then
  1682.     Root^.FScopeKind := skField;
  1683. end;
  1684.  
  1685. procedure TExprParser.GetFuncResultInfo(Node : PExprNode);
  1686. begin
  1687.   Node^.FDataType := ftString;
  1688.   if (CompareText(Node^.FData, 'COUNT(*)') <> 0 )
  1689.      and (CompareText(Node^.FData,'GETDATE') <> 0 )
  1690.      and ( (Node^.FArgs = nil ) or ( Node^.FArgs.Count = 0) ) then
  1691.       DatabaseError(SExprTypeMis);
  1692.  
  1693.   if (Node^.FArgs <> nil) and (Node^.FArgs.Count > 0) then
  1694.      Node^.FScopeKind := PExprNode(Node^.FArgs.Items[0])^.FScopeKind;
  1695.   if (CompareText(Node^.FData , 'SUM') = 0) or
  1696.      (CompareText(Node^.FData , 'AVG') = 0) then
  1697.   begin
  1698.     Node^.FDataType := ftFloat;
  1699.     Node^.FScopeKind := skAgg;
  1700.   end
  1701.   else if (CompareText(Node^.FData , 'MIN') = 0) or
  1702.           (CompareText(Node^.FData , 'MAX') = 0) then
  1703.   begin
  1704.     Node^.FDataType := PExprNode(Node^.FArgs.Items[0])^.FDataType;
  1705.     Node^.FScopeKind := skAgg;
  1706.   end
  1707.   else if  (CompareText(Node^.FData , 'COUNT') = 0) or
  1708.            (CompareText(Node^.FData , 'COUNT(*)') = 0) then
  1709.   begin
  1710.     Node^.FDataType := ftInteger;
  1711.     Node^.FScopeKind := skAgg;
  1712.   end
  1713.   else if (CompareText(Node^.FData , 'YEAR') = 0) or
  1714.           (CompareText(Node^.FData , 'MONTH') = 0) or
  1715.           (CompareText(Node^.FData , 'DAY') = 0) or
  1716.           (CompareText(Node^.FData , 'HOUR') = 0) or
  1717.           (CompareText(Node^.FData , 'MINUTE') = 0) or
  1718.           (CompareText(Node^.FData , 'SECOND') = 0 ) then
  1719.   begin
  1720.     Node^.FDataType := ftInteger;
  1721.     Node^.FScopeKind := PExprNode(Node^.FArgs.Items[0])^.FScopeKind;
  1722.   end
  1723.   else if CompareText(Node^.FData , 'GETDATE') = 0  then
  1724.   begin
  1725.     Node^.FDataType := ftDateTime;
  1726.     Node^.FScopeKind := skConst;
  1727.   end
  1728.   else if CompareText(Node^.FData , 'DATE') = 0  then
  1729.   begin
  1730.     Node^.FDataType := ftDate;
  1731.     Node^.FScopeKind := PExprNode(Node^.FArgs.Items[0])^.FScopeKind;
  1732.   end
  1733.   else if CompareText(Node^.FData , 'TIME') = 0  then
  1734.   begin
  1735.     Node^.FDataType := ftTime;
  1736.     Node^.FScopeKind := PExprNode(Node^.FArgs.Items[0])^.FScopeKind;
  1737.   end;
  1738. end;
  1739.  
  1740. function TExprParser.TokenName: string;
  1741. begin
  1742.   if FSourcePtr = FTokenPtr then Result := SExprNothing else
  1743.   begin
  1744.     SetString(Result, FTokenPtr, FSourcePtr - FTokenPtr);
  1745.     Result := '''' + Result + '''';
  1746.   end;
  1747. end;
  1748.  
  1749. function TExprParser.TokenSymbolIs(const S: string): Boolean;
  1750. begin
  1751.   Result := (FToken = etSymbol) and (CompareText(FTokenString, S) = 0);
  1752. end;
  1753.  
  1754.  
  1755. function TExprParser.TokenSymbolIsFunc(const S: string) : Boolean;
  1756. begin
  1757.   Result := (CompareText(S, 'UPPER') = 0) or
  1758.             (CompareText(S, 'LOWER') = 0) or
  1759.             (CompareText(S, 'SUBSTRING') = 0) or
  1760.             (CompareText(S, 'TRIM') = 0) or
  1761.             (CompareText(S, 'TRIMLEFT') = 0) or
  1762.             (CompareText(S, 'TRIMRIGHT') = 0) or
  1763.             (CompareText(S, 'YEAR') = 0) or
  1764.             (CompareText(S, 'MONTH') = 0) or
  1765.             (CompareText(S, 'DAY') = 0) or
  1766.             (CompareText(S, 'HOUR') = 0) or
  1767.             (CompareText(S, 'MINUTE') = 0) or
  1768.             (CompareText(S, 'SECOND') = 0) or
  1769.             (CompareText(S, 'GETDATE') = 0) or
  1770.             (CompareText(S, 'DATE') = 0) or
  1771.             (CompareText(S, 'TIME') = 0) or
  1772.             (CompareText(S, 'SUM') = 0) or
  1773.             (CompareText(S, 'MIN') = 0) or
  1774.             (CompareText(S, 'MAX') = 0) or
  1775.             (CompareText(S, 'AVG') = 0) or
  1776.             (CompareText(S, 'COUNT') = 0);
  1777.  
  1778. end;
  1779.  
  1780. procedure  TExprParser.TypeCheckArithOp(Node: PExprNode);
  1781. begin
  1782.   with Node^ do
  1783.   begin
  1784.     if IsNumeric(FLeft.FDataType) and IsNumeric(FRight.FDataType)  then
  1785.       FDataType := ftFloat
  1786.     else if (FLeft.FDataType in StringFieldTypes) and
  1787.        (FRight.FDataType in StringFieldTypes) and (FOperator = coADD) then
  1788.       FDataType := ftString
  1789.     else if IsTemporal(FLeft.FDataType) and IsNumeric(FRight.FDataType) and
  1790.        (FOperator = coADD) then
  1791.       FDataType := ftDateTime
  1792.     else if IsTemporal(FLeft.FDataType) and IsNumeric(FRight.FDataType) and
  1793.        (FOperator = coSUB) then
  1794.       FDataType := FLeft.FDataType
  1795.     else if IsTemporal(FLeft.FDataType) and IsTemporal(FRight.FDataType) and
  1796.        (FOperator = coSUB) then
  1797.       FDataType := ftFloat
  1798.     else if (FLeft.FDataType in StringFieldTypes) and IsTemporal(FRight.FDataType) and
  1799.        (FOperator = coSUB) then
  1800.     begin
  1801.       FLeft.FDataType := FRight.FDataType;
  1802.       FDataType := ftFloat;
  1803.     end
  1804.     else if ( FLeft.FDataType in StringFieldTypes) and  IsNumeric(FRight.FDataType )and
  1805.          (FLeft.FKind = enConst)  then
  1806.       FLeft.FDataType := ftDateTime
  1807.     else
  1808.       DatabaseError(SExprTypeMis);
  1809.   end;
  1810. end;
  1811.  
  1812. end.
  1813.