📄 dbcommon.pas
字号:
begin
Result := ParseExpr3;
while TokenSymbolIs('AND') do
begin
NextToken;
Result := FFilter.NewNode(enOperator, coAND, Unassigned,
Result, ParseExpr3);
GetScopeKind(Result, Result^.FLeft, Result^.FRight);
Result^.FDataType := ftBoolean;
end;
end;
function TExprParser.ParseExpr3: PExprNode;
begin
if TokenSymbolIs('NOT') then
begin
NextToken;
Result := FFilter.NewNode(enOperator, coNOT, Unassigned,
ParseExpr4, nil);
Result^.FDataType := ftBoolean;
end else
Result := ParseExpr4;
GetScopeKind(Result, Result^.FLeft, Result^.FRight);
end;
function TExprParser.ParseExpr4: PExprNode;
const
Operators: array[etEQ..etLT] of TCANOperator = (
coEQ, coNE, coGE, coLE, coGT, coLT);
var
Operator: TCANOperator;
Left, Right: PExprNode;
begin
Result := ParseExpr5;
if (FToken in [etEQ..etLT]) or (FToken = etLIKE)
or (FToken = etISNULL) or (FToken = etISNOTNULL)
or (FToken = etIN) then
begin
case FToken of
etEQ..etLT:
Operator := Operators[FToken];
etLIKE:
Operator := coLIKE;
etISNULL:
Operator := coISBLANK;
etISNOTNULL:
Operator := coNOTBLANK;
etIN:
Operator := coIN;
else
Operator := coNOTDEFINED;
end;
NextToken;
Left := Result;
if Operator = coIN then
begin
if FToken <> etLParen then
DatabaseErrorFmt(SExprNoLParen, [TokenName]);
NextToken;
Result := FFilter.NewNode(enOperator, coIN, Unassigned,
Left, nil);
Result.FDataType := ftBoolean;
if FToken <> etRParen then
begin
Result.FArgs := TList.Create;
repeat
Right := ParseExpr;
if IsTemporal(Left.FDataType) then
Right.FDataType := Left.FDataType;
Result.FArgs.Add(Right);
if (FToken <> etComma) and (FToken <> etRParen) then
DatabaseErrorFmt(SExprNoRParenOrComma, [TokenName]);
if FToken = etComma then NextToken;
until (FToken = etRParen) or (FToken = etEnd);
if FToken <> etRParen then
DatabaseErrorFmt(SExprNoRParen, [TokenName]);
NextToken;
end else
DatabaseError(SExprEmptyInList);
end else
begin
if (Operator <> coISBLANK) and (Operator <> coNOTBLANK) then
Right := ParseExpr5
else
Right := nil;
Result := FFilter.NewNode(enOperator, Operator, Unassigned,
Left, Right);
if Right <> nil then
begin
if (Left^.FKind = enField) and (Right^.FKind = enConst) then
begin
Right^.FDataType := Left^.FDataType;
Right^.FDataSize := Left^.FDataSize;
end
else if (Right^.FKind = enField) and (Left^.FKind = enConst) then
begin
Left^.FDataType := Right^.FDataType;
Left^.FDataSize := Right^.FDataSize;
end;
end;
if (Left^.FDataType in BlobFieldTypes) and (Operator = coLIKE) then
begin
if Right^.FKind = enConst then Right^.FDataType := ftString;
end
else if (Operator <> coISBLANK) and (Operator <> coNOTBLANK)
and ((Left^.FDataType in (BlobFieldTypes + [ftBytes])) or
((Right <> nil) and (Right^.FDataType in (BlobFieldTypes + [ftBytes])))) then
DatabaseError(SExprTypeMis);
Result.FDataType := ftBoolean;
if Right <> nil then
begin
if IsTemporal(Left.FDataType) and (Right.FDataType in StringFieldTypes) then
Right.FDataType := Left.FDataType
else if IsTemporal(Right.FDataType) and (Left.FDataType in StringFieldTypes) then
Left.FDataType := Right.FDataType;
end;
GetScopeKind(Result, Left, Right);
end;
end;
end;
function TExprParser.ParseExpr5: PExprNode;
const
Operators: array[etADD..etDIV] of TCANOperator = (
coADD, coSUB, coMUL, coDIV);
var
Operator: TCANOperator;
Left, Right: PExprNode;
begin
Result := ParseExpr6;
while FToken in [etADD, etSUB] do
begin
if not (poExtSyntax in FParserOptions) then
DatabaseError(SExprNoArith);
Operator := Operators[FToken];
Left := Result;
NextToken;
Right := ParseExpr6;
Result := FFilter.NewNode(enOperator, Operator, Unassigned, Left, Right);
TypeCheckArithOp(Result);
GetScopeKind(Result, Left, Right);
end;
end;
function TExprParser.ParseExpr6: PExprNode;
const
Operators: array[etADD..etDIV] of TCANOperator = (
coADD, coSUB, coMUL, coDIV);
var
Operator: TCANOperator;
Left, Right: PExprNode;
begin
Result := ParseExpr7;
while FToken in [etMUL, etDIV] do
begin
if not (poExtSyntax in FParserOptions) then
DatabaseError(SExprNoArith);
Operator := Operators[FToken];
Left := Result;
NextToken;
Right := ParseExpr7;
Result := FFilter.NewNode(enOperator, Operator, Unassigned, Left, Right);
TypeCheckArithOp(Result);
GetScopeKind(Result, Left, Right);
end;
end;
function TExprParser.ParseExpr7: PExprNode;
var
FuncName: string;
begin
case FToken of
etSymbol:
if (poExtSyntax in FParserOptions)
and NextTokenIsLParen and TokenSymbolIsFunc(FTokenString) then
begin
Funcname := FTokenString;
NextToken;
if FToken <> etLParen then
DatabaseErrorFmt(SExprNoLParen, [TokenName]);
NextToken;
if (CompareText(FuncName,'count') = 0) and (FToken = etMUL) then
begin
FuncName := 'COUNT(*)';
NextToken;
end;
Result := FFilter.NewNode(enFunc, coNOTDEFINED, FuncName,
nil, nil);
if FToken <> etRParen then
begin
Result.FArgs := TList.Create;
repeat
Result.FArgs.Add(ParseExpr);
if (FToken <> etComma) and (FToken <> etRParen) then
DatabaseErrorFmt(SExprNoRParenOrComma, [TokenName]);
if FToken = etComma then NextToken;
until (FToken = etRParen) or (FToken = etEnd);
end else
Result.FArgs := nil;
GetFuncResultInfo(Result);
end
else if TokenSymbolIs('NULL') then
begin
Result := FFilter.NewNode(enConst, coNOTDEFINED, Variants.Null, nil, nil);
Result.FScopeKind := skConst;
end
else if TokenSymbolIs(FStrTrue) then
begin
Result := FFilter.NewNode(enConst, coNOTDEFINED, 1, nil, nil);
Result.FScopeKind := skConst;
end
else if TokenSymbolIs(FStrFalse) then
begin
Result := FFilter.NewNode(enConst, coNOTDEFINED, 0, nil, nil);
Result.FScopeKind := skConst;
end
else
begin
Result := FFilter.NewNode(enField, coNOTDEFINED, FTokenString, nil, nil);
Result.FScopeKind := skField;
end;
etName:
begin
Result := FFilter.NewNode(enField, coNOTDEFINED, FTokenString, nil, nil);
Result.FScopeKind := skField;
end;
etLiteral:
begin
Result := FFilter.NewNode(enConst, coNOTDEFINED, FTokenString, nil, nil);
if FNumericLit then Result^.FDataType := ftFloat else
Result^.FDataType := ftString;
Result.FScopeKind := skConst;
end;
etLParen:
begin
NextToken;
Result := ParseExpr;
if FToken <> etRParen then DatabaseErrorFmt(SExprNoRParen, [TokenName]);
end;
else
DatabaseErrorFmt(SExprExpected, [TokenName]);
Result := nil;
end;
NextToken;
end;
procedure TExprParser.GetScopeKind(Root, Left, Right : PExprNode);
begin
if (Left = nil) and (Right = nil) then Exit;
if Right = nil then
begin
Root.FScopeKind := Left.FScopeKind;
Exit;
end;
if ((Left^.FScopeKind = skField) and (Right^.FScopeKind = skAgg))
or ((Left^.FScopeKind = skAgg) and (Right^.FScopeKind = skField)) then
DatabaseError(SExprBadScope);
if (Left^.FScopeKind = skConst) and (Right^.FScopeKind = skConst) then
Root^.FScopeKind := skConst
else if (Left^.FScopeKind = skAgg) or (Right^.FScopeKind = skAgg) then
Root^.FScopeKind := skAgg
else if (Left^.FScopeKind = skField) or (Right^.FScopeKind = skField) then
Root^.FScopeKind := skField;
end;
procedure TExprParser.GetFuncResultInfo(Node : PExprNode);
begin
Node^.FDataType := ftString;
if (CompareText(Node^.FData, 'COUNT(*)') <> 0 )
and (CompareText(Node^.FData,'GETDATE') <> 0 )
and ( (Node^.FArgs = nil ) or ( Node^.FArgs.Count = 0) ) then
DatabaseError(SExprTypeMis);
if (Node^.FArgs <> nil) and (Node^.FArgs.Count > 0) then
Node^.FScopeKind := PExprNode(Node^.FArgs.Items[0])^.FScopeKind;
if (CompareText(Node^.FData , 'SUM') = 0) or
(CompareText(Node^.FData , 'AVG') = 0) then
begin
Node^.FDataType := ftFloat;
Node^.FScopeKind := skAgg;
end
else if (CompareText(Node^.FData , 'MIN') = 0) or
(CompareText(Node^.FData , 'MAX') = 0) then
begin
Node^.FDataType := PExprNode(Node^.FArgs.Items[0])^.FDataType;
Node^.FScopeKind := skAgg;
end
else if (CompareText(Node^.FData , 'COUNT') = 0) or
(CompareText(Node^.FData , 'COUNT(*)') = 0) then
begin
Node^.FDataType := ftInteger;
Node^.FScopeKind := skAgg;
end
else if (CompareText(Node^.FData , 'YEAR') = 0) or
(CompareText(Node^.FData , 'MONTH') = 0) or
(CompareText(Node^.FData , 'DAY') = 0) or
(CompareText(Node^.FData , 'HOUR') = 0) or
(CompareText(Node^.FData , 'MINUTE') = 0) or
(CompareText(Node^.FData , 'SECOND') = 0 ) then
begin
Node^.FDataType := ftInteger;
Node^.FScopeKind := PExprNode(Node^.FArgs.Items[0])^.FScopeKind;
end
else if CompareText(Node^.FData , 'GETDATE') = 0 then
begin
Node^.FDataType := ftDateTime;
Node^.FScopeKind := skConst;
end
else if CompareText(Node^.FData , 'DATE') = 0 then
begin
Node^.FDataType := ftDate;
Node^.FScopeKind := PExprNode(Node^.FArgs.Items[0])^.FScopeKind;
end
else if CompareText(Node^.FData , 'TIME') = 0 then
begin
Node^.FDataType := ftTime;
Node^.FScopeKind := PExprNode(Node^.FArgs.Items[0])^.FScopeKind;
end;
end;
function TExprParser.TokenName: string;
begin
if FSourcePtr = FTokenPtr then Result := SExprNothing else
begin
SetString(Result, FTokenPtr, FSourcePtr - FTokenPtr);
Result := '''' + Result + '''';
end;
end;
function TExprParser.TokenSymbolIs(const S: string): Boolean;
begin
Result := (FToken = etSymbol) and (CompareText(FTokenString, S) = 0);
end;
function TExprParser.TokenSymbolIsFunc(const S: string) : Boolean;
begin
Result := (CompareText(S, 'UPPER') = 0) or
(CompareText(S, 'LOWER') = 0) or
(CompareText(S, 'SUBSTRING') = 0) or
(CompareText(S, 'TRIM') = 0) or
(CompareText(S, 'TRIMLEFT') = 0) or
(CompareText(S, 'TRIMRIGHT') = 0) or
(CompareText(S, 'YEAR') = 0) or
(CompareText(S, 'MONTH') = 0) or
(CompareText(S, 'DAY') = 0) or
(CompareText(S, 'HOUR') = 0) or
(CompareText(S, 'MINUTE') = 0) or
(CompareText(S, 'SECOND') = 0) or
(CompareText(S, 'GETDATE') = 0) or
(CompareText(S, 'DATE') = 0) or
(CompareText(S, 'TIME') = 0) or
(CompareText(S, 'SUM') = 0) or
(CompareText(S, 'MIN') = 0) or
(CompareText(S, 'MAX') = 0) or
(CompareText(S, 'AVG') = 0) or
(CompareText(S, 'COUNT') = 0);
end;
procedure TExprParser.TypeCheckArithOp(Node: PExprNode);
begin
with Node^ do
begin
if IsNumeric(FLeft.FDataType) and IsNumeric(FRight.FDataType) then
FDataType := ftFloat
else if (FLeft.FDataType in StringFieldTypes) and
(FRight.FDataType in StringFieldTypes) and (FOperator = coADD) then
FDataType := ftString
else if IsTemporal(FLeft.FDataType) and IsNumeric(FRight.FDataType) and
(FOperator = coADD) then
FDataType := ftDateTime
else if IsTemporal(FLeft.FDataType) and IsNumeric(FRight.FDataType) and
(FOperator = coSUB) then
FDataType := FLeft.FDataType
else if IsTemporal(FLeft.FDataType) and IsTemporal(FRight.FDataType) and
(FOperator = coSUB) then
FDataType := ftFloat
else if (FLeft.FDataType in StringFieldTypes) and IsTemporal(FRight.FDataType) and
(FOperator = coSUB) then
begin
FLeft.FDataType := FRight.FDataType;
FDataType := ftFloat;
end
else if ( FLeft.FDataType in StringFieldTypes) and IsNumeric(FRight.FDataType )and
(FLeft.FKind = enConst) then
FLeft.FDataType := ftDateTime
else
DatabaseError(SExprTypeMis);
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -