home *** CD-ROM | disk | FTP | other *** search
-
- {*******************************************************}
- { }
- { Delphi Visual Component Library }
- { Additional BDE dependent Classes }
- { }
- { Copyright (c) 1995,96 Borland International }
- { }
- {*******************************************************}
-
- unit DBCommon;
-
- interface
-
- uses Windows, Classes, DB, BDE;
-
- { FieldType Mappings }
-
- const
- FldTypeMap: array[TFieldType] of Byte = (
- fldUNKNOWN, fldZSTRING, fldINT16, fldINT32, fldUINT16, fldBOOL,
- fldFLOAT, fldFLOAT, fldBCD, fldDATE, fldTIME, fldTIMESTAMP, fldBYTES,
- fldVARBYTES, fldINT32, fldBLOB, fldBLOB, fldBLOB, fldBLOB, fldBLOB,
- fldBLOB, fldBLOB, fldCURSOR);
-
- FldSubTypeMap: array[TFieldType] of Word = (
- 0, 0, 0, 0, 0, 0, 0, fldstMONEY, 0, 0, 0, 0, 0, 0, fldstAUTOINC,
- fldstBINARY, fldstMEMO, fldstGRAPHIC, fldstFMTMEMO, fldstOLEOBJ,
- fldstDBSOLEOBJ, fldstTYPEDBINARY, 0);
-
- DataTypeMap: array[0..MAXLOGFLDTYPES - 1] of TFieldType = (
- ftUnknown, ftString, ftDate, ftBlob, ftBoolean, ftSmallint,
- ftInteger, ftFloat, ftBCD, ftBytes, ftTime, ftDateTime,
- ftWord, ftInteger, ftUnknown, ftVarBytes, ftUnknown, ftUnknown);
-
- BlobTypeMap: array[fldstMEMO..fldstTYPEDBINARY] of TFieldType = (
- ftMemo, ftBlob, ftFmtMemo, ftParadoxOle, ftGraphic,
- ftDBaseOle, ftTypedBinary);
-
- { TFilterExpr }
-
- type
-
- TExprNodeKind = (enField, enConst, enOperator);
-
- PExprNode = ^TExprNode;
- TExprNode = record
- FNext: PExprNode;
- FKind: TExprNodeKind;
- FPartial: Boolean;
- FOperator: CanOp;
- FData: Variant;
- FLeft: PExprNode;
- FRight: PExprNode;
- end;
-
- TFilterExpr = class
- private
- FDataSet: TDataSet;
- FOptions: TFilterOptions;
- FNodes: PExprNode;
- FExprBuffer: PCANExpr;
- FExprBufSize: Integer;
- FExprNodeSize: Integer;
- FExprDataSize: Integer;
- function FieldFromNode(Node: PExprNode): TField;
- function GetExprData(Pos, Size: Integer): PChar;
- function PutCompareNode(Node: PExprNode): Integer;
- function PutConstBCD(const Value: Variant; Decimals: Integer): Integer;
- function PutConstBool(const Value: Variant): Integer;
- function PutConstDate(const Value: Variant): Integer;
- function PutConstDateTime(const Value: Variant): Integer;
- function PutConstFloat(const Value: Variant): Integer;
- function PutConstInt(DataType: Integer; const Value: Variant): Integer;
- function PutConstNode(DataType: Integer; Data: PChar;
- Size: Integer): Integer;
- function PutConstStr(const Value: string): Integer;
- function PutConstTime(const Value: Variant): Integer;
- function PutData(Data: PChar; Size: Integer): Integer;
- function PutExprNode(Node: PExprNode): Integer;
- function PutFieldNode(Field: TField): Integer;
- function PutNode(NodeType: NodeClass; OpType: CanOp;
- OpCount: Integer): Integer;
- procedure SetNodeOp(Node, Index, Data: Integer);
- public
- constructor Create(DataSet: TDataSet; Options: TFilterOptions);
- destructor Destroy; override;
- function NewCompareNode(Field: TField; Operator: CanOp;
- const Value: Variant): PExprNode;
- function NewNode(Kind: TExprNodeKind; Operator: CanOp;
- const Data: Variant; Left, Right: PExprNode): PExprNode;
- function GetFilterData(Root: PExprNode): PCANExpr;
- end;
-
- { TExprParser }
-
- TExprToken = (etEnd, etSymbol, etName, etLiteral, etLParen, etRParen,
- etEQ, etNE, etGE, etLE, etGT, etLT);
-
- TExprParser = class
- private
- FFilter: TFilterExpr;
- FText: string;
- FSourcePtr: PChar;
- FTokenPtr: PChar;
- FTokenString: string;
- FStrTrue: string;
- FStrFalse: string;
- FToken: TExprToken;
- FFilterData: PCANExpr;
- FDataSize: Integer;
- procedure NextToken;
- function ParseExpr: PExprNode;
- function ParseExpr2: PExprNode;
- function ParseExpr3: PExprNode;
- function ParseExpr4: PExprNode;
- function ParseExpr5: PExprNode;
- function TokenName: string;
- function TokenSymbolIs(const S: string): Boolean;
- public
- constructor Create(DataSet: TDataSet; const Text: string;
- Options: TFilterOptions);
- destructor Destroy; override;
- property FilterData: PCANExpr read FFilterData;
- property DataSize: Integer read FDataSize;
- end;
-
- { TMasterDataLink }
-
- TMasterDataLink = class(TDataLink)
- private
- FDataSet: TDataSet;
- FFieldNames: string;
- FFields: TList;
- FOnMasterChange: TNotifyEvent;
- FOnMasterDisable: TNotifyEvent;
- procedure SetFieldNames(const Value: string);
- protected
- procedure ActiveChanged; override;
- procedure CheckBrowseMode; override;
- procedure LayoutChanged; override;
- procedure RecordChanged(Field: TField); override;
- public
- constructor Create(DataSet: TDataSet);
- destructor Destroy; override;
- property FieldNames: string read FFieldNames write SetFieldNames;
- property Fields: TList read FFields;
- property OnMasterChange: TNotifyEvent read FOnMasterChange write FOnMasterChange;
- property OnMasterDisable: TNotifyEvent read FOnMasterDisable write FOnMasterDisable;
- end;
-
- function FMTBCDToCurr(const BCD: FMTBcd; var Curr: Currency): Boolean;
- function CurrToFMTBCD(Curr: Currency; var BCD: FMTBcd; Precision,
- Decimals: Integer): Boolean;
- function SafeArrayToVariant(SafeArray: PVarArray): Variant;
-
- implementation
-
- uses SysUtils, DBConsts;
-
- function SafeArrayToVariant(SafeArray: PVarArray): Variant;
- begin
- if Assigned(SafeArray) then
- begin
- VarClear(Result);
- TVarData(Result).VType := varByte or varArray;
- TVarData(Result).VArray := SafeArray;
- end else
- Result := NULL;
- end;
-
- function FMTBCDToCurr(const BCD: FMTBcd; var Curr: Currency): Boolean;
- const
- FConst10: Single = 10;
- CWNear: Word = $133F;
- var
- CtrlWord: Word;
- Temp: Integer;
- Digits: array[0..63] of Byte;
- asm
- PUSH EBX
- PUSH ESI
- MOV EBX,EAX
- MOV ESI,EDX
- MOV AL,0
- MOVZX EDX,[EBX].FMTBcd.iPrecision
- OR EDX,EDX
- JE @@8
- LEA ECX,[EDX+1]
- SHR ECX,1
- @@1: MOV AL,[EBX].FMTBcd.iFraction.Byte[ECX-1]
- MOV AH,AL
- SHR AL,4
- AND AH,0FH
- MOV Digits.Word[ECX*2-2],AX
- DEC ECX
- JNE @@1
- XOR EAX,EAX
- @@2: MOV AL,Digits.Byte[ECX]
- OR AL,AL
- JNE @@3
- INC ECX
- CMP ECX,EDX
- JNE @@2
- FLDZ
- JMP @@7
- @@3: MOV Temp,EAX
- FILD Temp
- @@4: INC ECX
- CMP ECX,EDX
- JE @@5
- FMUL FConst10
- MOV AL,Digits.Byte[ECX]
- MOV Temp,EAX
- FIADD Temp
- JMP @@4
- @@5: MOV AL,[EBX].FMTBcd.iSignSpecialPlaces
- OR AL,AL
- JNS @@6
- FCHS
- @@6: AND EAX,3FH
- SUB EAX,4
- NEG EAX
- CALL FPower10
- @@7: FSTCW CtrlWord
- FLDCW CWNear
- FISTP [ESI].Currency
- FSTSW AX
- NOT AL
- AND AL,1
- FCLEX
- FLDCW CtrlWord
- FWAIT
- @@8: POP ESI
- POP EBX
- end;
-
- function CurrToFMTBCD(Curr: Currency; var BCD: FMTBcd; Precision,
- Decimals: Integer): Boolean;
- const
- Power10: array[0..3] of Single = (10000, 1000, 100, 10);
- var
- Digits: array[0..63] of Byte;
- asm
- PUSH EBX
- PUSH ESI
- PUSH EDI
- MOV ESI,EAX
- XCHG ECX,EDX
- MOV [ESI].FMTBcd.iPrecision,CL
- MOV [ESI].FMTBcd.iSignSpecialPlaces,DL
- @@1: SUB EDX,4
- JE @@3
- JA @@2
- FILD Curr
- FDIV Power10.Single[EDX*4+16]
- FISTP Curr
- JMP @@3
- @@2: DEC ECX
- MOV Digits.Byte[ECX],0
- DEC EDX
- JNE @@2
- @@3: MOV EAX,Curr.Integer[0]
- MOV EBX,Curr.Integer[4]
- OR EBX,EBX
- JNS @@4
- NEG EBX
- NEG EAX
- SBB EBX,0
- OR [ESI].FMTBcd.iSignSpecialPlaces,80H
- @@4: MOV EDI,10
- @@5: MOV EDX,EAX
- OR EDX,EBX
- JE @@7
- XOR EDX,EDX
- OR EBX,EBX
- JE @@6
- XCHG EAX,EBX
- DIV EDI
- XCHG EAX,EBX
- @@6: DIV EDI
- @@7: MOV Digits.Byte[ECX-1],DL
- DEC ECX
- JNE @@5
- OR EAX,EBX
- MOV AL,0
- JNE @@9
- MOV CL,[ESI].FMTBcd.iPrecision
- INC ECX
- SHR ECX,1
- @@8: MOV AX,Digits.Word[ECX*2-2]
- SHL AL,4
- OR AL,AH
- MOV [ESI].FMTBcd.iFraction.Byte[ECX-1],AL
- DEC ECX
- JNE @@8
- MOV AL,1
- @@9: POP EDI
- POP ESI
- POP EBX
- end;
-
- { TFilterExpr }
-
- constructor TFilterExpr.Create(DataSet: TDataSet; Options: TFilterOptions);
- begin
- FDataSet := DataSet;
- FOptions := Options;
- end;
-
- destructor TFilterExpr.Destroy;
- var
- Node: PExprNode;
- begin
- FreeMem(FExprBuffer, FExprBufSize);
- while FNodes <> nil do
- begin
- Node := FNodes;
- FNodes := Node^.FNext;
- Dispose(Node);
- end;
- end;
-
- function TFilterExpr.FieldFromNode(Node: PExprNode): TField;
- begin
- Result := FDataSet.FieldByName(Node^.FData);
- if not (Result.FieldKind in [fkData, fkInternalCalc]) then
- DatabaseErrorFmt(SExprBadField, [Result.FieldName]);
- end;
-
- function TFilterExpr.GetExprData(Pos, Size: Integer): PChar;
- begin
- ReallocMem(FExprBuffer, FExprBufSize + Size);
- Move(PChar(FExprBuffer)[Pos], PChar(FExprBuffer)[Pos + Size],
- FExprBufSize - Pos);
- Inc(FExprBufSize, Size);
- Result := PChar(FExprBuffer) + Pos;
- end;
-
- function TFilterExpr.GetFilterData(Root: PExprNode): PCANExpr;
- begin
- FExprBufSize := SizeOf(CANExpr);
- GetMem(FExprBuffer, FExprBufSize);
- PutExprNode(Root);
- with FExprBuffer^ do
- begin
- iVer := CANEXPRVERSION;
- iTotalSize := FExprBufSize;
- iNodes := $FFFF;
- iNodeStart := SizeOf(CANExpr);
- iLiteralStart := FExprNodeSize + SizeOf(CANExpr);
- end;
- Result := FExprBuffer;
- end;
-
- function TFilterExpr.NewCompareNode(Field: TField; Operator: CanOp;
- const Value: Variant): PExprNode;
- begin
- Result := NewNode(enOperator, Operator, Unassigned,
- NewNode(enField, canNOTDEFINED, Field.FieldName, nil, nil),
- NewNode(enConst, canNOTDEFINED, Value, nil, nil));
- end;
-
- function TFilterExpr.NewNode(Kind: TExprNodeKind; Operator: CanOp;
- const Data: Variant; Left, Right: PExprNode): PExprNode;
- begin
- New(Result);
- with Result^ do
- begin
- FNext := FNodes;
- FKind := Kind;
- FPartial := False;
- FOperator := Operator;
- FData := Data;
- FLeft := Left;
- FRight := Right;
- end;
- FNodes := Result;
- end;
-
- function TFilterExpr.PutCompareNode(Node: PExprNode): Integer;
- const
- ReverseOperator: array[canEQ..canLE] of CanOp = (
- canEQ, canNE, canLT, canGT, canLE, canGE);
- var
- Operator: CanOp;
- Left, Right, Temp: PExprNode;
- Field: TField;
- FieldPos, ConstPos, CaseInsensitive, PartialLength, L: Integer;
- S: string;
- begin
- Operator := Node^.FOperator;
- Left := Node^.FLeft;
- Right := Node^.FRight;
- if (Right^.FKind = enField) and (Left^.FKind <> enField) then
- begin
- Temp := Left;
- Left := Right;
- Right := Temp;
- Operator := ReverseOperator[Operator];
- end;
- Field := FieldFromNode(Left);
- if (Right^.FKind = enField) then
- begin
- Result := PutNode(nodeBINARY, Operator, 2);
- SetNodeOp(Result, 0, PutFieldNode(Field));
- SetNodeOp(Result, 1, PutFieldNode(FieldFromNode(Right)));
- end
- else if VarIsNull(Right^.FData) then
- begin
- case Operator of
- canEQ: Operator := canISBLANK;
- canNE: Operator := canNOTBLANK;
- else
- DatabaseError(SExprBadNullTest);
- end;
- Result := PutNode(nodeUNARY, Operator, 1);
- SetNodeOp(Result, 0, PutFieldNode(Field));
- end else
- begin
- if ((Operator = canEQ) or (Operator = canNE)) and
- (Field.DataType = ftString) then
- begin
- S := Right^.FData;
- L := Length(S);
- if L <> 0 then
- begin
- CaseInsensitive := 0;
- PartialLength := 0;
- if foCaseInsensitive in FOptions then CaseInsensitive := 1;
- if Node^.FPartial then PartialLength := L else
- if not (foNoPartialCompare in FOptions) and (L > 1) and
- (S[L] = '*') then
- begin
- Delete(S, L, 1);
- PartialLength := L - 1;
- end;
- if (CaseInsensitive <> 0) or (PartialLength <> 0) then
- begin
- Result := PutNode(nodeCOMPARE, Operator, 4);
- SetNodeOp(Result, 0, CaseInsensitive);
- SetNodeOp(Result, 1, PartialLength);
- SetNodeOp(Result, 2, PutFieldNode(Field));
- SetNodeOp(Result, 3, PutConstStr(S));
- Exit;
- end;
- end;
- end;
- Result := PutNode(nodeBINARY, Operator, 2);
- FieldPos := PutFieldNode(Field);
- case Field.DataType of
- ftString:
- ConstPos := PutConstStr(Right^.FData);
- ftSmallint:
- ConstPos := PutConstInt(fldINT16, Right^.FData);
- ftInteger, ftAutoInc:
- ConstPos := PutConstInt(fldINT32, Right^.FData);
- ftWord:
- ConstPos := PutConstInt(fldUINT16, Right^.FData);
- ftFloat, ftCurrency:
- ConstPos := PutConstFloat(Right^.FData);
- ftBCD:
- ConstPos := PutConstBCD(Right^.FData, Field.Size);
- ftDate:
- ConstPos := PutConstDate(Right^.FData);
- ftTime:
- ConstPos := PutConstTime(Right^.FData);
- ftDateTime:
- ConstPos := PutConstDateTime(Right^.FData);
- ftBoolean:
- ConstPos := PutConstBool(Right^.FData);
- else
- DatabaseErrorFmt(SExprBadField, [Field.FieldName]);
- ConstPos := 0;
- end;
- SetNodeOp(Result, 0, FieldPos);
- SetNodeOp(Result, 1, ConstPos);
- end;
- end;
-
- function TFilterExpr.PutConstBCD(const Value: Variant;
- Decimals: Integer): Integer;
- var
- C: Currency;
- BCD: FMTBcd;
- begin
- if VarType(Value) = varString then
- C := StrToCurr(string(TVarData(Value).VString)) else
- C := Value;
- CurrToFMTBCD(C, BCD, 32, Decimals);
- Result := PutConstNode(fldBCD, @BCD, 18);
- end;
-
- function TFilterExpr.PutConstBool(const Value: Variant): Integer;
- var
- B: WordBool;
- begin
- B := Value;
- Result := PutConstNode(fldBOOL, @B, SizeOf(WordBool));
- end;
-
- function TFilterExpr.PutConstDate(const Value: Variant): Integer;
- var
- DateTime: TDateTime;
- TimeStamp: TTimeStamp;
- begin
- if VarType(Value) = varString then
- DateTime := StrToDate(string(TVarData(Value).VString)) else
- DateTime := VarToDateTime(Value);
- TimeStamp := DateTimeToTimeStamp(DateTime);
- Result := PutConstNode(fldDATE, @TimeStamp.Date, 4);
- end;
-
- function TFilterExpr.PutConstDateTime(const Value: Variant): Integer;
- var
- DateTime: TDateTime;
- DateData: Double;
- begin
- if VarType(Value) = varString then
- DateTime := StrToDateTime(string(TVarData(Value).VString)) else
- DateTime := VarToDateTime(Value);
- DateData := TimeStampToMSecs(DateTimeToTimeStamp(DateTime));
- Result := PutConstNode(fldTIMESTAMP, @DateData, 8);
- end;
-
- function TFilterExpr.PutConstFloat(const Value: Variant): Integer;
- var
- F: Double;
- begin
- if VarType(Value) = varString then
- F := StrToFloat(string(TVarData(Value).VString)) else
- F := Value;
- Result := PutConstNode(fldFLOAT, @F, SizeOf(Double));
- end;
-
- function TFilterExpr.PutConstInt(DataType: Integer;
- const Value: Variant): Integer;
- var
- I, Size: Integer;
- begin
- if VarType(Value) = varString then
- I := StrToInt(string(TVarData(Value).VString)) else
- I := Value;
- Size := 2;
- case DataType of
- fldINT16:
- if (I < -32768) or (I > 32767) then DatabaseError(SExprRangeError);
- fldUINT16:
- if (I < 0) or (I > 65535) then DatabaseError(SExprRangeError);
- else
- Size := 4;
- end;
- Result := PutConstNode(DataType, @I, Size);
- end;
-
- function TFilterExpr.PutConstNode(DataType: Integer; Data: PChar;
- Size: Integer): Integer;
- begin
- Result := PutNode(nodeCONST, canCONST2, 3);
- SetNodeOp(Result, 0, DataType);
- SetNodeOp(Result, 1, Size);
- SetNodeOp(Result, 2, PutData(Data, Size));
- end;
-
- function TFilterExpr.PutConstStr(const Value: string): Integer;
- var
- Str: string;
- Buffer: array[0..255] of Char;
- begin
- if Length(Value) >= SizeOf(Buffer) then
- Str := Copy(Value, 1, SizeOf(Buffer) - 1) else
- Str := Value;
- FDataSet.Translate(PChar(Str), Buffer, True);
- Result := PutConstNode(fldZSTRING, Buffer, Length(Str) + 1);
- end;
-
- function TFilterExpr.PutConstTime(const Value: Variant): Integer;
- var
- DateTime: TDateTime;
- TimeStamp: TTimeStamp;
- begin
- if VarType(Value) = varString then
- DateTime := StrToTime(string(TVarData(Value).VString)) else
- DateTime := VarToDateTime(Value);
- TimeStamp := DateTimeToTimeStamp(DateTime);
- Result := PutConstNode(fldTIME, @TimeStamp.Time, 4);
- end;
-
- function TFilterExpr.PutData(Data: PChar; Size: Integer): Integer;
- begin
- Move(Data^, GetExprData(FExprBufSize, Size)^, Size);
- Result := FExprDataSize;
- Inc(FExprDataSize, Size);
- end;
-
- function TFilterExpr.PutExprNode(Node: PExprNode): Integer;
- const
- BoolFalse: WordBool = False;
- var
- Field: TField;
- begin
- case Node^.FKind of
- enField:
- begin
- Field := FieldFromNode(Node);
- if Field.DataType <> ftBoolean then
- DatabaseErrorFmt(SExprNotBoolean, [Field.FieldName]);
- Result := PutNode(nodeBINARY, canNE, 2);
- SetNodeOp(Result, 0, PutFieldNode(Field));
- SetNodeOp(Result, 1, PutConstNode(fldBOOL, @BoolFalse,
- SizeOf(WordBool)));
- end;
- enOperator:
- case Node^.FOperator of
- canEQ..canLE:
- Result := PutCompareNode(Node);
- canAND, canOR:
- begin
- Result := PutNode(nodeBINARY, Node^.FOperator, 2);
- SetNodeOp(Result, 0, PutExprNode(Node^.FLeft));
- SetNodeOp(Result, 1, PutExprNode(Node^.FRight));
- end;
- else
- Result := PutNode(nodeUNARY, canNOT, 1);
- SetNodeOp(Result, 0, PutExprNode(Node^.FLeft));
- end;
- else
- DatabaseError(SExprIncorrect);
- Result := 0;
- end;
- end;
-
- function TFilterExpr.PutFieldNode(Field: TField): Integer;
- var
- Buffer: array[0..255] of Char;
- begin
- FDataSet.Translate(PChar(Field.FieldName), Buffer, True);
- Result := PutNode(nodeFIELD, canFIELD2, 2);
- SetNodeOp(Result, 0, Field.FieldNo);
- SetNodeOp(Result, 1, PutData(Buffer, StrLen(Buffer) + 1));
- end;
-
- function TFilterExpr.PutNode(NodeType: NodeClass; OpType: CanOp;
- OpCount: Integer): Integer;
- var
- Size: Integer;
- begin
- Size := SizeOf(CANHdr) + OpCount * SizeOf(Word);
- with PCANHdr(GetExprData(SizeOf(CANExpr) + FExprNodeSize, Size))^ do
- begin
- nodeClass := NodeType;
- canOp := OpType;
- end;
- Result := FExprNodeSize;
- Inc(FExprNodeSize, Size);
- end;
-
- procedure TFilterExpr.SetNodeOp(Node, Index, Data: Integer);
- begin
- PWordArray(PChar(FExprBuffer) + (SizeOf(CANExpr) + Node +
- SizeOf(CANHdr)))^[Index] := Data;
- end;
-
- constructor TExprParser.Create(DataSet: TDataSet; const Text: string;
- Options: TFilterOptions);
- var
- Root: PExprNode;
- begin
- FFilter := TFilterExpr.Create(DataSet, Options);
- FStrTrue := STextTrue;
- FStrFalse := STextFalse;
- FText := Text;
- FSourcePtr := PChar(Text);
- NextToken;
- Root := ParseExpr;
- if FToken <> etEnd then DatabaseError(SExprTermination);
- FFilterData := FFilter.GetFilterData(Root);
- FDataSize := FFilter.FExprBufSize;
- end;
-
- destructor TExprParser.Destroy;
- begin
- FFilter.Free;
- end;
-
- procedure TExprParser.NextToken;
- var
- P, TokenStart: PChar;
- L: Integer;
- StrBuf: array[0..255] of Char;
-
- function IsKatakana(const Chr: Byte): Boolean;
- begin
- Result := (SysLocale.PriLangID = LANG_JAPANESE) and (Chr in [$A1..$DF]);
- end;
-
- begin
- FTokenString := '';
- P := FSourcePtr;
- 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
- begin
- while TRUE do
- begin
- if (P^ in ['A'..'Z', 'a'..'z', '0'..'9', '_']) or
- IsKatakana(Byte(P^)) then
- Inc(P)
- else
- if P^ in LeadBytes then
- Inc(P, 2)
- else
- Break;
- end;
- end;
- SetString(FTokenString, TokenStart, P - TokenStart);
- FToken := etSymbol;
- 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
- begin
- Inc(P);
- if P^ <> '''' then Break;
- end;
- if L < SizeOf(StrBuf) then
- begin
- StrBuf[L] := P^;
- Inc(L);
- end;
- Inc(P);
- end;
- SetString(FTokenString, StrBuf, L);
- FToken := etLiteral;
- end;
- '-', '0'..'9':
- begin
- TokenStart := P;
- Inc(P);
- while P^ in ['0'..'9', '.', 'e', 'E', '+', '-'] do Inc(P);
- SetString(FTokenString, TokenStart, P - TokenStart);
- FToken := etLiteral;
- 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;
- #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, canOR, Unassigned,
- Result, ParseExpr2);
- end;
- end;
-
- function TExprParser.ParseExpr2: PExprNode;
- begin
- Result := ParseExpr3;
- while TokenSymbolIs('AND') do
- begin
- NextToken;
- Result := FFilter.NewNode(enOperator, canAND, Unassigned,
- Result, ParseExpr3);
- end;
- end;
-
- function TExprParser.ParseExpr3: PExprNode;
- begin
- if TokenSymbolIs('NOT') then
- begin
- NextToken;
- Result := FFilter.NewNode(enOperator, canNOT, Unassigned,
- ParseExpr4, nil);
- end else
- Result := ParseExpr4;
- end;
-
- function TExprParser.ParseExpr4: PExprNode;
- const
- Operators: array[etEQ..etLT] of CanOp = (
- canEQ, canNE, canGE, canLE, canGT, canLT);
- var
- Operator: CanOp;
- begin
- Result := ParseExpr5;
- if FToken in [etEQ..etLT] then
- begin
- Operator := Operators[FToken];
- NextToken;
- Result := FFilter.NewNode(enOperator, Operator, Unassigned,
- Result, ParseExpr5);
- end;
- end;
-
- function TExprParser.ParseExpr5: PExprNode;
- begin
- case FToken of
- etSymbol:
- if TokenSymbolIs('NULL') then
- Result := FFilter.NewNode(enConst, canNOTDEFINED, System.Null, nil, nil)
- else if TokenSymbolIs(FStrTrue) then
- Result := FFilter.NewNode(enConst, canNOTDEFINED, 1, nil, nil)
- else if TokenSymbolIs(FStrFalse) then
- Result := FFilter.NewNode(enConst, canNOTDEFINED, 0, nil, nil)
- else
- Result := FFilter.NewNode(enField, canNOTDEFINED, FTokenString, nil, nil);
- etName:
- Result := FFilter.NewNode(enField, canNOTDEFINED, FTokenString, nil, nil);
- etLiteral:
- Result := FFilter.NewNode(enConst, canNOTDEFINED, FTokenString, nil, nil);
- etLParen:
- begin
- NextToken;
- Result := ParseExpr;
- if FToken <> etRParen then DatabaseErrorFmt(SExprNoRParen, [TokenName]);
- end;
- else
- DatabaseErrorFmt(SExprExpected, [TokenName]);
- Result := nil;
- end;
- NextToken;
- 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;
-
- { TMasterDataLink }
-
- constructor TMasterDataLink.Create(DataSet: TDataSet);
- begin
- inherited Create;
- FDataSet := DataSet;
- FFields := TList.Create;
- end;
-
- destructor TMasterDataLink.Destroy;
- begin
- FFields.Free;
- inherited Destroy;
- end;
-
- procedure TMasterDataLink.ActiveChanged;
- begin
- FFields.Clear;
- if Active then
- try
- DataSet.GetFieldList(FFields, FFieldNames);
- except
- FFields.Clear;
- raise;
- end;
- if FDataSet.Active and not (csDestroying in FDataSet.ComponentState) then
- if Active and (FFields.Count > 0) then
- begin
- if Assigned(FOnMasterChange) then FOnMasterChange(Self);
- end else
- if Assigned(FOnMasterDisable) then FOnMasterDisable(Self);
- end;
-
- procedure TMasterDataLink.CheckBrowseMode;
- begin
- if FDataSet.Active then FDataSet.CheckBrowseMode;
- end;
-
- procedure TMasterDataLink.LayoutChanged;
- begin
- ActiveChanged;
- end;
-
- procedure TMasterDataLink.RecordChanged(Field: TField);
- begin
- if (DataSource.State <> dsSetKey) and FDataSet.Active and
- (FFields.Count > 0) and ((Field = nil) or
- (FFields.IndexOf(Field) >= 0)) and
- Assigned(FOnMasterChange) then
- FOnMasterChange(Self);
- end;
-
- procedure TMasterDataLink.SetFieldNames(const Value: string);
- begin
- if FFieldNames <> Value then
- begin
- FFieldNames := Value;
- ActiveChanged;
- end;
- end;
-
-
- end.