📄 dbcommon.pas
字号:
else
begin
ListElem := PutNode(nodeLISTELEM, coLISTELEM2, 2);
SetNodeOp(ListElem, 0, LeftPos);
SetNodeOp(ListElem, 1, 0);
SetNodeOp(PrevListElem, 1, ListElem);
PrevListElem := ListElem;
end;
end;
end else
SetNodeOp(Result, 1, 0);
end;
end;
end;
function TFilterExpr.PutFieldNode(Field: TField; Node: PExprNode): Integer;
var
Buffer: array[0..255] of Char;
begin
if poFieldNameGiven in FParserOptions then
FDataSet.Translate(PChar(Field.FieldName), Buffer, True)
else
FDataSet.Translate(PChar(string(Node^.FData)), Buffer, True);
Result := PutNode(nodeFIELD, coFIELD2, 2);
SetNodeOp(Result, 0, Field.FieldNo);
SetNodeOp(Result, 1, PutData(Buffer, StrLen(Buffer) + 1));
end;
function TFilterExpr.PutNode(NodeType: NodeClass; OpType: TCANOperator;
OpCount: Integer): Integer;
var
Size: Integer;
Data: PChar;
begin
Size := CANHDRSIZE + OpCount * SizeOf(Word);
Data := GetExprData(CANEXPRSIZE + FExprNodeSize, Size);
PInteger(@Data[0])^ := Integer(NodeType); { CANHdr.nodeClass }
PInteger(@Data[4])^ := Integer(OpType); { CANHdr.coOp }
Result := FExprNodeSize;
Inc(FExprNodeSize, Size);
end;
procedure TFilterExpr.SetNodeOp(Node, Index, Data: Integer);
begin
PWordArray(PChar(FExprBuffer) + (CANEXPRSIZE + Node +
CANHDRSIZE))^[Index] := Data;
end;
function TFilterExpr.GetFieldByName(Name: string) : TField;
var
I: Integer;
F: TField;
FieldInfo: TFieldInfo;
begin
Result := nil;
if poFieldNameGiven in FParserOptions then
Result := FDataSet.FieldByName(FFieldName)
else if poUseOrigNames in FParserOptions then
begin
for I := 0 to FDataset.FieldCount - 1 do
begin
F := FDataSet.Fields[I];
if GetFieldInfo(F.Origin, FieldInfo) and
(AnsiCompareStr(Name, FieldInfo.OriginalFieldName) = 0) then
begin
Result := F;
Exit;
end;
end;
end;
if Result = nil then
Result := FDataSet.FieldByName(Name);
if (Result <> nil) and (Result.FieldKind = fkCalculated) and (poAggregate in FParserOptions) then
DatabaseErrorFmt(SExprNoAggOnCalcs, [Result.FieldName]);
if (poFieldDepend in FParserOptions) and (Result <> nil) and
(FDependentFields <> nil) then
FDependentFields[Result.FieldNo-1] := True;
end;
constructor TExprParser.Create(DataSet: TDataSet; const Text: string;
Options: TFilterOptions; ParserOptions: TParserOptions; const FieldName: string;
DepFields: TBits; FieldMap: TFieldMap);
begin
FDecimalSeparator := DecimalSeparator;
FFieldMap := FieldMap;
FStrTrue := STextTrue;
FStrFalse := STextFalse;
FDataSet := DataSet;
FDependentFields := DepFields;
FFilter := TFilterExpr.Create(DataSet, Options, ParserOptions, FieldName,
DepFields, FieldMap);
if Text <> '' then
SetExprParams(Text, Options, ParserOptions, FieldName);
end;
destructor TExprParser.Destroy;
begin
FFilter.Free;
end;
procedure TExprParser.SetExprParams(const Text: string; Options: TFilterOptions;
ParserOptions: TParserOptions; const FieldName: string);
var
Root, DefField: PExprNode;
begin
FParserOptions := ParserOptions;
if FFilter <> nil then
FFilter.Free;
FFilter := TFilterExpr.Create(FDataSet, Options, ParserOptions, FieldName,
FDependentFields, FFieldMap);
FText := Text;
FSourcePtr := PChar(Text);
FFieldName := FieldName;
NextToken;
Root := ParseExpr;
if FToken <> etEnd then DatabaseError(SExprTermination);
if (poAggregate in FParserOptions) and (Root^.FScopeKind <> skAgg) then
DatabaseError(SExprNotAgg);
if (not (poAggregate in FParserOptions)) and (Root^.FScopeKind = skAgg) then
DatabaseError(SExprNoAggFilter);
if poDefaultExpr in ParserOptions then
begin
DefField := FFilter.NewNode(enField, coNOTDEFINED, FFieldName, nil, nil);
if (IsTemporal(DefField^.FDataType) and (Root^.FDataType in StringFieldTypes)) or
((DefField^.FDataType = ftBoolean ) and (Root^.FDataType in StringFieldTypes)) then
Root^.FDataType := DefField^.FDataType;
if not ((IsTemporal(DefField^.FDataType) and IsTemporal(Root^.FDataType))
or (IsNumeric(DefField^.FDataType) and IsNumeric(Root^.FDataType))
or ((DefField^.FDataType in StringFieldTypes) and (Root^.FDataType in StringFieldTypes))
or ((DefField^.FDataType = ftBoolean) and (Root^.FDataType = ftBoolean))) then
DatabaseError(SExprTypeMis);
Root := FFilter.NewNode(enOperator, coASSIGN, Unassigned, Root, DefField);
end;
if not (poAggregate in FParserOptions) and not(poDefaultExpr in ParserOptions)
and (Root^.FDataType <> ftBoolean ) then
DatabaseError(SExprIncorrect);
FFilterData := FFilter.GetFilterData(Root);
FDataSize := FFilter.FExprBufSize;
end;
function TExprParser.NextTokenIsLParen : Boolean;
var
P : PChar;
begin
P := FSourcePtr;
while (P^ <> #0) and (P^ <= ' ') do Inc(P);
Result := P^ = '(';
end;
function EndOfLiteral(var P : PChar): Boolean;
var
FName: String;
PTemp: PChar;
begin
Inc(P);
Result := P^ <> '''';
if Result then
begin // now, look for 'John's Horse'
if AnsiStrScan(P, '''') <> Nil then // found another '
begin
PTemp := P; // don't advance P
while PTemp[0] in [ ' ', ')' ] do Inc(PTemp);
if NextSQLToken(PTemp, FName, stValue) in [stFieldName, stUnknown] then
begin // 'John's Horse' case: not really end of literal
Result := False;
Dec(P);
end;
end;
end;
end;
procedure TExprParser.NextToken;
type
ASet = Set of Char;
var
P, TokenStart: PChar;
L: Integer;
StrBuf: array[0..255] of Char;
function IsKatakana(const Chr: Byte): Boolean;
begin
{$IFDEF MSWINDOWS}
Result := (SysLocale.PriLangID = LANG_JAPANESE) and (Chr in [$A1..$DF]);
{$ENDIF}
{$IFDEF LINUX}
Result := False;
{$ENDIF}
end;
procedure Skip(TheSet: ASet);
begin
while TRUE do
begin
if P^ in LeadBytes then
Inc(P, 2)
else if (P^ in TheSet) or IsKatakana(Byte(P^)) then
Inc(P)
else
Exit;
end;
end;
begin
FPrevToken := FToken;
FTokenString := '';
P := FSourcePtr;
while (P^ <> #0) and (P^ <= ' ') do Inc(P);
if (P^ <> #0) and (P^ = '/') and (P[1] <> #0) and (P[1] = '*')then
begin
P := P + 2;
while (P^ <> #0) and (P^ <> '*') do Inc(P);
if (P^ = '*') and (P[1] <> #0) and (P[1] = '/') then
P := P + 2
else
DatabaseErrorFmt(SExprInvalidChar, [P^]);
end;
while (P^ <> #0) and (P^ <= ' ') do Inc(P);
FTokenPtr := P;
case P^ of
'A'..'Z', 'a'..'z', '_', #$81..#$fe:
begin
TokenStart := P;
if not SysLocale.FarEast then
begin
Inc(P);
while P^ in ['A'..'Z', 'a'..'z', '0'..'9', '_', '.', '[', ']'] do Inc(P);
end
else
Skip(['A'..'Z', 'a'..'z', '0'..'9', '_', '.', '[', ']']);
SetString(FTokenString, TokenStart, P - TokenStart);
FToken := etSymbol;
if CompareText(FTokenString, 'LIKE') = 0 then { do not localize }
FToken := etLIKE
else if CompareText(FTokenString, 'IN') = 0 then { do not localize }
FToken := etIN
else if CompareText(FTokenString, 'IS') = 0 then { do not localize }
begin
while (P^ <> #0) and (P^ <= ' ') do Inc(P);
TokenStart := P;
Skip(['A'..'Z', 'a'..'z']);
SetString(FTokenString, TokenStart, P - TokenStart);
if CompareText(FTokenString, 'NOT')= 0 then { do not localize }
begin
while (P^ <> #0) and (P^ <= ' ') do Inc(P);
TokenStart := P;
Skip(['A'..'Z', 'a'..'z']);
SetString(FTokenString, TokenStart, P - TokenStart);
if CompareText(FTokenString, 'NULL') = 0 then
FToken := etISNOTNULL
else
DatabaseError(SInvalidKeywordUse);
end
else if CompareText (FTokenString, 'NULL') = 0 then { do not localize }
begin
FToken := etISNULL;
end
else
DatabaseError(SInvalidKeywordUse);
end;
end;
'[':
begin
Inc(P);
TokenStart := P;
P := AnsiStrScan(P, ']');
if P = nil then DatabaseError(SExprNameError);
SetString(FTokenString, TokenStart, P - TokenStart);
FToken := etName;
Inc(P);
end;
'''':
begin
Inc(P);
L := 0;
while True do
begin
if P^ = #0 then DatabaseError(SExprStringError);
if P^ = '''' then
if EndOfLiteral(P) then
Break;
if L < SizeOf(StrBuf) then
begin
StrBuf[L] := P^;
Inc(L);
end;
Inc(P);
end;
SetString(FTokenString, StrBuf, L);
FToken := etLiteral;
FNumericLit := False;
end;
'-', '0'..'9':
begin
if (FPrevToken <> etLiteral) and (FPrevToken <> etName) and
(FPrevToken <> etSymbol)and (FPrevToken <> etRParen) then
begin
TokenStart := P;
Inc(P);
while (P^ in ['0'..'9', FDecimalSeparator, 'e', 'E', '+', '-']) do
Inc(P);
if ((P-1)^ = ',') and (FDecimalSeparator = ',') and (P^ = ' ') then
Dec(P);
SetString(FTokenString, TokenStart, P - TokenStart);
FToken := etLiteral;
FNumericLit := True;
end
else
begin
FToken := etSUB;
Inc(P);
end;
end;
'(':
begin
Inc(P);
FToken := etLParen;
end;
')':
begin
Inc(P);
FToken := etRParen;
end;
'<':
begin
Inc(P);
case P^ of
'=':
begin
Inc(P);
FToken := etLE;
end;
'>':
begin
Inc(P);
FToken := etNE;
end;
else
FToken := etLT;
end;
end;
'=':
begin
Inc(P);
FToken := etEQ;
end;
'>':
begin
Inc(P);
if P^ = '=' then
begin
Inc(P);
FToken := etGE;
end else
FToken := etGT;
end;
'+':
begin
Inc(P);
FToken := etADD;
end;
'*':
begin
Inc(P);
FToken := etMUL;
end;
'/':
begin
Inc(P);
FToken := etDIV;
end;
',':
begin
Inc(P);
FToken := etComma;
end;
#0:
FToken := etEnd;
else
DatabaseErrorFmt(SExprInvalidChar, [P^]);
end;
FSourcePtr := P;
end;
function TExprParser.ParseExpr: PExprNode;
begin
Result := ParseExpr2;
while TokenSymbolIs('OR') do
begin
NextToken;
Result := FFilter.NewNode(enOperator, coOR, Unassigned,
Result, ParseExpr2);
GetScopeKind(Result, Result^.FLeft, Result^.FRight);
Result^.FDataType := ftBoolean;
end;
end;
function TExprParser.ParseExpr2: PExprNode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -