home *** CD-ROM | disk | FTP | other *** search
-
- {*******************************************************}
- { }
- { Delphi Visual Component Library }
- { }
- { Copyright (c) 1995,96 Borland International }
- { }
- {*******************************************************}
-
- unit DBTables;
-
- {$N+,P+,S-,R-}
-
- interface
-
- uses SysUtils, Windows, Bde, Classes, Controls, Graphics, Mask, DB;
-
- type
-
- { TIndexDef }
-
- TIndexDefs = class;
-
- TIndexOptions = set of (ixPrimary, ixUnique, ixDescending,
- ixCaseInsensitive, ixExpression);
-
- TIndexDef = class
- private
- FOwner: TIndexDefs;
- FSource: string;
- FName: string;
- FFields: string;
- FOptions: TIndexOptions;
- function GetExpression: string;
- function GetFields: string;
- public
- constructor Create(Owner: TIndexDefs; const Name, Fields: string;
- Options: TIndexOptions);
- destructor Destroy; override;
- property Expression: string read GetExpression;
- property Fields: string read GetFields;
- property Name: string read FName;
- property Options: TIndexOptions read FOptions;
- property Source: string read FSource;
- end;
-
- { TIndexDefs }
-
- TTable = class;
-
- TIndexDefs = class
- private
- FTable: TTable;
- FItems: TList;
- FUpdated: Boolean;
- FReserved: Byte;
- function GetCount: Integer;
- function GetIndexForFields(const Fields: string;
- CaseInsensitive: Boolean): TIndexDef;
- function GetItem(Index: Integer): TIndexDef;
- public
- constructor Create(Table: TTable);
- destructor Destroy; override;
- procedure Add(const Name, Fields: string; Options: TIndexOptions);
- procedure Assign(IndexDefs: TIndexDefs);
- procedure Clear;
- function FindIndexForFields(const Fields: string): TIndexDef;
- function IndexOf(const Name: string): Integer;
- procedure Update;
- property Count: Integer read GetCount;
- property Items[Index: Integer]: TIndexDef read GetItem; default;
- end;
-
- { TTableDataLink }
-
- TTableDataLink = class(TDataLink)
- private
- FTable: TTable;
- FFieldNames: string;
- FFields: TList;
- procedure SetFieldNames(const Value: string);
- protected
- procedure ActiveChanged; override;
- procedure CheckBrowseMode; override;
- procedure LayoutChanged; override;
- procedure RecordChanged(Field: TField); override;
- public
- constructor Create(Table: TTable);
- destructor Destroy; override;
- end;
-
- { TTable }
-
- TBatchMode = (batAppend, batUpdate, batAppendUpdate, batDelete, batCopy);
- TTableType = (ttDefault, ttParadox, ttDBase, ttASCII);
- TLockType = (ltReadLock, ltWriteLock);
- TIndexName = type string;
-
- TIndexFiles = class(TStringList)
- private
- FOwner: TTable;
- public
- constructor Create(AOwner: TTable);
- function Add(const S: string): Integer; override;
- procedure Clear; override;
- procedure Delete(Index: Integer); override;
- procedure Insert(Index: Integer; const S: string); override;
- end;
-
- TTable = class(TDBDataSet)
- private
- FIndexDefs: TIndexDefs;
- FDataLink: TTableDataLink;
- FExclusive: Boolean;
- FReadOnly: Boolean;
- FTableType: TTableType;
- FFieldsIndex: Boolean;
- FTableName: TFileName;
- FIndexName: TIndexName;
- FIndexFiles: TStrings;
- FLookupHandle: HDBICur;
- FLookupKeyFields: string;
- FLookupCursor: HDBICur;
- procedure DecodeIndexDesc(const IndexDesc: IDXDesc;
- var Source, Name, Fields: string; var Options: TIndexOptions);
- procedure EncodeFieldDesc(var FieldDesc: FLDDesc;
- const Name: string; DataType: TFieldType; Size: Word);
- procedure EncodeIndexDesc(var IndexDesc: IDXDesc;
- const Name, Fields: string; Options: TIndexOptions);
- function GetDriverTypeName(Buffer: PChar): PChar;
- function GetIndexFieldNames: string;
- function GetIndexName: string;
- procedure GetIndexParams(const IndexName: string; FieldsIndex: Boolean;
- var IndexedName, IndexTag: string);
- function GetMasterFields: string;
- function GetTableTypeName: PChar;
- function IsDBaseTable: Boolean;
- procedure MasterChanged;
- procedure SetDataSource(Value: TDataSource);
- procedure SetExclusive(Value: Boolean);
- procedure SetIndex(const Value: string; FieldsIndex: Boolean);
- procedure SetIndexFieldNames(const Value: string);
- procedure SetIndexFiles(Value: TStrings);
- procedure SetIndexName(const Value: string);
- procedure SetMasterFields(const Value: string);
- procedure SetReadOnly(Value: Boolean);
- procedure SetTableLock(LockType: TLockType; Lock: Boolean);
- procedure SetTableName(const Value: TFileName);
- procedure SetTableType(Value: TTableType);
- procedure UpdateIndexDefs;
- procedure UpdateRange;
- protected
- function CreateHandle: HDBICur; override;
- procedure DataEvent(Event: TDataEvent; Info: Longint); override;
- procedure DestroyHandle; override;
- procedure DestroyLookupCursor; override;
- procedure DoOnNewRecord; override;
- function GetCanModify: Boolean; override;
- function GetDataSource: TDataSource; override;
- function GetHandle(const IndexName, IndexTag: string): HDBICur;
- function GetLanguageDriverName: string;
- function GetLookupCursor(const KeyFields: string;
- CaseInsensitive: Boolean): HDBICur; override;
- procedure InitFieldDefs; override;
- function IsProductionIndex(const IndexName: string): Boolean;
- procedure PrepareCursor; override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function BatchMove(ASource: TDataSet; AMode: TBatchMode): Longint;
- procedure AddIndex(const Name, Fields: string; Options: TIndexOptions);
- procedure ApplyRange;
- procedure CancelRange;
- procedure CloseIndexFile(const IndexFileName: string);
- procedure CreateTable;
- procedure DeleteIndex(const Name: string);
- procedure DeleteTable;
- procedure EditKey;
- procedure EditRangeEnd;
- procedure EditRangeStart;
- procedure EmptyTable;
- function FindKey(const KeyValues: array of const): Boolean;
- procedure FindNearest(const KeyValues: array of const);
- procedure GetIndexNames(List: TStrings);
- procedure GotoCurrent(Table: TTable);
- function GotoKey: Boolean;
- procedure GotoNearest;
- procedure LockTable(LockType: TLockType);
- procedure OpenIndexFile(const IndexName: string);
- procedure RenameTable(const NewTableName: string);
- procedure SetKey;
- procedure SetRange(const StartValues, EndValues: array of const);
- procedure SetRangeEnd;
- procedure SetRangeStart;
- procedure UnlockTable(LockType: TLockType);
- property IndexDefs: TIndexDefs read FIndexDefs;
- property IndexFieldCount: Integer read GetIndexFieldCount;
- property IndexFields[Index: Integer]: TField read GetIndexField write SetIndexField;
- property KeyExclusive: Boolean read GetKeyExclusive write SetKeyExclusive;
- property KeyFieldCount: Integer read GetKeyFieldCount write SetKeyFieldCount;
- published
- property Exclusive: Boolean read FExclusive write SetExclusive default False;
- property IndexFieldNames: string read GetIndexFieldNames write SetIndexFieldNames;
- property IndexFiles: TStrings read FIndexFiles write SetIndexFiles;
- property IndexName: string read GetIndexName write SetIndexName;
- property MasterFields: string read GetMasterFields write SetMasterFields;
- property MasterSource: TDataSource read GetDataSource write SetDataSource;
- property ReadOnly: Boolean read FReadOnly write SetReadOnly default False;
- property TableName: TFileName read FTableName write SetTableName;
- property TableType: TTableType read FTableType write SetTableType default ttDefault;
- property UpdateMode;
- property UpdateObject;
- end;
-
- { TBatchMove }
-
- TBatchMove = class(TComponent)
- private
- FDestination: TTable;
- FSource: TDataSet;
- FMode: TBatchMode;
- FAbortOnKeyViol: Boolean;
- FAbortOnProblem: Boolean;
- FTransliterate: Boolean;
- FRecordCount: Longint;
- FMovedCount: Longint;
- FKeyViolCount: Longint;
- FProblemCount: Longint;
- FChangedCount: Longint;
- FMappings: TStrings;
- FKeyViolTableName: TFileName;
- FProblemTableName: TFileName;
- FChangedTableName: TFileName;
- FCommitCount: Integer;
- function ConvertName(const Name: string; Buffer: PChar): PChar;
- procedure SetDesination(Value: TTable);
- procedure SetMappings(Value: TStrings);
- procedure SetSource(Value: TDataSet);
- protected
- procedure Notification(AComponent: TComponent;
- Operation: TOperation); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Execute;
- public
- property ChangedCount: Longint read FChangedCount;
- property KeyViolCount: Longint read FKeyViolCount;
- property MovedCount: Longint read FMovedCount;
- property ProblemCount: Longint read FProblemCount;
- published
- property AbortOnKeyViol: Boolean read FAbortOnKeyViol write FAbortOnKeyViol default True;
- property AbortOnProblem: Boolean read FAbortOnProblem write FAbortOnProblem default True;
- property CommitCount: Integer read FCommitCount write FCommitCount default 0;
- property ChangedTableName: TFileName read FChangedTableName write FChangedTableName;
- property Destination: TTable read FDestination write FDestination;
- property KeyViolTableName: TFileName read FKeyViolTableName write FKeyViolTableName;
- property Mappings: TStrings read FMappings write SetMappings;
- property Mode: TBatchMode read FMode write FMode default batAppend;
- property ProblemTableName: TFileName read FProblemTableName write FProblemTableName;
- property RecordCount: Longint read FRecordCount write FRecordCount default 0;
- property Source: TDataSet read FSource write SetSource;
- property Transliterate: Boolean read FTransliterate write FTransliterate default True;
- end;
-
- { TParam }
-
- TQuery = class;
- TParams = class;
-
- TParamType = (ptUnknown, ptInput, ptOutput, ptInputOutput, ptResult);
-
- TParam = class(TObject)
- private
- FParamList: TParams;
- FData: Variant;
- FName: string;
- FDataType: TFieldType;
- FNull: Boolean;
- FBound: Boolean;
- FParamType: TParamType;
- procedure AccessError;
- procedure InitValue;
- protected
- function GetAsBCD: Currency;
- function GetAsBoolean: Boolean;
- function GetAsDateTime: TDateTime;
- function GetAsFloat: Double;
- function GetAsInteger: Longint;
- function GetAsString: string;
- function GetAsVariant: Variant;
- function IsEqual(Value: TParam): Boolean;
- procedure SetAsBCD(Value: Currency);
- procedure SetAsBoolean(Value: Boolean);
- procedure SetAsCurrency(Value: Double);
- procedure SetAsDate(Value: TDateTime);
- procedure SetAsDateTime(Value: TDateTime);
- procedure SetAsFloat(Value: Double);
- procedure SetAsInteger(Value: Longint);
- procedure SetAsString(const Value: string);
- procedure SetAsSmallInt(Value: LongInt);
- procedure SetAsTime(Value: TDateTime);
- procedure SetAsVariant(Value: Variant);
- procedure SetAsWord(Value: LongInt);
- procedure SetDataType(Value: TFieldType);
- procedure SetText(const Value: string);
- public
- constructor Create(AParamList: TParams; AParamType: TParamType);
- destructor Destroy; override;
- procedure Assign(Param: TParam);
- procedure AssignField(Field: TField);
- procedure AssignFieldValue(Field: TField; const Value: Variant);
- procedure Clear;
- procedure GetData(Buffer: Pointer);
- function GetDataSize: Word;
- procedure SetData(Buffer: Pointer);
- property AsBCD: Currency read GetAsBCD write SetAsBCD;
- property AsBoolean: Boolean read GetAsBoolean write SetAsBoolean;
- property AsCurrency: Double read GetAsFloat write SetAsCurrency;
- property AsDate: TDateTime read GetAsDateTime write SetAsDate;
- property AsDateTime: TDateTime read GetAsDateTime write SetAsDateTime;
- property AsFloat: Double read GetAsFloat write SetAsFloat;
- property AsInteger: LongInt read GetAsInteger write SetAsInteger;
- property AsSmallInt: LongInt read GetAsInteger write SetAsSmallInt;
- property AsString: string read GetAsString write SetAsString;
- property AsTime: TDateTime read GetAsDateTime write SetAsTime;
- property AsWord: LongInt read GetAsInteger write SetAsWord;
- property Bound: Boolean read FBound write FBound;
- property DataType: TFieldType read FDataType write SetDataType;
- property IsNull: Boolean read FNull;
- property Name: string read FName write FName;
- property ParamType: TParamType read FParamType write FParamType;
- property Text: string read GetAsString write SetText;
- property Value: Variant read GetAsVariant write SetAsVariant;
- end;
-
- { TParams }
-
- TParams = class(TPersistent)
- private
- FItems: TList;
- function GetParam(Index: Word): TParam;
- function GetParamValue(const ParamName: string): Variant;
- function GetVersion: Word;
- procedure ReadBinaryData(Stream: TStream);
- procedure SetParamValue(const ParamName: string;
- const Value: Variant);
- procedure WriteBinaryData(Stream: TStream);
- protected
- procedure AssignTo(Dest: TPersistent); override;
- procedure DefineProperties(Filer: TFiler); override;
- public
- constructor Create; virtual;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure AssignValues(Value: TParams);
- procedure AddParam(Value: TParam);
- procedure RemoveParam(Value: TParam);
- function CreateParam(FldType: TFieldType; const ParamName: string;
- ParamType: TParamType): TParam;
- function Count: Integer;
- procedure Clear;
- procedure GetParamList(List: TList; const ParamNames: string);
- function IsEqual(Value: TParams): Boolean;
- function ParamByName(const Value: string): TParam;
- property Items[Index: Word]: TParam read GetParam; default;
- property ParamValues[const ParamName: string]: Variant read GetParamValue write SetParamValue;
- end;
-
- { TStoredProc }
-
- PServerDesc = ^TServerDesc;
- TServerDesc = record
- ParamName: string[DBIMAXSPNAMELEN];
- BindType: TFieldType;
- end;
-
- TParamBindMode = (pbByName, pbByNumber);
-
- TStoredProc = class(TDBDataSet)
- private
- FStmtHandle: HDBIStmt;
- FProcName: string;
- FParams: TParams;
- FParamDesc: PChar;
- FRecordBuffer: PChar;
- FOverLoad: Word;
- FPrepared: Boolean;
- FQueryMode: Boolean;
- FServerDescs: PChar;
- FBindMode: TParamBindMode;
- procedure BindParams;
- function CheckServerParams: Boolean;
- function CreateCursor(GenHandle: Boolean): HDBICur;
- procedure CreateParamDesc;
- procedure FreeStatement;
- function GetCursor(GenHandle: Boolean): HDBICur;
- procedure PrepareProc;
- procedure SetParamsList(Value: TParams);
- procedure SetServerParams;
- protected
- function CreateHandle: HDBICur; override;
- procedure Disconnect; override;
- function GetParamsCount: Word;
- procedure SetDBFlag(Flag: Integer; Value: Boolean); override;
- procedure SetOverLoad(Value: Word);
- procedure SetProcName(const Value: string);
- procedure SetPrepared(Value: Boolean);
- procedure SetPrepare(Value: Boolean);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure CopyParams(Value: TParams);
- function DescriptionsAvailable: Boolean;
- procedure ExecProc;
- function ParamByName(const Value: string): TParam;
- procedure Prepare;
- procedure GetResults;
- procedure UnPrepare;
- property ParamCount: Word read GetParamsCount;
- property StmtHandle: HDBIStmt read FStmtHandle;
- property Prepared: Boolean read FPrepared write SetPrepare;
- published
- property StoredProcName: string read FProcName write SetProcName;
- property Overload: Word read FOverload write SetOverload default 0;
- property Params: TParams read FParams write SetParamsList;
- property ParamBindMode: TParamBindMode read FBindMode write FBindMode default pbByName;
- property UpdateObject;
- end;
-
- { TQuery }
-
- TQuery = class(TDBDataSet)
- private
- FStmtHandle: HDBIStmt;
- FSQL: TStrings;
- FPrepared: Boolean;
- FParams: TParams;
- FText: string;
- FDataLink: TDataLink;
- FLocal: Boolean;
- FRowsAffected: Integer;
- FUniDirectional: Boolean;
- FRequestLive: Boolean;
- FSQLBinary: PChar;
- FConstrained: Boolean;
- FParamCheck: Boolean;
- function CreateCursor(GenHandle: Boolean): HDBICur;
- procedure CreateParams(List: TParams; const Value: PChar);
- procedure DefineProperties(Filer: TFiler); override;
- procedure FreeStatement;
- function GetQueryCursor(GenHandle: Boolean): HDBICur;
- procedure GetStatementHandle(SQLText: PChar);
- function GetSQLText: PChar;
- function GetRowsAffected: Integer;
- procedure PrepareSQL(Value: PChar);
- procedure QueryChanged(Sender: TObject);
- procedure ReadBinaryData(Stream: TStream);
- procedure RefreshParams;
- procedure SetDataSource(Value: TDataSource);
- procedure SetQuery(Value: TStrings);
- procedure SetParamsList(Value: TParams);
- procedure SetParams;
- procedure SetParamsFromCursor;
- procedure SetPrepared(Value: Boolean);
- procedure SetPrepare(Value: Boolean);
- procedure WriteBinaryData(Stream: TStream);
- protected
- function CreateHandle: HDBICur; override;
- procedure Disconnect; override;
- function GetDataSource: TDataSource; override;
- function GetParamsCount: Word;
- procedure SetDBFlag(Flag: Integer; Value: Boolean); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure ExecSQL;
- function ParamByName(const Value: string): TParam;
- procedure Prepare;
- procedure UnPrepare;
- property Prepared: Boolean read FPrepared write SetPrepare;
- property ParamCount: Word read GetParamsCount;
- property Local: Boolean read FLocal;
- property StmtHandle: HDBIStmt read FStmtHandle;
- property Text: string read FText;
- property RowsAffected: Integer read GetRowsAffected;
- property SQLBinary: PChar read FSQLBinary write FSQLBinary;
- published
- property Constrained: Boolean read FConstrained write FConstrained default False;
- property DataSource: TDataSource read GetDataSource write SetDataSource;
- property Params: TParams read FParams write SetParamsList;
- property ParamCheck: Boolean read FParamCheck write FParamCheck default True;
- property RequestLive: Boolean read FRequestLive write FRequestLive default False;
- property SQL: TStrings read FSQL write SetQuery;
- property UniDirectional: Boolean read FUniDirectional write FUniDirectional default False;
- property UpdateMode;
- property UpdateObject;
- end;
-
- { TUpdateSQL }
-
- TUpdateSQL = class(TDataSetUpdateObject)
- private
- FDataSet: TDataSet;
- FQueries: array[TUpdateKind] of TQuery;
- FSQLText: array[TUpdateKind] of TStrings;
- function GetQuery(UpdateKind: TUpdateKind): TQuery;
- function GetSQL(UpdateKind: TUpdateKind): TStrings;
- function GetSQLIndex(Index: Integer): TStrings;
- procedure SetSQL(UpdateKind: TUpdateKind; Value: TStrings);
- procedure SetSQLIndex(Index: Integer; Value: TStrings);
- protected
- function GetDataSet: TDataSet; override;
- procedure SetDataSet(ADataSet: TDataSet); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Apply(UpdateKind: TUpdateKind); override;
- procedure ExecSQL(UpdateKind: TUpdateKind);
- procedure SetParams(UpdateKind: TUpdateKind);
- property DataSet;
- property Query[UpdateKind: TUpdateKind]: TQuery read GetQuery;
- property SQL[UpdateKind: TUpdateKind]: TStrings read GetSQL write SetSQL;
- published
- property ModifySQL: TStrings index 0 read GetSQLIndex write SetSQLIndex;
- property InsertSQL: TStrings index 1 read GetSQLIndex write SetSQLIndex;
- property DeleteSQL: TStrings index 2 read GetSQLIndex write SetSQLIndex;
- end;
-
- { TStringField }
-
- TStringField = class(TField)
- private
- FTransliterate: Boolean;
- FReserved: Byte;
- protected
- function GetAsBoolean: Boolean; override;
- function GetAsDateTime: TDateTime; override;
- function GetAsFloat: Double; override;
- function GetAsInteger: Longint; override;
- function GetAsString: string; override;
- function GetAsVariant: Variant; override;
- function GetDefaultWidth: Integer; override;
- procedure GetText(var Text: string; DisplayText: Boolean); override;
- function GetValue(var Value: string): Boolean;
- procedure SetAsBoolean(Value: Boolean); override;
- procedure SetAsDateTime(Value: TDateTime); override;
- procedure SetAsFloat(Value: Double); override;
- procedure SetAsInteger(Value: Longint); override;
- procedure SetAsString(const Value: string); override;
- procedure SetVarValue(const Value: Variant); override;
- public
- constructor Create(AOwner: TComponent); override;
- property Value: string read GetAsString write SetAsString;
- published
- property EditMask;
- property Size default 20;
- property Transliterate: Boolean read FTransliterate write FTransliterate default True;
- end;
-
- { TNumericField }
-
- TNumericField = class(TField)
- private
- FDisplayFormat: string;
- FEditFormat: string;
- procedure RangeError(Value, Min, Max: Extended);
- procedure SetDisplayFormat(const Value: string);
- procedure SetEditFormat(const Value: string);
- public
- constructor Create(AOwner: TComponent); override;
- published
- property Alignment default taRightJustify;
- property DisplayFormat: string read FDisplayFormat write SetDisplayFormat;
- property EditFormat: string read FEditFormat write SetEditFormat;
- end;
-
- { TIntegerField }
-
- TIntegerField = class(TNumericField)
- private
- FMinRange: Longint;
- FMaxRange: Longint;
- FMinValue: Longint;
- FMaxValue: Longint;
- procedure CheckRange(Value, Min, Max: Longint);
- procedure SetMaxValue(Value: Longint);
- procedure SetMinValue(Value: Longint);
- protected
- function GetAsFloat: Double; override;
- function GetAsInteger: Longint; override;
- function GetAsString: string; override;
- function GetAsVariant: Variant; override;
- procedure GetText(var Text: string; DisplayText: Boolean); override;
- function GetValue(var Value: Longint): Boolean;
- procedure SetAsFloat(Value: Double); override;
- procedure SetAsInteger(Value: Longint); override;
- procedure SetAsString(const Value: string); override;
- procedure SetVarValue(const Value: Variant); override;
- public
- constructor Create(AOwner: TComponent); override;
- function IsValidChar(Ch: Char): Boolean; override;
- property Value: Longint read GetAsInteger write SetAsInteger;
- published
- property MaxValue: Longint read FMaxValue write SetMaxValue default 0;
- property MinValue: Longint read FMinValue write SetMinValue default 0;
- end;
-
- { TSmallintField }
-
- TSmallintField = class(TIntegerField)
- public
- constructor Create(AOwner: TComponent); override;
- end;
-
- { TWordField }
-
- TWordField = class(TIntegerField)
- public
- constructor Create(AOwner: TComponent); override;
- end;
-
- { TAutoIncField }
-
- TAutoIncField = class(TIntegerField)
- public
- constructor Create(AOwner: TComponent); override;
- end;
-
- { TFloatField }
-
- TFloatField = class(TNumericField)
- private
- FCurrency: Boolean;
- FCheckRange: Boolean;
- FPrecision: Integer;
- FMinValue: Double;
- FMaxValue: Double;
- procedure SetCurrency(Value: Boolean);
- procedure SetMaxValue(Value: Double);
- procedure SetMinValue(Value: Double);
- procedure SetPrecision(Value: Integer);
- procedure UpdateCheckRange;
- protected
- function GetAsFloat: Double; override;
- function GetAsInteger: Longint; override;
- function GetAsString: string; override;
- function GetAsVariant: Variant; override;
- procedure GetText(var Text: string; DisplayText: Boolean); override;
- procedure SetAsFloat(Value: Double); override;
- procedure SetAsInteger(Value: Longint); override;
- procedure SetAsString(const Value: string); override;
- procedure SetVarValue(const Value: Variant); override;
- public
- constructor Create(AOwner: TComponent); override;
- function IsValidChar(Ch: Char): Boolean; override;
- property Value: Double read GetAsFloat write SetAsFloat;
- published
- property Currency: Boolean read FCurrency write SetCurrency default False;
- property MaxValue: Double read FMaxValue write SetMaxValue;
- property MinValue: Double read FMinValue write SetMinValue;
- property Precision: Integer read FPrecision write SetPrecision default 15;
- end;
-
- { TCurrencyField }
-
- TCurrencyField = class(TFloatField)
- public
- constructor Create(AOwner: TComponent); override;
- published
- property Currency default True;
- end;
-
- { TBCDField }
-
- TBCDField = class(TNumericField)
- public
- FCurrency: Boolean;
- FCheckRange: Boolean;
- FMinValue: Currency;
- FMaxValue: Currency;
- procedure SetCurrency(Value: Boolean);
- procedure SetMaxValue(Value: Currency);
- procedure SetMinValue(Value: Currency);
- procedure UpdateCheckRange;
- protected
- function GetAsCurrency: Currency; override;
- function GetAsFloat: Double; override;
- function GetAsInteger: Longint; override;
- function GetAsString: string; override;
- function GetAsVariant: Variant; override;
- procedure GetText(var Text: string; DisplayText: Boolean); override;
- function GetValue(var Value: Currency): Boolean;
- procedure SetAsCurrency(Value: Currency); override;
- procedure SetAsFloat(Value: Double); override;
- procedure SetAsInteger(Value: Longint); override;
- procedure SetAsString(const Value: string); override;
- procedure SetVarValue(const Value: Variant); override;
- public
- constructor Create(AOwner: TComponent); override;
- function IsValidChar(Ch: Char): Boolean; override;
- property Value: Currency read GetAsCurrency write SetAsCurrency;
- published
- property Currency: Boolean read FCurrency write SetCurrency default False;
- property MaxValue: Currency read FMaxValue write SetMaxValue;
- property MinValue: Currency read FMinValue write SetMinValue;
- property Size default 4;
- end;
-
- { TBooleanField }
-
- TBooleanField = class(TField)
- private
- FDisplayValues: string;
- FTextValues: array[Boolean] of string;
- procedure LoadTextValues;
- procedure SetDisplayValues(const Value: string);
- protected
- function GetAsBoolean: Boolean; override;
- function GetAsString: string; override;
- function GetAsVariant: Variant; override;
- function GetDefaultWidth: Integer; override;
- procedure SetAsBoolean(Value: Boolean); override;
- procedure SetAsString(const Value: string); override;
- procedure SetVarValue(const Value: Variant); override;
- public
- constructor Create(AOwner: TComponent); override;
- property Value: Boolean read GetAsBoolean write SetAsBoolean;
- published
- property DisplayValues: string read FDisplayValues write SetDisplayValues;
- end;
-
- { TDateTimeField }
-
- TDateTimeField = class(TField)
- private
- FDisplayFormat: string;
- function GetValue(var Value: TDateTime): Boolean;
- procedure SetDisplayFormat(const Value: string);
- protected
- function GetAsDateTime: TDateTime; override;
- function GetAsFloat: Double; override;
- function GetAsString: string; override;
- function GetAsVariant: Variant; override;
- procedure GetText(var Text: string; DisplayText: Boolean); override;
- procedure SetAsDateTime(Value: TDateTime); override;
- procedure SetAsFloat(Value: Double); override;
- procedure SetAsString(const Value: string); override;
- procedure SetVarValue(const Value: Variant); override;
- public
- constructor Create(AOwner: TComponent); override;
- property Value: TDateTime read GetAsDateTime write SetAsDateTime;
- published
- property DisplayFormat: string read FDisplayFormat write SetDisplayFormat;
- property EditMask;
- end;
-
- { TDateField }
-
- TDateField = class(TDateTimeField)
- public
- constructor Create(AOwner: TComponent); override;
- end;
-
- { TTimeField }
-
- TTimeField = class(TDateTimeField)
- public
- constructor Create(AOwner: TComponent); override;
- end;
-
-
- { TBinaryField }
-
- TBinaryField = class(TField)
- protected
- function GetAsVariant: Variant; override;
- procedure SetVarValue(const Value: Variant); override;
- public
- constructor Create(AOwner: TComponent); override;
- published
- property Size default 16;
- end;
-
- { TBytesField }
-
- TBytesField = class(TBinaryField)
- public
- constructor Create(AOwner: TComponent); override;
- end;
-
- { TVarBytesField }
-
- TVarBytesField = class(TBytesField)
- public
- constructor Create(AOwner: TComponent); override;
- end;
-
- { TBlobField }
-
- TBlobType = ftBlob..ftTypedBinary;
-
- TBlobField = class(TField)
- private
- FModified: Boolean;
- FTransliterate: Boolean;
- function GetBlobType: TBlobType;
- procedure LoadFromBlob(Blob: TBlobField);
- procedure LoadFromBitmap(Bitmap: TBitmap);
- procedure LoadFromStrings(Strings: TStrings);
- procedure SaveToBitmap(Bitmap: TBitmap);
- procedure SaveToStrings(Strings: TStrings);
- procedure SetBlobType(Value: TBlobType);
- protected
- procedure AssignTo(Dest: TPersistent); override;
- procedure FreeBuffers; override;
- function GetAsString: string; override;
- function GetAsVariant: Variant; override;
- procedure GetText(var Text: string; DisplayText: Boolean); override;
- procedure SetAsString(const Value: string); override;
- procedure SetVarValue(const Value: Variant); override;
- public
- constructor Create(AOwner: TComponent); override;
- procedure Assign(Source: TPersistent); override;
- procedure Clear; override;
- procedure LoadFromFile(const FileName: string);
- procedure LoadFromStream(Stream: TStream);
- procedure SaveToFile(const FileName: string);
- procedure SaveToStream(Stream: TStream);
- procedure SetFieldType(Value: TFieldType); override;
- procedure SetText(const Value: string); override;
- property Value: string read GetAsString write SetAsString;
- published
- property BlobType: TBlobType read GetBlobType write SetBlobType;
- property Size default 0;
- end;
-
- { TMemoField }
-
- TMemoField = class(TBlobField)
- public
- constructor Create(AOwner: TComponent); override;
- published
- property Transliterate: Boolean read FTransliterate write FTransliterate default True;
- end;
-
- { TGraphicField }
-
- TGraphicField = class(TBlobField)
- public
- constructor Create(AOwner: TComponent); override;
- end;
-
- { TBlobStream }
-
- TBlobStreamMode = (bmRead, bmWrite, bmReadWrite);
-
- TBlobStream = class(TStream)
- private
- FField: TBlobField;
- FDataSet: TDataSet;
- FRecord: PChar;
- FBuffer: PChar;
- FFieldNo: Integer;
- FOpened: Boolean;
- FModified: Boolean;
- FPosition: Longint;
- function GetBlobSize: Longint;
- public
- constructor Create(Field: TBlobField; Mode: TBlobStreamMode);
- destructor Destroy; override;
- function Read(var Buffer; Count: Longint): Longint; override;
- function Write(const Buffer; Count: Longint): Longint; override;
- function Seek(Offset: Longint; Origin: Word): Longint; override;
- procedure Truncate;
- end;
-
- { TFieldDataLink }
-
- TFieldDataLink = class(TDataLink)
- private
- FField: TField;
- FFieldName: string;
- FControl: TWinControl;
- FEditing: Boolean;
- FModified: Boolean;
- FOnDataChange: TNotifyEvent;
- FOnEditingChange: TNotifyEvent;
- FOnUpdateData: TNotifyEvent;
- FOnActiveChange: TNotifyEvent;
- function GetCanModify: Boolean;
- procedure SetEditing(Value: Boolean);
- procedure SetField(Value: TField);
- procedure SetFieldName(const Value: string);
- procedure UpdateField;
- protected
- procedure ActiveChanged; override;
- procedure EditingChanged; override;
- procedure FocusControl(Field: TFieldRef); override;
- procedure LayoutChanged; override;
- procedure RecordChanged(Field: TField); override;
- procedure UpdateData; override;
- public
- function Edit: Boolean;
- procedure Modified;
- procedure Reset;
- property CanModify: Boolean read GetCanModify;
- property Control: TWinControl read FControl write FControl;
- property Editing: Boolean read FEditing;
- property Field: TField read FField;
- property FieldName: string read FFieldName write SetFieldName;
- property OnDataChange: TNotifyEvent read FOnDataChange write FOnDataChange;
- property OnEditingChange: TNotifyEvent read FOnEditingChange write FOnEditingChange;
- property OnUpdateData: TNotifyEvent read FOnUpdateData write FOnUpdateData;
- property OnActiveChange: TNotifyEvent read FOnActiveChange write FOnActiveChange;
- end;
-
- function BCDToCurr(const BCD: FMTBcd; var Curr: Currency): Boolean;
- function CurrToBCD(Curr: Currency; var BCD: FMTBcd; Precision,
- Decimals: Integer): Boolean;
-
- implementation
-
- uses DBConsts, Forms;
-
- { TQueryDataLink }
-
- type
- TQueryDataLink = class(TDataLink)
- private
- FQuery: TQuery;
- protected
- procedure ActiveChanged; override;
- procedure RecordChanged(Field: TField); override;
- procedure CheckBrowseMode; override;
- public
- constructor Create(AQuery: TQuery);
- end;
-
- { Date and time conversion record }
-
- type
- TDateTimeRec = record
- case TFieldType of
- ftDate: (Date: Longint);
- ftTime: (Time: Longint);
- ftDateTime: (DateTime: TDateTime);
- end;
-
- { Paradox graphic BLOB header }
-
- type
- TGraphicHeader = record
- Count: Word; { Fixed at 1 }
- HType: Word; { Fixed at $0100 }
- Size: Longint; { Size not including header }
- end;
-
- { Utility routines }
-
- procedure CheckIndexOpen(Status: DBIResult);
- begin
- if (Status <> 0) and (Status <> DBIERR_INDEXOPEN) then
- DbiError(Status);
- end;
-
- function IsFloat(const Value: string): Boolean;
- var
- I: Integer;
- begin
- Result := False;
- if Value <> '' then
- begin
- for I := 1 to Length(Value) do
- if not (Value[I] in [DecimalSeparator, '0'..'9']) then Exit;
- Result := True;
- end;
- end;
-
- function IsInteger(const Value: string): Boolean;
- var
- I: Integer;
- begin
- Result := False;
- if Value <> '' then
- begin
- for I := 1 to Length(Value) do
- if not (Value[I] in ['0'..'9']) then Exit;
- Result := True;
- end;
- end;
-
- function CompDiv(var Dividend: Comp; Divisor: Integer): Integer;
- asm
- MOV ECX,EDX
- MOV EDX,[EAX].Integer[4]
- MOV EAX,[EAX].Integer[0]
- DIV ECX
- end;
-
- function CompMod(var Dividend: Comp; Divisor: Integer): Integer;
- asm
- MOV ECX,EDX
- MOV EDX,[EAX].Integer[4]
- MOV EAX,[EAX].Integer[0]
- DIV ECX
- MOV EAX,EDX
- end;
-
- function BCDToCurr(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 CurrToBCD(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;
-
- { TIndexDef }
-
- constructor TIndexDef.Create(Owner: TIndexDefs; const Name, Fields: string;
- Options: TIndexOptions);
- begin
- if Owner <> nil then
- begin
- Owner.FItems.Add(Self);
- Owner.FUpdated := False;
- FOwner := Owner;
- end;
- FName := Name;
- FFields := Fields;
- FOptions := Options;
- end;
-
- destructor TIndexDef.Destroy;
- begin
- if FOwner <> nil then
- begin
- FOwner.FItems.Remove(Self);
- FOwner.FUpdated := False;
- end;
- end;
-
- function TIndexDef.GetExpression: string;
- begin
- if ixExpression in Options then Result := FFields else Result := '';
- end;
-
- function TIndexDef.GetFields: string;
- begin
- if ixExpression in Options then Result := '' else Result := FFields;
- end;
-
- { TIndexDefs }
-
- constructor TIndexDefs.Create(Table: TTable);
- begin
- FTable := Table;
- FItems := TList.Create;
- end;
-
- destructor TIndexDefs.Destroy;
- begin
- if FItems <> nil then Clear;
- FItems.Free;
- end;
-
- procedure TIndexDefs.Add(const Name, Fields: string;
- Options: TIndexOptions);
- begin
- if IndexOf(Name) >= 0 then DBErrorFmt(SDuplicateIndexName, [Name]);
- TIndexDef.Create(Self, Name, Fields, Options);
- end;
-
- procedure TIndexDefs.Assign(IndexDefs: TIndexDefs);
- var
- I: Integer;
- begin
- Clear;
- for I := 0 to IndexDefs.Count - 1 do
- with IndexDefs[I] do Add(Name, Fields, Options);
- end;
-
- procedure TIndexDefs.Clear;
- begin
- while FItems.Count > 0 do TIndexDef(FItems.Last).Free;
- end;
-
- function TIndexDefs.FindIndexForFields(const Fields: string): TIndexDef;
- begin
- Result := GetIndexForFields(Fields, False);
- if Result = nil then
- DBErrorFmt(SNoIndexForFields, [FTable.TableName, Fields]);
- end;
-
- function TIndexDefs.GetCount: Integer;
- begin
- Result := FItems.Count;
- end;
-
- function TIndexDefs.GetIndexForFields(const Fields: string;
- CaseInsensitive: Boolean): TIndexDef;
- var
- Exact: Boolean;
- I, L: Integer;
- begin
- Update;
- L := Length(Fields);
- Exact := True;
- while True do
- begin
- for I := 0 to FItems.Count - 1 do
- begin
- Result := FItems[I];
- if (Result.FOptions * [ixDescending, ixExpression] = []) and
- (not CaseInsensitive or (ixCaseInsensitive in Result.FOptions)) then
- if Exact then
- begin
- if AnsiCompareText(Fields, Result.Fields) = 0 then Exit;
- end
- else begin
- if (AnsiCompareText(Fields, Copy(Result.Fields, 1, L)) = 0) and
- ((Length(Result.FFields) = L) or
- (Result.FFields[L + 1] = ';')) then Exit;
- end;
- end;
- if not Exact then Break;
- Exact := False;
- end;
- Result := nil;
- end;
-
- function TIndexDefs.GetItem(Index: Integer): TIndexDef;
- begin
- Result := FItems[Index];
- end;
-
- function TIndexDefs.IndexOf(const Name: string): Integer;
- begin
- for Result := 0 to FItems.Count - 1 do
- if AnsiCompareText(TIndexDef(FItems[Result]).FName, Name) = 0 then Exit;
- Result := -1;
- end;
-
- procedure TIndexDefs.Update;
- begin
- FTable.UpdateIndexDefs;
- end;
-
- { TBatchMove }
-
- constructor TBatchMove.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FAbortOnKeyViol := True;
- FAbortOnProblem := True;
- FTransliterate := True;
- FMappings := TStringList.Create;
- end;
-
- destructor TBatchMove.Destroy;
- begin
- FMappings.Free;
- inherited Destroy;
- end;
-
- function TBatchMove.ConvertName(const Name: string; Buffer: PChar): PChar;
- begin
- if Name <> '' then
- Result := AnsiToNative(Destination.DBLocale, Name, Buffer, 255) else
- Result := nil;
- end;
-
- procedure TBatchMove.Execute;
- type
- PFieldMap = ^TFieldMap;
- TFieldMap = array[1..1024] of Word;
- var
- SourceActive, DestinationActive: Boolean;
- BatchMode: TBatchMode;
- I: Integer;
- FieldCount: Word;
- FieldMap: PFieldMap;
- DestName, SourceName: string;
- SKeyViolName, SProblemName, SChangedName: DBITBLNAME;
-
- procedure GetMappingNames;
- var
- P: Integer;
- Mapping: string;
- begin
- Mapping := FMappings[I];
- P := Pos('=', Mapping);
- if P > 0 then
- begin
- DestName := Copy(Mapping, 1, P - 1);
- SourceName := Copy(Mapping, P + 1, 255);
- end else
- begin
- DestName := Mapping;
- SourceName := Mapping;
- end;
- end;
-
- begin
- if (Destination = nil) or (Source = nil) or (Destination = Source) then
- DBError(SInvalidBatchMove);
- SourceActive := Source.Active;
- DestinationActive := Destination.Active;
- FieldCount := 0;
- FieldMap := nil;
- try
- Source.DisableControls;
- Destination.DisableControls;
- Source.Open;
- Source.CheckBrowseMode;
- Source.UpdateCursorPos;
- BatchMode := FMode;
- if BatchMode = batCopy then
- begin
- Destination.Close;
- if FMappings.Count = 0 then
- Destination.FieldDefs := Source.FieldDefs
- else
- begin
- Destination.FieldDefs.Clear;
- for I := 0 to FMappings.Count - 1 do
- begin
- GetMappingNames;
- with Source.FieldDefs.Find(SourceName) do
- Destination.FieldDefs.Add(DestName, DataType, Size, Required);
- end;
- end;
- Destination.IndexDefs.Clear;
- Destination.CreateTable;
- BatchMode := batAppend;
- end;
- Destination.Open;
- Destination.CheckBrowseMode;
- if FMappings.Count <> 0 then
- begin
- FieldCount := Destination.FieldDefs.Count;
- FieldMap := AllocMem(FieldCount * SizeOf(Word));
- for I := 0 to FMappings.Count - 1 do
- begin
- GetMappingNames;
- FieldMap^[Destination.FieldDefs.Find(DestName).FieldNo] :=
- Source.FieldDefs.Find(SourceName).FieldNo;
- end;
- end;
- if FRecordCount > 0 then
- begin
- Source.UpdateCursorPos;
- FMovedCount := FRecordCount;
- end else
- begin
- Check(DbiSetToBegin(Source.Handle));
- FMovedCount := MaxLongint;
- end;
- Source.CursorPosChanged;
- try
- if CommitCount > 0 then
- Check(DbiSetProp(hDBIObj(Destination.DBHandle), dbBATCHCOUNT, CommitCount));
- Check(DbiBatchMove(nil, Source.Handle, nil, Destination.Handle,
- EBATMode(BatchMode), FieldCount, PWord(FieldMap), nil, nil, 0,
- ConvertName(FKeyViolTableName, SKeyViolName),
- ConvertName(FProblemTableName, SProblemName),
- ConvertName(FChangedTableName, SChangedName),
- @FProblemCount, @FKeyViolCount, @FChangedCount,
- FAbortOnProblem, FAbortOnKeyViol, FMovedCount, FTransliterate));
- finally
- if DestinationActive then Destination.First;
- end;
- finally
- if FieldMap <> nil then FreeMem(FieldMap, FieldCount * SizeOf(Word));
- if not DestinationActive then Destination.Close;
- if not SourceActive then Source.Close;
- Destination.EnableControls;
- Source.EnableControls;
- end;
- end;
-
- procedure TBatchMove.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- inherited Notification(AComponent, Operation);
- if Operation = opRemove then
- begin
- if Destination = AComponent then Destination := nil;
- if Source = AComponent then Source := nil;
- end;
- end;
-
- procedure TBatchMove.SetDesination(Value: TTable);
- begin
- FDestination := Value;
- if Value <> nil then Value.FreeNotification(Self);
- end;
-
- procedure TBatchMove.SetMappings(Value: TStrings);
- begin
- FMappings.Assign(Value);
- end;
-
- procedure TBatchMove.SetSource(Value: TDataSet);
- begin
- FSource := Value;
- if Value <> nil then Value.FreeNotification(Self);
- end;
-
- { TTableDataLink }
-
- constructor TTableDataLink.Create(Table: TTable);
- begin
- inherited Create;
- FTable := Table;
- FFields := TList.Create;
- end;
-
- destructor TTableDataLink.Destroy;
- begin
- FFields.Free;
- inherited Destroy;
- end;
-
- procedure TTableDataLink.ActiveChanged;
- begin
- FFields.Clear;
- if Active then
- try
- DataSet.GetFieldList(FFields, FFieldNames);
- except
- FFields.Clear;
- raise;
- end;
- if FTable.Active and not (csDestroying in FTable.ComponentState) then
- if Active and (FFields.Count > 0) then
- FTable.MasterChanged else
- FTable.CancelRange;
- end;
-
- procedure TTableDataLink.CheckBrowseMode;
- begin
- if FTable.Active then FTable.CheckBrowseMode;
- end;
-
- procedure TTableDataLink.LayoutChanged;
- begin
- ActiveChanged;
- end;
-
- procedure TTableDataLink.RecordChanged(Field: TField);
- begin
- if (DataSource.State <> dsSetKey) and FTable.Active and
- (FFields.Count > 0) and ((Field = nil) or
- (FFields.IndexOf(Field) >= 0)) then
- FTable.MasterChanged;
- end;
-
- procedure TTableDataLink.SetFieldNames(const Value: string);
- begin
- if FFieldNames <> Value then
- begin
- FFieldNames := Value;
- ActiveChanged;
- end;
- end;
-
- { TIndexFiles }
-
- constructor TIndexFiles.Create(AOwner: TTable);
- begin
- inherited Create;
- FOwner := AOwner;
- end;
-
- function TIndexFiles.Add(const S: string): Integer;
- begin
- Result := inherited Add(S);
- with FOwner do
- begin
- if Active then OpenIndexFile(S);
- FIndexDefs.FUpdated := False;
- end;
- end;
-
- procedure TIndexFiles.Clear;
- var
- I: Integer;
- begin
- with FOwner do
- if Active then
- for I := 0 to Count - 1 do CloseIndexFile(Strings[I]);
- inherited Clear;
- end;
-
- procedure TIndexFiles.Insert(Index: Integer; const S: string);
- begin
- inherited Insert(Index, S);
- with FOwner do
- begin
- if Active then OpenIndexFile(S);
- FIndexDefs.FUpdated := False;
- end;
- end;
-
- procedure TIndexFiles.Delete(Index: Integer);
- begin
- with FOwner do
- begin
- if Active then CloseIndexFile(Strings[Index]);
- FIndexDefs.FUpdated := False;
- end;
- inherited Delete(Index);
- end;
-
- { TTable }
-
- constructor TTable.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FIndexDefs := TIndexDefs.Create(Self);
- FDataLink := TTableDataLink.Create(Self);
- FIndexFiles := TIndexFiles.Create(Self);
- end;
-
- destructor TTable.Destroy;
- begin
- FIndexFiles.Free;
- FDataLink.Free;
- FIndexDefs.Free;
- inherited Destroy;
- end;
-
- procedure TTable.AddIndex(const Name, Fields: string;
- Options: TIndexOptions);
- var
- STableName: array[0..DBIMAXTBLNAMELEN - 1] of Char;
- IndexDesc: IDXDesc;
- OldLocale, CursorLocale: TLocale;
- LName: string;
- begin
- CursorLocale := nil;
- FieldDefs.Update;
- if Active then
- begin
- EncodeIndexDesc(IndexDesc, Name, Fields, Options);
- CheckBrowseMode;
- CursorPosChanged;
- Check(DbiAddIndex(DBHandle, Handle, nil, nil, IndexDesc, nil));
- end
- else begin
- LName := GetLanguageDriverName;
- if (LName <> '') and (OsLdLoadBySymbName(PChar(LName), CursorLocale) = 0) then
- begin
- OldLocale := Locale;
- SetLocale(CursorLocale);
- end;
- try
- EncodeIndexDesc(IndexDesc, Name, Fields, Options);
- SetDBFlag(dbfTable, True);
- try
- Check(DbiAddIndex(DBHandle, nil, AnsiToNative(DBLocale, TableName,
- STableName, SizeOf(STableName) - 1), GetTableTypeName,
- IndexDesc, nil));
- finally
- SetDBFlag(dbfTable, False);
- end;
- finally
- if CursorLocale <> nil then
- begin
- OsLdUnloadObj(CursorLocale);
- SetLocale(OldLocale);
- end;
- end;
- end;
- FIndexDefs.FUpdated := False;
- end;
-
- procedure TTable.ApplyRange;
- begin
- CheckBrowseMode;
- if SetCursorRange then First;
- end;
-
- function TTable.BatchMove(ASource: TDataSet; AMode: TBatchMode): Longint;
- begin
- with TBatchMove.Create(nil) do
- try
- Destination := Self;
- Source := ASource;
- Mode := AMode;
- Execute;
- Result := MovedCount;
- finally
- Free;
- end;
- end;
-
- procedure TTable.CancelRange;
- begin
- CheckBrowseMode;
- UpdateCursorPos;
- if ResetCursorRange then Resync([]);
- end;
-
- function TTable.GetCanModify: Boolean;
- begin
- Result := inherited GetCanModify and not ReadOnly;
- end;
-
- function TTable.GetHandle(const IndexName, IndexTag: string): HDBICur;
- const
- OpenModes: array[Boolean] of DbiOpenMode = (dbiReadWrite, dbiReadOnly);
- ShareModes: array[Boolean] of DbiShareMode = (dbiOpenShared, dbiOpenExcl);
- var
- STableName: array[0..DBIMAXTBLNAMELEN - 1] of Char;
- SIndexName: array[0..DBIMAXTBLNAMELEN - 1] of Char;
- OpenMode: DbiOpenMode;
- RetCode: DbiResult;
- I: Integer;
- begin
- AnsiToNative(DBLocale, FTableName, STableName, SizeOf(STableName) - 1);
- Result := nil;
- OpenMode := OpenModes[FReadOnly or ForceUpdateCallback];
- while True do
- begin
- RetCode := DbiOpenTable(DBHandle, STableName, GetTableTypeName,
- PChar(IndexName), PChar(IndexTag), 0, OpenMode, ShareModes[FExclusive],
- xltField, False, nil, Result);
- if RetCode = DBIERR_TABLEREADONLY then
- OpenMode := dbiReadOnly
- else if CheckOpen(RetCode) then Break;
- end;
- if IsDBaseTable then
- for I := 0 to IndexFiles.Count - 1 do
- begin
- CharToOem(PChar(IndexFiles[I]), SIndexName);
- CheckIndexOpen(DbiOpenIndex(Result, SIndexName, 0));
- end;
- end;
-
- function TTable.CreateHandle: HDBICur;
- var
- IndexName, IndexTag: string;
- begin
- if FTableName = '' then DBError(SNoTableName);
- GetIndexParams(FIndexName, FFieldsIndex, IndexName, IndexTag);
- if IsProductionIndex(IndexName) then
- Result := GetHandle(IndexName, IndexTag) else
- Result := GetHandle('', '');
- end;
-
- function TTable.GetLanguageDriverName: string;
- const
- Names: array[TTableType] of string =
- (szPARADOX, szPARADOX, szDBASE, szASCII);
- var
- Buffer: array[0..DBIMAXPATHLEN] of char;
- S, DriverName: string;
- Database: TDatabase;
- begin
- Buffer[0] := #0;
- DriverName := '';
- Database := DBSession.OpenDatabase(DatabaseName);
- try
- if Database.IsSQLBased then
- begin
- DriverName := Session.GetAliasDriverName(DatabaseName);
- FmtStr(S, ':%s:%s', [DatabaseName, TableName]);
- AnsiToNative(DBLocale, S, Buffer, SizeOf(Buffer) - 1);
- end
- else begin
- AnsiToNative(DBLocale, TableName, Buffer, SizeOf(Buffer) - 1);
- DbiFormFullName(Database.Handle, Buffer, nil, Buffer);
- if (TableType <> ttDefault) or
- (ExtractFileExt(TableName) = '') then
- DriverName := Names[TableType]
- else if IsDBaseTable then
- DriverName := szDBASE else
- DriverName := szPARADOX;
- end;
- if DbiGetLdName(PChar(DriverName), @Buffer, @Buffer) <> 0 then
- Buffer := #0;
- finally
- Session.CloseDatabase(Database);
- end;
- Result := Buffer;
- end;
-
- procedure TTable.CreateTable;
- var
- I: Integer;
- FieldDescs: PFLDDesc;
- ValCheckPtr: PVCHKDesc;
- DriverTypeName: DBINAME;
- TableDesc: CRTblDesc;
- TempLocale, OldLocale: TLocale;
- LName: string;
- SQLLName: DBIName;
- PSQLLName: PChar;
-
- function GetStandardLanguageDriver: string;
- var
- DriverName: string;
- Buffer: array[0..DBIMAXNAMELEN - 1] of char;
- begin
- if not Database.IsSQLBased then
- begin
- DriverName := GetTableTypeName;
- if DriverName = '' then
- if IsDBaseTable then
- DriverName := szDBASE else
- DriverName := szPARADOX;
- if DbiGetLdName(PChar(DriverName), nil, Buffer) = 0 then
- Result := Buffer;
- end
- else Result := '';
- end;
-
- begin
- CheckInactive;
- if FieldDefs.Count = 0 then
- for I := 0 to FieldCount - 1 do
- with Fields[I] do
- if FieldKind = fkData then
- FieldDefs.Add(FieldName, DataType, Size, Required);
- FieldDescs := nil;
- FillChar(TableDesc, SizeOf(TableDesc), 0);
- with TableDesc do
- begin
- SetDBFlag(dbfTable, True);
- try
- AnsiToNative(Locale, TableName, szTblName, SizeOf(szTblName) - 1);
- if GetTableTypeName <> nil then
- StrCopy(szTblType, GetTableTypeName);
- iFldCount := FieldDefs.Count;
- FieldDescs := AllocMem(iFldCount * SizeOf(FLDDesc));
- TempLocale := nil;
- LName := GetStandardLanguageDriver;
- if (LName <> '') and (OsLdLoadBySymbName(PChar(LName), TempLocale) = 0) then
- begin
- OldLocale := Locale;
- SetLocale(TempLocale);
- end;
- try
- for I := 0 to FieldDefs.Count - 1 do
- with FieldDefs[I] do
- begin
- EncodeFieldDesc(PFieldDescList(FieldDescs)^[I], Name,
- DataType, Size);
- if Required then Inc(iValChkCount);
- end;
- finally
- if TempLocale <> nil then
- begin
- OsLdUnloadObj(TempLocale);
- SetLocale(OldLocale);
- end;
- end;
- pFldDesc := AllocMem(iFldCount * SizeOf(FLDDesc));
- PSQLLName := nil;
- if Database.IsSQLBased then
- if DbiGetLdNameFromDB(DBHandle, nil, SQLLName) = 0 then
- PSQLLName := SQLLName;
- Check(DbiTranslateRecordStructure(nil, iFldCount, FieldDescs,
- GetDriverTypeName(DriverTypeName), PSQLLName, pFLDDesc, False));
- iIdxCount := IndexDefs.Count;
- pIdxDesc := AllocMem(iIdxCount * SizeOf(IDXDesc));
- for I := 0 to IndexDefs.Count - 1 do
- with IndexDefs[I] do
- EncodeIndexDesc(PIndexDescList(pIdxDesc)^[I], Name, Fields,
- Options);
- if iValChkCount <> 0 then
- begin
- pVChkDesc := AllocMem(iValChkCount * SizeOf(VCHKDesc));
- ValCheckPtr := pVChkDesc;
- for I := 0 to FieldDefs.Count - 1 do
- if FieldDefs[I].Required then
- begin
- ValCheckPtr^.iFldNum := I + 1;
- ValCheckPtr^.bRequired := True;
- Inc(ValCheckPtr);
- end;
- end;
- Check(DbiCreateTable(DBHandle, True, TableDesc));
- finally
- if pVChkDesc <> nil then FreeMem(pVChkDesc, iValChkCount * SizeOf(VCHKDesc));
- if pIdxDesc <> nil then FreeMem(pIdxDesc, iIdxCount * SizeOf(IDXDesc));
- if pFldDesc <> nil then FreeMem(pFldDesc, iFldCount * SizeOf(FLDDesc));
- if FieldDescs <> nil then FreeMem(FieldDescs, iFldCount * SizeOf(FLDDesc));
- SetDBFlag(dbfTable, False);
- end;
- end;
- end;
-
- procedure TTable.DataEvent(Event: TDataEvent; Info: Longint);
- begin
- if Event = dePropertyChange then FIndexDefs.FUpdated := False;
- inherited DataEvent(Event, Info);
- end;
-
- procedure TTable.DecodeIndexDesc(const IndexDesc: IDXDesc;
- var Source, Name, Fields: string; var Options: TIndexOptions);
- var
- IndexOptions: TIndexOptions;
- I: Integer;
- SSource, SName: PChar;
- begin
- with IndexDesc do
- begin
- if szTagName[0] = #0 then
- begin
- SName := szName;
- Source := '';
- end
- else begin
- SSource := szName;
- SName := szTagName;
- NativeToAnsi(nil, SSource, Source);
- end;
- NativeToAnsi(Locale, SName, Name);
- Name := ExtractFileName(Name);
- Source := ExtractFileName(Source);
- IndexOptions := [];
- if bPrimary then Include(IndexOptions, ixPrimary);
- if bUnique then Include(IndexOptions, ixUnique);
- if bDescending then Include(IndexOptions, ixDescending);
- if bCaseInsensitive then Include(IndexOptions, ixCaseInsensitive);
- if bExpIdx then
- begin
- Include(IndexOptions, ixExpression);
- NativeToAnsi(Locale, szKeyExp, Fields);
- end else
- begin
- Fields := '';
- for I := 0 to iFldsInKey - 1 do
- begin
- if I <> 0 then Fields := Fields + ';';
- Fields := Fields + FieldDefs[aiKeyFld[I] - 1].Name;
- end;
- end;
- Options := IndexOptions;
- end;
- end;
-
- procedure TTable.DeleteIndex(const Name: string);
- var
- STableName: array[0..DBIMAXTBLNAMELEN - 1] of Char;
- IndexName, IndexTag: string;
- OldLocale, CursorLocale: TLocale;
- LName: string;
- begin
- if Active then
- begin
- GetIndexParams(Name, False, IndexName, IndexTag);
- CheckBrowseMode;
- Check(DbiDeleteIndex(DBHandle, Handle, nil, nil, PChar(IndexName),
- PChar(IndexTag), 0));
- end
- else begin
- CursorLocale := nil;
- LName := GetLanguageDriverName;
- if (LName <> '') and (OsLdLoadBySymbName(PChar(LName), CursorLocale) = 0) then
- begin
- OldLocale := Locale;
- SetLocale(CursorLocale);
- end;
- try
- GetIndexParams(Name, False, IndexName, IndexTag);
- SetDBFlag(dbfTable, True);
- try
- Check(DbiDeleteIndex(DBHandle, nil, AnsiToNative(DBLocale, TableName,
- STableName, SizeOf(STableName) - 1), GetTableTypeName,
- PChar(IndexName), PChar(IndexTag), 0));
- finally
- SetDBFlag(dbfTable, False);
- end;
- finally
- if CursorLocale <> nil then
- begin
- OsLdUnloadObj(CursorLocale);
- SetLocale(OldLocale);
- end;
- end;
- end;
- FIndexDefs.FUpdated := False;
- end;
-
- procedure TTable.DeleteTable;
- var
- STableName: array[0..DBIMAXTBLNAMELEN - 1] of Char;
- begin
- CheckInactive;
- SetDBFlag(dbfTable, True);
- try
- Check(DbiDeleteTable(DBHandle, AnsiToNative(DBLocale, TableName,
- STableName, SizeOf(STableName) - 1), GetTableTypeName));
- finally
- SetDBFlag(dbfTable, False);
- end;
- end;
-
- procedure TTable.DestroyHandle;
- begin
- DestroyLookupCursor;
- inherited DestroyHandle;
- end;
-
- procedure TTable.DestroyLookupCursor;
- begin
- if FLookupHandle <> nil then
- begin
- DbiCloseCursor(FLookupHandle);
- FLookupHandle := nil;
- FLookupKeyFields := '';
- end;
- end;
-
- procedure TTable.DoOnNewRecord;
- var
- I: Integer;
- begin
- if FDataLink.Active and (FDataLink.FFields.Count > 0) then
- for I := 0 to FDataLink.FFields.Count - 1 do
- IndexFields[I] := TField(FDataLink.FFields[I]);
- inherited DoOnNewRecord;
- end;
-
- procedure TTable.EditKey;
- begin
- SetKeyBuffer(kiLookup, False);
- end;
-
- procedure TTable.EditRangeEnd;
- begin
- SetKeyBuffer(kiRangeEnd, False);
- end;
-
- procedure TTable.EditRangeStart;
- begin
- SetKeyBuffer(kiRangeStart, False);
- end;
-
- procedure TTable.EmptyTable;
- var
- STableName: array[0..DBIMAXTBLNAMELEN - 1] of Char;
- begin
- if Active then
- begin
- CheckBrowseMode;
- Check(DbiEmptyTable(DBHandle, Handle, nil, nil));
- ClearBuffers;
- DataEvent(deDataSetChange, 0);
- end else
- begin
- SetDBFlag(dbfTable, True);
- try
- Check(DbiEmptyTable(DBHandle, nil, AnsiToNative(DBLocale, TableName,
- STableName, SizeOf(STableName) - 1), GetTableTypeName));
- finally
- SetDBFlag(dbfTable, False);
- end;
- end;
- end;
-
- procedure TTable.EncodeFieldDesc(var FieldDesc: FLDDesc;
- const Name: string; DataType: TFieldType; Size: Word);
- const
- TypeMap: array[TFieldType] of Word = (
- fldUNKNOWN, fldZSTRING, fldINT16, fldINT32, fldUINT16, fldBOOL,
- fldFLOAT, fldFLOAT, fldBCD, fldDATE, fldTIME, fldTIMESTAMP, fldBYTES,
- fldVARBYTES, fldINT32, fldBLOB, fldBLOB, fldBLOB, fldBLOB, fldBLOB,
- fldBLOB, fldBLOB);
- SubTypeMap: 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);
- begin
- with FieldDesc do
- begin
- AnsiToNative(Locale, Name, szName, SizeOf(szName) - 1);
- iFldType := TypeMap[DataType];
- iSubType := SubTypeMap[DataType];
- case DataType of
- ftString, ftBytes, ftVarBytes, ftBlob, ftMemo, ftGraphic,
- ftFmtMemo, ftParadoxOle, ftDBaseOle, ftTypedBinary:
- iUnits1 := Size;
- ftBCD:
- begin
- iUnits1 := 32;
- iUnits2 := Size;
- end;
- end;
- end;
- end;
-
- procedure TTable.EncodeIndexDesc(var IndexDesc: IDXDesc;
- const Name, Fields: string; Options: TIndexOptions);
- var
- Pos: Integer;
- begin
- FillChar(IndexDesc, SizeOf(IndexDesc), 0);
- with IndexDesc do
- begin
- if IsDBaseTable then
- AnsiToNative(Locale, Name, szTagName, SizeOf(szTagName) - 1)
- else
- AnsiToNative(Locale, Name, szName, SizeOf(szName) - 1);
- bPrimary := ixPrimary in Options;
- bUnique := ixUnique in Options;
- bDescending := ixDescending in Options;
- bMaintained := True;
- bCaseInsensitive := ixCaseInsensitive in Options;
- if ixExpression in Options then
- begin
- bExpIdx := True;
- AnsiToNative(Locale, Fields, szKeyExp, SizeOf(szKeyExp) - 1);
- end else
- begin
- Pos := 1;
- while (Pos <= Length(Fields)) and (iFldsInKey < 16) do
- begin
- aiKeyFld[iFldsInKey] :=
- FieldDefs.Find(ExtractFieldName(Fields, Pos)).FieldNo;
- Inc(iFldsInKey);
- end;
- end;
- end;
- end;
-
- function TTable.FindKey(const KeyValues: array of const): Boolean;
- begin
- CheckBrowseMode;
- SetKeyFields(kiLookup, KeyValues);
- Result := GotoKey;
- end;
-
- procedure TTable.FindNearest(const KeyValues: array of const);
- begin
- CheckBrowseMode;
- SetKeyFields(kiLookup, KeyValues);
- GotoNearest;
- end;
-
- function TTable.GetDataSource: TDataSource;
- begin
- Result := FDataLink.DataSource;
- end;
-
- function TTable.GetDriverTypeName(Buffer: PChar): PChar;
- var
- Length: Word;
- begin
- Result := Buffer;
- Check(DbiGetProp(HDBIOBJ(DBHandle), dbDATABASETYPE, Buffer,
- SizeOf(DBINAME), Length));
- if StrIComp(Buffer, 'STANDARD') = 0 then
- begin
- Result := GetTableTypeName;
- if Result <> nil then Result := StrCopy(Buffer, Result);
- end;
- end;
-
- function TTable.GetIndexFieldNames: string;
- begin
- if FFieldsIndex then Result := FIndexName else Result := '';
- end;
-
- function TTable.GetIndexName: string;
- begin
- if FFieldsIndex then Result := '' else Result := FIndexName;
- end;
-
- procedure TTable.GetIndexNames(List: TStrings);
- var
- I: Integer;
- begin
- UpdateIndexDefs;
- for I := 0 to FIndexDefs.Count - 1 do
- with FIndexDefs[I] do
- if Name <> '' then List.Add(Name);
- end;
-
- procedure TTable.GetIndexParams(const IndexName: string;
- FieldsIndex: Boolean; var IndexedName, IndexTag: string);
- var
- I: Integer;
- IndexStr: TIndexName;
- SIndexName: array[0..127] of Char;
- SIndexTag: array[0..DBIMAXNAMELEN - 1] of Char;
- OldLocale, CursorLocale: TLocale;
- LName: string;
- begin
- SIndexName[0] := #0;
- SIndexTag[0] := #0;
- if (IndexName <> '') and not InfoQueryMode then
- begin
- UpdateIndexDefs;
- IndexStr := IndexName;
- CursorLocale := nil;
- if not Active then LName := GetLanguageDriverName;
- if (LName <> '') and (OsLdLoadBySymbName(PChar(LName), CursorLocale) = 0) then
- begin
- OldLocale := Locale;
- SetLocale(CursorLocale);
- end;
- try
- if FieldsIndex then
- if Database.IsSQLBased then
- begin
- for I := 1 to Length(IndexStr) do
- if IndexStr[I] = ';' then IndexStr[I] := '@';
- IndexStr := '@' + IndexStr;
- end else
- IndexStr := IndexDefs.FindIndexForFields(IndexName).Name;
- if IsDBaseTable then
- begin
- if UpperCase(ExtractFileExt(IndexStr)) <> '.NDX' then
- begin
- AnsiToNative(Locale, IndexStr, SIndexTag, SizeOf(SIndexTag) - 1);
- with IndexDefs do
- begin
- I := IndexOf(IndexStr);
- if I <> -1 then
- IndexStr := Items[I].Source else
- DBErrorFmt(SIndexDoesNotExist, [IndexName]);
- AnsiToNative(nil, IndexStr, SIndexName, SizeOf(SIndexName) - 1);
- end;
- end;
- end else
- AnsiToNative(Locale, IndexStr, SIndexName, SizeOf(SIndexName) - 1);
- finally
- if CursorLocale <> nil then
- begin
- OsLdUnloadObj(CursorLocale);
- SetLocale(OldLocale);
- end;
- end;
- end;
- IndexedName := SIndexName;
- IndexTag := SIndexTag;
- end;
-
- function TTable.GetLookupCursor(const KeyFields: string;
- CaseInsensitive: Boolean): HDBICur;
- var
- FLookupFldLen: Integer;
- IndexFound, FieldsIndex: Boolean;
- KeyIndexName, IndexName, IndexTag: string;
- KeyIndex: TIndexDef;
- begin
- FLookupFldLen := Length(FLookupKeyFields);
- if (FLookupFldLen = 0) or
- (StrComp(PChar(FLookupKeyFields), PChar(KeyFields)) <> 0) or
- (FLookupKeyFields[FLookupFldLen] <> Char(CaseInsensitive)) then
- begin
- DestroyLookupCursor;
- IndexFound := False;
- if Database.IsSQLBased then
- begin
- if not CaseInsensitive then
- begin
- KeyIndexName := KeyFields;
- FieldsIndex := True;
- IndexFound := True;
- end;
- end else
- begin
- KeyIndex := IndexDefs.GetIndexForFields(KeyFields, CaseInsensitive);
- if KeyIndex <> nil then
- begin
- KeyIndexName := KeyIndex.Name;
- FieldsIndex := False;
- IndexFound := True;
- end;
- end;
- if IndexFound then
- begin
- Check(DbiCloneCursor(Handle, True, False, FLookupHandle));
- GetIndexParams(KeyIndexName, FieldsIndex, IndexName, IndexTag);
- Check(DbiSwitchToIndex(FLookupHandle, PChar(IndexName),
- PChar(IndexTag), 0, False));
- end;
- FLookupKeyFields := Format('%s'#0'%s', [KeyFields, Char(CaseInsensitive)]);
- end;
- Result := FLookupHandle;
- end;
-
- function TTable.GetMasterFields: string;
- begin
- Result := FDataLink.FFieldNames;
- end;
-
- function TTable.GetTableTypeName: PChar;
- const
- Names: array[TTableType] of PChar =
- (szPARADOX, szPARADOX, szDBASE, szASCII);
- var
- TableType: TTableType;
- Extension: string;
- begin
- Result := nil;
- if not Database.IsSQLBased then
- begin
- TableType := FTableType;
- if TableType = ttDefault then
- begin
- Extension := ExtractFileExt(FTableName);
- if CompareText(Extension, '.DBF') = 0 then TableType := ttDBase;
- if CompareText(Extension, '.TXT') = 0 then TableType := ttASCII;
- end;
- Result := Names[TableType];
- end;
- end;
-
- procedure TTable.GotoCurrent(Table: TTable);
- begin
- CheckBrowseMode;
- Table.CheckBrowseMode;
- if (AnsiCompareText(DatabaseName, Table.DatabaseName) <> 0) or
- (AnsiCompareText(TableName, Table.TableName) <> 0) then
- DBError(STableMismatch);
- Table.UpdateCursorPos;
- Check(DbiSetToCursor(Handle, Table.Handle));
- Resync([rmExact, rmCenter]);
- end;
-
- function TTable.GotoKey: Boolean;
- var
- KeyBuffer: PKeyBuffer;
- IndexBuffer, RecBuffer: PChar;
- UseKey: Boolean;
- begin
- CheckBrowseMode;
- CursorPosChanged;
- KeyBuffer := GetKeyBuffer(kiLookup);
- IndexBuffer := AllocMem(KeySize);
- try
- RecBuffer := PChar(KeyBuffer) + SizeOf(TKeyBuffer);
- UseKey := DbiExtractKey(Handle, RecBuffer, IndexBuffer) = 0;
- if UseKey then RecBuffer := IndexBuffer;
- Result := DbiGetRecordForKey(Handle, UseKey, KeyBuffer^.FieldCount, 0,
- RecBuffer, nil) = 0;
- if Result then Resync([rmExact, rmCenter]);
- finally
- FreeMem(IndexBuffer, KeySize);
- end;
- end;
-
- procedure TTable.GotoNearest;
- var
- SearchCond: DBISearchCond;
- KeyBuffer: PKeyBuffer;
- IndexBuffer, RecBuffer: PChar;
- UseKey: Boolean;
- begin
- CheckBrowseMode;
- CursorPosChanged;
- KeyBuffer := GetKeyBuffer(kiLookup);
- if KeyBuffer^.Exclusive then
- SearchCond := keySEARCHGT else
- SearchCond := keySEARCHGEQ;
- IndexBuffer := AllocMem(KeySize);
- try
- RecBuffer := PChar(KeyBuffer) + SizeOf(TKeyBuffer);
- UseKey := DbiExtractKey(Handle, RecBuffer, IndexBuffer) = 0;
- if UseKey then RecBuffer := IndexBuffer;
- Check(DbiSetToKey(Handle, SearchCond, UseKey, KeyBuffer^.FieldCount, 0,
- RecBuffer));
- Resync([rmCenter]);
- finally
- FreeMem(IndexBuffer, KeySize);
- end;
- end;
-
- procedure TTable.InitFieldDefs;
- var
- FieldNo: Word;
- FCursor, VCursor: HDBICur;
- RequiredFields: set of 0..255;
- STableName: array[0..DBIMAXTBLNAMELEN - 1] of Char;
- FieldDesc: FLDDesc;
- ValCheckDesc: VCHKDesc;
- OldLocale, CursorLocale: TLocale;
- LName: string;
- begin
- CursorLocale := nil;
- SetDBFlag(dbfFieldList, True);
- try
- if FTableName = '' then DBError(SNoTableName);
- AnsiToNative(DBLocale, TableName, STableName, SizeOf(STableName) - 1);
- RequiredFields := [];
- if not Active then LName := GetLanguageDriverName;
- if (LName <> '') and (OsLdLoadBySymbName(PChar(LName), CursorLocale) = 0) then
- begin
- OldLocale := Locale;
- SetLocale(CursorLocale);
- end;
- try
- while not CheckOpen(DbiOpenFieldList(DBHandle, STableName,
- GetTableTypeName, False, FCursor)) do {Retry};
- try
- if DbiOpenVChkList(DBHandle, STableName, GetTableTypeName,
- VCursor) = 0 then
- begin
- while DbiGetNextRecord(VCursor, dbiNoLock, @ValCheckDesc, nil) = 0 do
- if ValCheckDesc.bRequired then
- Include(RequiredFields, ValCheckDesc.iFldNum - 1);
- DbiCloseCursor(VCursor);
- end;
- FieldNo := 0;
- FieldDefs.Clear;
- while DbiGetNextRecord(FCursor, dbiNoLock, @FieldDesc, nil) = 0 do
- begin
- FieldDefs.AddFieldDesc(FieldDesc, FieldNo in RequiredFields,
- FieldNo + 1);
- Inc(FieldNo);
- end;
- finally
- DbiCloseCursor(FCursor);
- end;
- finally
- if CursorLocale <> nil then
- begin
- OsLdUnloadObj(CursorLocale);
- SetLocale(OldLocale);
- end;
- end;
- finally
- SetDBFlag(dbfFieldList, False);
- end;
- end;
-
- function TTable.IsDBaseTable: Boolean;
- begin
- Result := (FTableType = ttDBase) or
- (CompareText(ExtractFileExt(TableName), '.DBF') = 0);
- end;
-
- function TTable.IsProductionIndex(const IndexName: string): Boolean;
- begin
- Result := True;
- if IsDBaseTable and (IndexName <> '') then
- if AnsiUpperCase(ExtractFileExt(IndexName)) = '.NDX' then
- Result := False
- else Result := AnsiUpperCase(ChangeFileExt(TableName, '')) =
- AnsiUpperCase(ChangeFileExt(IndexName, ''));
- end;
-
- procedure TTable.LockTable(LockType: TLockType);
- begin
- SetTableLock(LockType, True);
- end;
-
- procedure TTable.MasterChanged;
- begin
- CheckBrowseMode;
- UpdateRange;
- ApplyRange;
- end;
-
- procedure TTable.PrepareCursor;
- var
- IndexName, IndexTag: string;
- begin
- GetIndexParams(FIndexName, FFieldsIndex, IndexName, IndexTag);
- if not IsProductionIndex(IndexName) then SwitchToIndex(IndexName, IndexTag);
- if FDataLink.Active and (FDataLink.FFields.Count > 0) then
- begin
- UpdateRange;
- SetCursorRange;
- end;
- end;
-
- procedure TTable.RenameTable(const NewTableName: string);
- var
- SCurTableName: array[0..DBIMAXTBLNAMELEN - 1] of Char;
- SNewTableName: array[0..DBIMAXTBLNAMELEN - 1] of Char;
- begin
- CheckInactive;
- SetDBFlag(dbfTable, True);
- try
- Check(DbiRenameTable(DBHandle, AnsiToNative(DBLocale, TableName,
- SCurTableName, SizeOf(SCurTableName) - 1), GetTableTypeName,
- AnsiToNative(DBLocale, NewTableName, SNewTableName,
- SizeOf(SNewTableName) - 1)));
- finally
- SetDBFlag(dbfTable, False);
- end;
- TableName := NewTableName;
- end;
-
- procedure TTable.SetDataSource(Value: TDataSource);
- begin
- if IsLinkedTo(Value) then DBError(SCircularDataLink);
- FDataLink.DataSource := Value;
- end;
-
- procedure TTable.SetExclusive(Value: Boolean);
- begin
- CheckInactive;
- FExclusive := Value;
- end;
-
- procedure TTable.SetIndex(const Value: string; FieldsIndex: Boolean);
- var
- IndexName, IndexTag: string;
- begin
- if Active then CheckBrowseMode;
- if (FIndexName <> Value) or (FFieldsIndex <> FieldsIndex) then
- begin
- if Active then
- begin
- GetIndexParams(Value, FieldsIndex, IndexName, IndexTag);
- SwitchToIndex(IndexName, IndexTag);
- if FDataLink.Active and (FDataLink.FFields.Count > 0) then
- begin
- UpdateRange;
- SetCursorRange;
- end;
- end;
- FIndexName := Value;
- FFieldsIndex := FieldsIndex;
- if Active then Resync([]);
- end;
- end;
-
- procedure TTable.SetIndexFieldNames(const Value: string);
- begin
- SetIndex(Value, Value <> '');
- end;
-
- procedure TTable.SetIndexName(const Value: string);
- begin
- SetIndex(Value, False);
- end;
-
- procedure TTable.SetIndexFiles(Value: TStrings);
- begin
- FIndexFiles.Assign(Value);
- end;
-
- procedure TTable.SetKey;
- begin
- SetKeyBuffer(kiLookup, True);
- end;
-
- procedure TTable.SetMasterFields(const Value: string);
- begin
- FDataLink.SetFieldNames(Value);
- end;
-
- procedure TTable.SetRange(const StartValues, EndValues: array of const);
- begin
- CheckBrowseMode;
- SetKeyFields(kiRangeStart, StartValues);
- SetKeyFields(kiRangeEnd, EndValues);
- ApplyRange;
- end;
-
- procedure TTable.SetRangeEnd;
- begin
- SetKeyBuffer(kiRangeEnd, True);
- end;
-
- procedure TTable.SetRangeStart;
- begin
- SetKeyBuffer(kiRangeStart, True);
- end;
-
- procedure TTable.SetReadOnly(Value: Boolean);
- begin
- CheckInactive;
- FReadOnly := Value;
- end;
-
- procedure TTable.SetTableLock(LockType: TLockType; Lock: Boolean);
- var
- L: DBILockType;
- begin
- if State = dsInactive then DBError(SDataSetClosed);
- if LockType = ltReadLock then L := dbiREADLOCK else L := dbiWRITELOCK;
- if Lock then
- Check(DbiAcqTableLock(Handle, L)) else
- Check(DbiRelTableLock(Handle, False, L));
- end;
-
- procedure TTable.SetTableName(const Value: TFileName);
- begin
- CheckInactive;
- if not (csReading in ComponentState) and
- (FTableName <> Value) then IndexFiles.Clear;
- FTableName := Value;
- DataEvent(dePropertyChange, 0);
- end;
-
- procedure TTable.SetTableType(Value: TTableType);
- begin
- CheckInactive;
- FTableType := Value;
- end;
-
- procedure TTable.OpenIndexFile(const IndexName: string);
- var
- Buffer: array[0..DBIMAXNAMELEN - 1] of char;
- begin
- CheckIndexOpen(DbiOpenIndex(Handle,
- AnsiToNative(Locale, IndexName, Buffer, SizeOf(Buffer) - 1), 0));
- end;
-
- procedure TTable.CloseIndexFile(const IndexFileName: string);
- var
- IndexName, IndexTag: string;
- Buffer: array[0..DBIMAXNAMELEN - 1] of char;
- begin
- GetIndexParams(FIndexName, FFieldsIndex, IndexName, IndexTag);
- if AnsiUpperCase(IndexName) = AnsiUpperCase(IndexFileName) then
- Self.IndexName := '';
- Check(DbiCloseIndex(Handle,
- AnsiToNative(Locale, IndexFileName, Buffer, SizeOf(Buffer) - 1), 0));
- end;
-
- procedure TTable.UpdateIndexDefs;
- var
- Options: TIndexOptions;
- Name, Source, Fields: string;
- CursorProps: CurProps;
- Cursor: HDBICur;
- IndexBuff: PIndexDescList;
- I: Integer;
- NumIndexes: Word;
- OldLocale, CursorLocale: TLocale;
- begin
- if not FIndexDefs.FUpdated then
- begin
- SetDBFlag(dbfIndexList, True);
- try
- FieldDefs.Update;
- if Handle = nil then
- begin
- Cursor := GetHandle('', '');
- if DbiGetLdObj(Cursor, CursorLocale) = 0 then
- begin
- OldLocale := Locale;
- SetLocale(CursorLocale);
- end;
- end
- else Cursor := Handle;
- try
- DbiGetCursorProps(Cursor, CursorProps);
- NumIndexes := CursorProps.iIndexes;
- IndexBuff := AllocMem(NumIndexes * SizeOf(IDXDesc));
- try
- IndexDefs.Clear;
- DbiGetIndexDescs(Cursor, PIDXDesc(IndexBuff));
- for I := 0 to NumIndexes - 1 do
- begin
- DecodeIndexDesc(IndexBuff^[I], Source, Name, Fields, Options);
- with IndexDefs do
- begin
- Add(Name, Fields, Options);
- if Source <> '' then Items[Count - 1].FSource := Source;
- end;
- end;
- IndexDefs.FUpdated := True;
- finally
- FreeMem(IndexBuff, NumIndexes * SizeOf(IDXDesc));
- end;
- finally
- if (Cursor <> nil) and (Cursor <> Handle) then
- begin
- SetLocale(OldLocale);
- DbiCloseCursor(Cursor);
- end;
- end;
- finally
- SetDBFlag(dbfIndexList, False);
- end;
- end;
- end;
-
- procedure TTable.UpdateRange;
- begin
- SetLinkRanges(FDataLink.FFields);
- end;
-
- procedure TTable.UnlockTable(LockType: TLockType);
- begin
- SetTableLock(LockType, False);
- end;
-
- { TParams }
-
- constructor TParams.Create;
- begin
- FItems := TList.Create;
- end;
-
- destructor TParams.Destroy;
- begin
- Clear;
- FItems.Free;
- inherited Destroy;
- end;
-
- procedure TParams.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- if Source is TParams then
- begin
- Clear;
- for I := 0 to TParams(Source).Count - 1 do
- with TParam.Create(Self, ptUnknown) do
- Assign(TParams(Source)[I]);
- end
- else inherited Assign(Source);
- end;
-
- procedure TParams.AssignTo(Dest: TPersistent);
- begin
- if Dest is TParams then TParams(Dest).Assign(Self)
- else inherited AssignTo(Dest);
- end;
-
- procedure TParams.AssignValues(Value: TParams);
- var
- I, J: Integer;
- begin
- for I := 0 to Count - 1 do
- for J := 0 to Value.Count - 1 do
- if Items[I].Name = Value[J].Name then
- begin
- Items[I].Assign(Value[J]);
- Break;
- end;
- end;
-
- procedure TParams.AddParam(Value: TParam);
- begin
- FItems.Add(Value);
- Value.FParamList := Self;
- end;
-
- procedure TParams.RemoveParam(Value: TParam);
- begin
- FItems.Remove(Value);
- Value.FParamList := nil;
- end;
-
- function TParams.CreateParam(FldType: TFieldType; const ParamName: string;
- ParamType: TParamType): TParam;
- begin
- Result := TParam.Create(Self, ParamType);
- with Result do
- begin
- Name := ParamName;
- DataType := FldType;
- end;
- end;
-
- function TParams.Count: Integer;
- begin
- Result := FItems.Count;
- end;
-
- function TParams.IsEqual(Value: TParams): Boolean;
- var
- I: Integer;
- begin
- Result := Count = Value.Count;
- if Result then
- for I := 0 to Count - 1 do
- begin
- Result := Items[I].IsEqual(Value.Items[I]);
- if not Result then Break;
- end
- end;
-
- procedure TParams.Clear;
- begin
- while FItems.Count > 0 do TParam(FItems.Last).Free;
- end;
-
- function TParams.GetParam(Index: Word): TParam;
- begin
- Result := ParamByName(TParam(FItems[Index]).Name);
- end;
-
- function TParams.ParamByName(const Value: string): TParam;
- var
- I: Integer;
- begin
- for I := 0 to FItems.Count - 1 do
- begin
- Result := FItems[I];
- if AnsiCompareText(Result.Name, Value) = 0 then Exit;
- end;
- DBErrorFmt(SParameterNotFound, [Value]);
- end;
-
- procedure TParams.DefineProperties(Filer: TFiler);
- begin
- inherited DefineProperties(Filer);
- Filer.DefineBinaryProperty('Data', ReadBinaryData, WriteBinaryData, Count > 0);
- end;
-
- procedure TParams.ReadBinaryData(Stream: TStream);
- var
- I, Temp, NumItems: Integer;
- Buffer: array[0..255] of Char;
- TempStr: string;
- Version: Word;
- begin
- Clear;
- with Stream do
- begin
- ReadBuffer(Version, SizeOf(Version));
- if Version > 2 then DBError(SInvalidVersion);
- NumItems := 0;
- if Version = 2 then ReadBuffer(NumItems, SizeOf(NumItems))
- else ReadBuffer(NumItems, 2);
- for I := 0 to NumItems - 1 do
- with TParam.Create(Self, ptUnknown) do
- begin
- Temp := 0;
- if Version = 2 then ReadBuffer(Temp, SizeOf(Temp))
- else ReadBuffer(Temp, 1);
- SetLength(TempStr, Temp);
- ReadBuffer(PChar(TempStr)^, Temp);
- Name := TempStr;
- ReadBuffer(FParamType, SizeOf(FParamType));
- ReadBuffer(FDataType, SizeOf(FDataType));
- if DataType <> ftUnknown then
- begin
- Temp := 0;
- if Version = 2 then ReadBuffer(Temp, SizeOf(Temp))
- else ReadBuffer(Temp, 2);
- ReadBuffer(Buffer, Temp);
- SetData(@Buffer);
- end;
- ReadBuffer(FNull, SizeOf(FNull));
- ReadBuffer(FBound, SizeOf(FBound));
- end;
- end;
- end;
-
- procedure TParams.WriteBinaryData(Stream: TStream);
- var
- I: Integer;
- Temp: SmallInt;
- Version: Word;
- Buffer: array[0..255] of Char;
- begin
- with Stream do
- begin
- Version := GetVersion;
- WriteBuffer(Version, SizeOf(Version));
- Temp := Count;
- WriteBuffer(Temp, SizeOf(Temp));
- for I := 0 to Count - 1 do
- with Items[I] do
- begin
- Temp := Length(FName);
- WriteBuffer(Temp, 1);
- WriteBuffer(PChar(FName)^, Length(FName));
- WriteBuffer(FParamType, SizeOf(FParamType));
- WriteBuffer(FDataType, SizeOf(FDataType));
- if DataType <> ftUnknown then
- begin
- GetData(@Buffer);
- Temp := GetDataSize;
- WriteBuffer(Temp, SizeOf(Temp));
- WriteBuffer(Buffer, Temp);
- end;
- WriteBuffer(FNull, SizeOf(FNull));
- WriteBuffer(FBound, SizeOf(FBound));
- end;
- end;
- end;
-
- function TParams.GetVersion: Word;
- begin
- Result := 1;
- end;
-
- function TParams.GetParamValue(const ParamName: string): Variant;
- var
- I: Integer;
- Params: TList;
- begin
- if Pos(';', ParamName) <> 0 then
- begin
- Params := TList.Create;
- try
- GetParamList(Params, ParamName);
- Result := VarArrayCreate([0, Params.Count - 1], varVariant);
- for I := 0 to Params.Count - 1 do
- Result[I] := TParam(Params[I]).Value;
- finally
- Params.Free;
- end;
- end else
- Result := ParamByName(ParamName).Value
- end;
-
- procedure TParams.SetParamValue(const ParamName: string;
- const Value: Variant);
- var
- I: Integer;
- Params: TList;
- begin
- if Pos(';', ParamName) <> 0 then
- begin
- Params := TList.Create;
- try
- GetParamList(Params, ParamName);
- for I := 0 to Params.Count - 1 do
- TParam(Params[I]).Value := Value[I];
- finally
- Params.Free;
- end;
- end else
- ParamByName(ParamName).Value := Value;
- end;
-
- procedure TParams.GetParamList(List: TList; const ParamNames: string);
- var
- Pos: Integer;
- begin
- Pos := 1;
- while Pos <= Length(ParamNames) do
- List.Add(ParamByName(ExtractFieldName(ParamNames, Pos)));
- end;
-
- { TParam }
-
- constructor TParam.Create(AParamList: TParams; AParamType: TParamType);
- begin
- if AParamList <> nil then AParamList.AddParam(Self);
- ParamType := AParamType;
- DataType := ftUnknown;
- FBound := False;
- end;
-
- destructor TParam.Destroy;
- begin
- if FParamList <> nil then FParamList.RemoveParam(Self);
- end;
-
- function TParam.IsEqual(Value: TParam): Boolean;
- begin
- Result := (VarType(FData) = VarType(Value.FData)) and
- (FData = Value.FData) and (Name = Value.Name) and
- (DataType = Value.DataType) and (IsNull = Value.IsNull) and
- (Bound = Value.Bound) and (ParamType = Value.ParamType);
- end;
-
- procedure TParam.SetDataType(Value: TFieldType);
- begin
- FData := 0;
- FDataType := Value;
- end;
-
- function TParam.GetDataSize: Word;
- begin
- case DataType of
- ftUnknown: DBErrorFmt(SFieldUndefinedType, [Name]);
- ftString: Result := Length(FData) + 1;
- ftBoolean: Result := SizeOf(WordBool);
- ftBCD: Result := SizeOf(FMTBcd);
- ftDateTime,
- ftCurrency,
- ftFloat: Result := SizeOf(Double);
- ftTime,
- ftDate,
- ftAutoInc,
- ftInteger: Result := SizeOf(Integer);
- ftSmallint: Result := SizeOf(SmallInt);
- ftWord: Result := SizeOf(Word);
- else
- DBErrorFmt(SFieldUnsupportedType, [Name]);
- end;
- end;
-
- procedure TParam.GetData(Buffer: Pointer);
- begin
- case DataType of
- ftUnknown: DBErrorFmt(SFieldUndefinedType, [Name]);
- ftString:
- begin
- StrMove(Buffer, PChar(string(FData)), Length(FData));
- (PChar(Buffer) + Length(FData))^ := #0;
- end;
- ftSmallint: SmallInt(Buffer^) := FData;
- ftWord: Word(Buffer^) := FData;
- ftAutoInc,
- ftInteger: Integer(Buffer^) := FData;
- ftTime: Integer(Buffer^) := DateTimeToTimeStamp(AsDateTime).Time;
- ftDate: Integer(Buffer^) := DateTimeToTimeStamp(AsDateTime).Date;
- ftDateTime: Double(Buffer^) := TimeStampToMSecs(DateTimeToTimeStamp(AsDateTime));
- ftBCD: CurrToBCD(AsBCD, FMTBcd(Buffer^), 32, 4);
- ftCurrency,
- ftFloat: Double(Buffer^) := FData;
- ftBoolean: WordBool(Buffer^) := FData;
- else
- DBErrorFmt(SFieldUnsupportedType, [Name]);
- end;
- end;
-
- procedure TParam.SetData(Buffer: Pointer);
- var
- Value: Currency;
- TimeStamp: TTimeStamp;
- begin
- case DataType of
- ftUnknown: DBErrorFmt(SFieldUndefinedType, [Name]);
- ftString: AsString := StrPas(Buffer);
- ftWord: AsWord := Word(Buffer^);
- ftSmallint: AsSmallInt := Smallint(Buffer^);
- ftInteger: AsInteger := Integer(Buffer^);
- ftTime:
- begin
- TimeStamp.Time := LongInt(Buffer^);
- TimeStamp.Date := DateDelta;
- AsTime := TimeStampToDateTime(TimeStamp);
- end;
- ftDate:
- begin
- TimeStamp.Time := 0;
- TimeStamp.Date := Integer(Buffer^);
- AsDate := TimeStampToDateTime(TimeStamp);
- end;
- ftDateTime:
- begin
- TimeStamp.Time := 0;
- TimeStamp.Date := Integer(Buffer^);
- AsDateTime := TimeStampToDateTime(MSecsToTimeStamp(Double(Buffer^)));
- end;
- ftBCD:
- begin
- BCDToCurr(FMTBcd(Buffer^), Value);
- AsBCD := Value;
- end;
- ftCurrency: AsCurrency := Double(Buffer^);
- ftFloat: AsFloat := Double(Buffer^);
- ftBoolean: AsBoolean := WordBool(Buffer^);
- else
- DBErrorFmt(SFieldUnsupportedType, [Name]);
- end;
- end;
-
- procedure TParam.SetText(const Value: string);
- begin
- InitValue;
- if DataType = ftUnknown then DataType := ftString;
- FData := Value;
- case DataType of
- ftDateTime, ftTime, ftDate: FData := VarToDateTime(FData);
- ftBCD: FData := Currency(FData);
- ftCurrency, ftFloat: FData := Single(FData);
- ftInteger, ftSmallInt, ftWord: FData := Integer(FData);
- ftBoolean: FData := Boolean(FData);
- end;
- end;
-
- procedure TParam.Assign(Param: TParam);
- begin
- if Param <> nil then
- begin
- DataType := Param.DataType;
- if Param.IsNull then Clear
- else begin
- InitValue;
- FData := Param.FData;
- end;
- FBound := Param.Bound;
- Name := Param.Name;
- if ParamType = ptUnknown then ParamType := Param.ParamType;
- end;
- end;
-
- procedure TParam.AssignFieldValue(Field: TField; const Value: Variant);
- begin
- if Field <> nil then
- begin
- DataType := Field.DataType;
- if VarIsNull(Value) then Clear
- else begin
- InitValue;
- FData := Value;
- end;
- FBound := True;
- end;
- end;
-
- procedure TParam.AssignField(Field: TField);
- begin
- if Field <> nil then
- begin
- DataType := Field.DataType;
- if Field.IsNull then Clear
- else begin
- InitValue;
- FData := Field.Value;
- end;
- FBound := True;
- Name := Field.FieldName;
- end;
- end;
-
- procedure TParam.AccessError;
- begin
- DBErrorFmt(SParamAccessError, [Name]);
- end;
-
- procedure TParam.Clear;
- begin
- FNull := True;
- FData := 0;
- end;
-
- procedure TParam.InitValue;
- begin
- FBound := True;
- FNull := False;
- end;
-
- procedure TParam.SetAsBoolean(Value: Boolean);
- begin
- InitValue;
- DataType := ftBoolean;
- FData := Value;
- end;
-
- function TParam.GetAsBoolean: Boolean;
- begin
- Result := FData;
- end;
-
- procedure TParam.SetAsFloat(Value: Double);
- begin
- InitValue;
- DataType := ftFloat;
- FData := Value;
- end;
-
- procedure TParam.SetAsCurrency(Value: Double);
- begin
- SetAsFloat(Value);
- FDataType := ftCurrency;
- end;
-
- procedure TParam.SetAsBCD(Value: Currency);
- begin
- InitValue;
- FData := Value;
- FDataType := ftBCD;
- end;
-
- function TParam.GetAsFloat: Double;
- begin
- Result := FData;
- end;
-
- function TParam.GetAsBCD: Currency;
- begin
- Result := FData;
- end;
-
- procedure TParam.SetAsInteger(Value: Longint);
- begin
- InitValue;
- DataType := ftInteger;
- FData := Value;
- end;
-
- procedure TParam.SetAsWord(Value: LongInt);
- begin
- SetAsInteger(Value);
- FDataType := ftWord;
- end;
-
- procedure TParam.SetAsSmallInt(Value: LongInt);
- begin
- SetAsInteger(Value);
- FDataType := ftSmallint;
- end;
-
- function TParam.GetAsInteger: Longint;
- begin
- Result := FData;
- end;
-
- procedure TParam.SetAsString(const Value: string);
- begin
- InitValue;
- DataType := ftString;
- FData := Value;
- end;
-
- function TParam.GetAsString: string;
- begin
- if not IsNull then
- case DataType of
- ftBoolean:
- if FData then Result := LoadStr(STextTrue)
- else Result := LoadStr(STextFalse);
- ftDateTime, ftDate, ftTime: Result := VarFromDateTime(FData)
- else Result := FData;
- end
- else Result := ''
- end;
-
- procedure TParam.SetAsDate(Value: TDateTime);
- begin
- InitValue;
- DataType := ftDate;
- FData := VarFromDateTime(Value);
- end;
-
- procedure TParam.SetAsTime(Value: TDateTime);
- begin
- SetAsDate(Value);
- FDataType := ftTime;
- end;
-
- procedure TParam.SetAsDateTime(Value: TDateTime);
- begin
- SetAsDate(Value);
- FDataType := ftDateTime;
- end;
-
- function TParam.GetAsDateTime: TDateTime;
- begin
- if IsNull then
- Result := 0 else
- Result := VarToDateTime(FData);
- end;
-
- procedure TParam.SetAsVariant(Value: Variant);
- begin
- InitValue;
- case VarType(Value) of
- varSmallint: DataType := ftSmallInt;
- varInteger: DataType := ftInteger;
- varCurrency: DataType := ftBCD;
- varSingle,
- varDouble: DataType := ftFloat;
- varDate: DataType := ftDateTime;
- varBoolean: DataType := ftBoolean;
- varString: DataType := ftString;
- else DataType := ftUnknown;
- end;
- FData := Value;
- end;
-
- function TParam.GetAsVariant: Variant;
- begin
- Result := FData;
- end;
-
- { TQueryDataLink }
-
- constructor TQueryDataLink.Create(AQuery: TQuery);
- begin
- inherited Create;
- FQuery := AQuery;
- end;
-
- procedure TQueryDataLink.ActiveChanged;
- begin
- if FQuery.Active then FQuery.RefreshParams;
- end;
-
- procedure TQueryDataLink.RecordChanged(Field: TField);
- begin
- if (Field = nil) and FQuery.Active then FQuery.RefreshParams;
- end;
-
- procedure TQueryDataLink.CheckBrowseMode;
- begin
- if FQuery.Active then FQuery.CheckBrowseMode;
- end;
-
- { TStoredProc }
-
- constructor TStoredProc.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FParams := TParams.Create;
- FParamDesc := nil;
- FRecordBuffer := nil;
- FServerDescs := nil;
- end;
-
- destructor TStoredProc.Destroy;
- begin
- Destroying;
- Disconnect;
- FParams.Free;
- inherited Destroy;
- end;
-
- procedure TStoredProc.Disconnect;
- begin
- Close;
- UnPrepare;
- end;
-
- function TStoredProc.CreateCursor(GenHandle: Boolean): HDBICur;
- begin
- if StoredProcName <> '' then
- begin
- SetPrepared(True);
- Result := GetCursor(GenHandle);
- end
- else Result := nil;
- end;
-
- function TStoredProc.CreateHandle: HDBICur;
- begin
- Result := CreateCursor(True);
- end;
-
- function TStoredProc.GetCursor(GenHandle: Boolean): HDBICur;
- var
- PCursor: phDBICur;
- begin
- Result := nil;
- if GenHandle then PCursor := @Result
- else PCursor := nil;
- BindParams;
- Check(DbiQExec(StmtHandle, PCursor));
- GetResults;
- end;
-
- procedure TStoredProc.ExecProc;
- begin
- CheckInActive;
- SetDBFlag(dbfExecProc, True);
- try
- CreateCursor(False);
- finally
- SetDBFlag(dbfExecProc, False);
- end;
- end;
-
- procedure TStoredProc.SetProcName(const Value: string);
- begin
- if not (csReading in ComponentState) then
- begin
- CheckInactive;
- if Value <> FProcName then
- begin
- FProcName := Value;
- FreeStatement;
- FParams.Clear;
- end;
- end else
- FProcName := Value;
- end;
-
- procedure TStoredProc.SetOverLoad(Value: Word);
- begin
- if not (csReading in ComponentState) then
- begin
- CheckInactive;
- if Value <> OverLoad then
- begin
- FOverLoad := Value;
- FreeStatement;
- FParams.Clear;
- end
- end else
- FOverLoad := Value;
- end;
-
- function TStoredProc.GetParamsCount: Word;
- begin
- Result := FParams.Count;
- end;
-
- procedure TStoredProc.CreateParamDesc;
- const
- TypeMap: array[0..MAXLOGFLDTYPES - 1] of TFieldType = (
- ftUnknown, ftString, ftDate, ftBlob, ftBoolean, ftSmallint,
- ftInteger, ftFloat, ftBCD, ftBytes, ftTime, ftDateTime,
- ftWord, ftUnknown, ftUnknown, ftVarBytes, ftUnknown);
- var
- Desc: SPParamDesc;
- Cursor: HDBICur;
- Buffer: array[0..DBIMAXSPNAMELEN] of Char;
- Name: string;
- DataType: TFieldType;
- begin
- AnsiToNative(DBLocale, StoredProcName, Buffer, DBIMAXSPNAMELEN);
- if DbiOpenSPParamList(DBHandle, Buffer, False, OverLoad, Cursor) = 0 then
- try
- while DbiGetNextRecord(Cursor, dbiNOLOCK, @Desc, nil) = 0 do
- with Desc do
- begin
- NativeToAnsi(DBLocale, szName, Name);
- if (TParamType(eParamType) = ptResult) and (Name = '') then
- Name := LoadStr(SResultName);
- if uFldType < MAXLOGFLDTYPES then DataType := TypeMap[uFldType]
- else DataType := ftUnknown;
- if (uFldType = fldFLOAT) and (uSubType = fldstMONEY) then
- DataType := ftCurrency;
- FParams.CreateParam(DataType, Name, TParamType(eParamType));
- end;
- SetServerParams;
- finally
- DbiCloseCursor(Cursor);
- end;
- end;
-
- procedure TStoredProc.SetServerParams;
- var
- I: Integer;
- DescPtr: PServerDesc;
- begin
- FServerDescs := StrAlloc(Params.Count * SizeOf(TServerDesc));
- DescPtr := PServerDesc(FServerDescs);
- for I := 0 to Params.Count - 1 do
- with Params[I], DescPtr^ do
- begin
- ParamName := Name;
- BindType := DataType;
- Inc(DescPtr);
- end;
- end;
-
- function TStoredProc.CheckServerParams: Boolean;
- var
- I, J: Integer;
- DescPtr: PServerDesc;
- begin
- if FServerDescs = nil then
- begin
- SetServerParams;
- Result := False;
- end else
- begin
- DescPtr := PServerDesc(FServerDescs);
- for I := 0 to StrBufSize(FServerDescs) div SizeOf(TServerDesc) - 1 do
- begin
- for J := 0 to Params.Count - 1 do
- with Params.Items[J], DescPtr^ do
- if (Name = ParamName) and (DataType <> BindType) then
- begin
- Result := False;
- Exit;
- end;
- Inc(DescPtr);
- end;
- Result := True;
- end;
- end;
-
- function TStoredProc.DescriptionsAvailable: Boolean;
- var
- Cursor: HDBICur;
- Buffer: array[0..DBIMAXSPNAMELEN] of Char;
- begin
- SetDBFlag(dbfProcDesc, True);
- try
- AnsiToNative(DBLocale, StoredProcName, Buffer, DBIMAXSPNAMELEN);
- Result := DbiOpenSPParamList(DBHandle, Buffer, False, OverLoad, Cursor) = 0;
- if Result then DbiCloseCursor(Cursor);
- finally
- SetDBFlag(dbfProcDesc, False);
- end;
- end;
-
- procedure TStoredProc.PrepareProc;
- const
- TypeMap: 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);
- var
- I: Integer;
- Desc: PSPParamDesc;
- NumBytes, Offset: Word;
- Buffer: array[0..DBIMAXSPNAMELEN] of Char;
- begin
- FParamDesc := StrAlloc(FParams.Count * SizeOf(SPParamDesc));
- FillChar(FParamDesc^, StrBufSize(FParamDesc), 0);
- Desc := PSPParamDesc(FParamDesc);
- NumBytes := 0;
- for I := 0 to FParams.Count - 1 do
- with Params[I] do
- if DataType = ftString then Inc(NumBytes, 255 + 2)
- else Inc(NumBytes, GetDataSize + 2);
- FRecordBuffer := StrAlloc(NumBytes);
- FillChar(FRecordBuffer^, NumBytes, 0);
- Offset := 0;
- for I := 0 to FParams.Count - 1 do
- begin
- with Params[I] do
- begin
- with Desc^ do
- begin
- if DataType = ftUnknown then
- DBErrorFmt(SNoParameterValue, [Name]);
- if ParamType = ptUnknown then
- DBErrorFmt(SNoParameterType, [Name]);
- if FBindMode = pbByName then
- AnsiToNative(Locale, Name, szName, DBIMAXNAMELEN)
- else uParamNum := I + 1;
- eParamType := STMTParamType(ParamType);
- uFldType := TypeMap[DataType];
- if DataType = ftCurrency then uSubType := fldstMONEY;
- if uFldType = fldZString then
- begin
- uLen := 255;
- iUnits1 := uLen - 1;
- end else
- uLen := GetDataSize;
- uOffset := Offset;
- Inc(Offset, uLen);
- uNullOffset := NumBytes - 2 * (I + 1);
- end;
- if ParamType in [ptInput, ptInputOutput] then
- SmallInt(Pointer(FRecordBuffer + NumBytes - 2 * (I + 1))^) := IndNull;
- Inc(Desc);
- end;
- end;
- AnsiToNative(Locale, StoredProcName, Buffer, DBIMAXSPNAMELEN);
- Check(DbiQPrepareProc(DBHandle, Buffer, FParams.Count,
- PSPParamDesc(FParamDesc), nil, FStmtHandle));
- end;
-
- procedure TStoredProc.GetResults;
- var
- I: Integer;
- CurPtr: PChar;
- IntPtr: ^SmallInt;
- NumBytes: Word;
- begin
- if FRecordBuffer <> nil then
- begin
- CurPtr := FRecordBuffer;
- NumBytes := StrBufSize(FRecordBuffer);
- for I := 0 to FParams.Count - 1 do
- with Params[I] do
- begin
- if ParamType in [ptOutput, ptInputOutput, ptResult] then
- begin
- if DataType = ftString then
- NativeToAnsiBuf(Locale, CurPtr, CurPtr, StrLen(CurPtr));
- IntPtr := Pointer(FRecordBuffer + NumBytes - 2 * (I + 1));
- if IntPtr^ = IndNull then Clear
- else if IntPtr^ = IndTrunc then DBErrorFmt(STruncationError, [Name])
- else SetData(CurPtr);
- end;
- if DataType = ftString then Inc(CurPtr, 255)
- else Inc(CurPtr, GetDataSize);
- end;
- end;
- end;
-
- procedure TStoredProc.BindParams;
- var
- I: Integer;
- CurPtr: PChar;
- NumBytes: Word;
- IntPtr: ^SmallInt;
- DrvName: array[0..DBIMAXNAMELEN - 1] of Char;
- DrvLocale: TLocale;
- begin
- if FRecordBuffer = nil then Exit;
- if not CheckServerParams then
- begin
- SetPrepared(False);
- SetPrepared(True);
- end;
- DrvName[0] := #0;
- DrvLocale := nil;
- DbiGetProp(HDBIOBJ(StmtHandle), stmtLANGDRVNAME, @DrvName, SizeOf(DrvName), NumBytes);
- if StrLen(DrvName) > 0 then OsLdLoadBySymbName(DrvName, DrvLocale);
- try
- NumBytes := StrBufSize(FRecordBuffer);
- CurPtr := FRecordBuffer;
- for I := 0 to FParams.Count - 1 do
- begin
- with Params[I] do
- begin
- if ParamType in [ptInput, ptInputOutput] then
- begin
- GetData(CurPtr);
- IntPtr := Pointer(FRecordBuffer + NumBytes - 2 * (I + 1));
- if IsNull then IntPtr^ := IndNull
- else IntPtr^ := 0;
- end;
- if DataType = ftString then
- begin
- if DrvLocale <> nil then
- AnsiToNativeBuf(DrvLocale, CurPtr, CurPtr, GetDataSize);
- Inc(CurPtr, 255);
- end
- else Inc(CurPtr, GetDataSize);
- end;
- end;
- Check(DbiQSetProcParams(StmtHandle, FParams.Count,
- PSPParamDesc(FParamDesc), FRecordBuffer));
- finally
- if DrvLocale <> nil then OsLdUnloadObj(DrvLocale);
- end;
- end;
-
- procedure TStoredProc.SetPrepared(Value: Boolean);
- begin
- if Handle <> nil then DBError(SDataSetOpen);
- if Prepared <> Value then
- begin
- if Value then
- try
- if FParams.Count = 0 then CreateParamDesc
- else SetServerParams;
- if not FQueryMode then PrepareProc;
- FPrepared := True;
- except
- FreeStatement;
- raise;
- end
- else FreeStatement;
- end;
- end;
-
- procedure TStoredProc.Prepare;
- begin
- SetDBFlag(dbfStoredProc, True);
- SetPrepared(True);
- end;
-
- procedure TStoredProc.UnPrepare;
- begin
- SetPrepared(False);
- SetDBFlag(dbfStoredProc, False);
- end;
-
- procedure TStoredProc.FreeStatement;
- begin
- if StmtHandle <> nil then DbiQFree(FStmtHandle);
- StrDispose(FParamDesc);
- FParamDesc := nil;
- StrDispose(FRecordBuffer);
- FRecordBuffer := nil;
- StrDispose(FServerDescs);
- FServerDescs := nil;
- FPrepared := False;
- end;
-
- procedure TStoredProc.SetPrepare(Value: Boolean);
- begin
- if Value then Prepare
- else UnPrepare;
- end;
-
- procedure TStoredProc.SetDBFlag(Flag: Integer; Value: Boolean);
- begin
- if not Value and (DBFlags - [Flag] = []) then SetPrepared(False);
- inherited SetDBFlag(Flag, Value);
- end;
-
- procedure TStoredProc.CopyParams(Value: TParams);
- begin
- if not Prepared and (FParams.Count = 0) then
- try
- FQueryMode := True;
- Prepare;
- Value.Assign(FParams);
- finally
- UnPrepare;
- FQueryMode := False;
- end else
- Value.Assign(FParams);
- end;
-
- procedure TStoredProc.SetParamsList(Value: TParams);
- begin
- CheckInactive;
- if Prepared then
- begin
- SetPrepared(False);
- FParams.Assign(Value);
- SetPrepared(True);
- end else
- FParams.Assign(Value);
- end;
-
- function TStoredProc.ParamByName(const Value: string): TParam;
- begin
- Result := FParams.ParamByName(Value);
- end;
-
- { TQuery }
-
- constructor TQuery.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FSQL := TStringList.Create;
- TStringList(SQL).OnChange := QueryChanged;
- FParams := TParams.Create;
- FDataLink := TQueryDataLink.Create(Self);
- RequestLive := False;
- ParamCheck := True;
- FRowsAffected := -1;
- end;
-
- destructor TQuery.Destroy;
- begin
- Destroying;
- Disconnect;
- SQL.Free;
- FParams.Free;
- FDataLink.Free;
- StrDispose(SQLBinary);
- inherited Destroy;
- end;
-
- procedure TQuery.Disconnect;
- begin
- Close;
- UnPrepare;
- end;
-
- procedure TQuery.SetPrepare(Value: Boolean);
- begin
- if Value then Prepare
- else UnPrepare;
- end;
-
- procedure TQuery.Prepare;
- begin
- SetDBFlag(dbfPrepared, True);
- SetPrepared(True);
- end;
-
- procedure TQuery.UnPrepare;
- begin
- SetPrepared(False);
- SetDBFlag(dbfPrepared, False);
- end;
-
- procedure TQuery.SetDataSource(Value: TDataSource);
- begin
- if IsLinkedTo(Value) then DBError(SCircularDataLink);
- FDataLink.DataSource := Value;
- end;
-
- function TQuery.GetDataSource: TDataSource;
- begin
- Result := FDataLink.DataSource;
- end;
-
- procedure TQuery.SetQuery(Value: TStrings);
- begin
- if SQL.Text <> Value.Text then
- begin
- Disconnect;
- SQL.BeginUpdate;
- try
- SQL.Assign(Value);
- finally
- SQL.EndUpdate;
- end;
- end;
- end;
-
- procedure TQuery.QueryChanged(Sender: TObject);
- var
- List: TParams;
- begin
- FText := SQL.Text;
- if not (csLoading in ComponentState) then
- begin
- Disconnect;
- StrDispose(SQLBinary);
- SQLBinary := nil;
- if ParamCheck or (csDesigning in ComponentState) then
- begin
- List := TParams.Create;
- try
- CreateParams(List, PChar(Text));
- List.AssignValues(FParams);
- FParams.Free;
- FParams := List;
- except
- List.Free;
- end;
- end;
- DataEvent(dePropertyChange, 0);
- end else
- CreateParams(nil, PChar(Text));
- end;
-
- procedure TQuery.SetParamsList(Value: TParams);
- begin
- FParams.AssignValues(Value);
- end;
-
- function TQuery.GetParamsCount: Word;
- begin
- Result := FParams.Count;
- end;
-
- procedure TQuery.DefineProperties(Filer: TFiler);
- begin
- inherited DefineProperties(Filer);
- Filer.DefineBinaryProperty('Data', ReadBinaryData, WriteBinaryData, SQLBinary <> nil);
- end;
-
- procedure TQuery.ReadBinaryData(Stream: TStream);
- begin
- SQLBinary := StrAlloc(Stream.Size);
- Stream.ReadBuffer(SQLBinary^, Stream.Size);
- end;
-
- procedure TQuery.WriteBinaryData(Stream: TStream);
- begin
- Stream.WriteBuffer(SQLBinary^, StrBufSize(SQLBinary));
- end;
-
- procedure TQuery.SetPrepared(Value: Boolean);
- begin
- if Handle <> nil then DBError(SDataSetOpen);
- if Value <> Prepared then
- begin
- if Value then
- begin
- FRowsAffected := -1;
- if Length(Text) > 1 then PrepareSQL(PChar(Text))
- else DBError(SEmptySQLStatement);
- end
- else
- begin
- FRowsAffected := RowsAffected;
- FreeStatement;
- end;
- FPrepared := Value;
- end;
- end;
-
- procedure TQuery.FreeStatement;
- begin
- if StmtHandle <> nil then DbiQFree(FStmtHandle);
- end;
-
- procedure TQuery.SetParamsFromCursor;
- var
- I: Integer;
- DataSet: TDataSet;
- begin
- if FDataLink.DataSource <> nil then
- begin
- DataSet := FDataLink.DataSource.DataSet;
- if DataSet <> nil then
- begin
- DataSet.FieldDefs.Update;
- for I := 0 to FParams.Count - 1 do
- with FParams[I] do
- if not Bound then
- begin
- AssignField(DataSet.FieldByName(Name));
- Bound := False;
- end;
- end;
- end;
- end;
-
- procedure TQuery.RefreshParams;
- var
- DataSet: TDataSet;
- begin
- DisableControls;
- try
- if FDataLink.DataSource <> nil then
- begin
- DataSet := FDataLink.DataSource.DataSet;
- if DataSet <> nil then
- if DataSet.Active and (DataSet.State <> dsSetKey) then
- begin
- Close;
- Open;
- end;
- end;
- finally
- EnableControls;
- end;
- end;
-
- function TQuery.ParamByName(const Value: string): TParam;
- begin
- Result := FParams.ParamByName(Value);
- end;
-
- procedure TQuery.CreateParams(List: TParams; const Value: PChar);
- var
- CurPos, StartPos: PChar;
- CurChar: Char;
- Literal: Boolean;
- EmbeddedLiteral: Boolean;
- Name: string;
-
- function NameDelimiter: Boolean;
- begin
- Result := CurChar in [' ', ',', ';', ')', #13, #10];
- end;
-
- function IsLiteral: Boolean;
- begin
- Result := CurChar in ['''', '"'];
- end;
-
- function StripLiterals(Buffer: PChar): string;
- var
- Len: Word;
- TempBuf: PChar;
-
- procedure StripChar(Value: Char);
- begin
- if TempBuf^ = Value then
- StrMove(TempBuf, TempBuf + 1, Len - 1);
- if TempBuf[StrLen(TempBuf) - 1] = Value then
- TempBuf[StrLen(TempBuf) - 1] := #0;
- end;
-
- begin
- Len := StrLen(Buffer) + 1;
- TempBuf := AllocMem(Len);
- Result := '';
- try
- StrCopy(TempBuf, Buffer);
- StripChar('''');
- StripChar('"');
- Result := StrPas(TempBuf);
- finally
- FreeMem(TempBuf, Len);
- end;
- end;
-
- begin
- CurPos := Value;
- Literal := False;
- EmbeddedLiteral := False;
- repeat
- CurChar := CurPos^;
- if (CurChar = ':') and not Literal and ((CurPos + 1)^ <> ':') then
- begin
- StartPos := CurPos;
- while (CurChar <> #0) and (Literal or not NameDelimiter) do
- begin
- Inc(CurPos);
- CurChar := CurPos^;
- if IsLiteral then
- begin
- Literal := Literal xor True;
- if CurPos = StartPos + 1 then EmbeddedLiteral := True;
- end;
- end;
- CurPos^ := #0;
- if EmbeddedLiteral then
- begin
- Name := StripLiterals(StartPos + 1);
- EmbeddedLiteral := False;
- end
- else Name := StrPas(StartPos + 1);
- if Assigned(List) then
- List.CreateParam(ftUnknown, Name, ptUnknown);
- CurPos^ := CurChar;
- StartPos^ := '?';
- Inc(StartPos);
- StrMove(StartPos, CurPos, StrLen(CurPos) + 1);
- CurPos := StartPos;
- end
- else if (CurChar = ':') and not Literal and ((CurPos + 1)^ = ':') then
- StrMove(CurPos, CurPos + 1, StrLen(CurPos) + 1)
- else if IsLiteral then Literal := Literal xor True;
- Inc(CurPos);
- until CurChar = #0;
- end;
-
- function TQuery.CreateCursor(GenHandle: Boolean): HDBICur;
- begin
- if SQL.Count > 0 then
- begin
- SetPrepared(True);
- if FDataLink.DataSource <> nil then SetParamsFromCursor;
- Result := GetQueryCursor(GenHandle);
- end
- else DBError(SEmptySQLStatement);
- end;
-
- function TQuery.CreateHandle: HDBICur;
- begin
- Result := CreateCursor(True)
- end;
-
- procedure TQuery.ExecSQL;
- begin
- CheckInActive;
- SetDBFlag(dbfExecSQL, True);
- try
- CreateCursor(False);
- finally
- SetDBFlag(dbfExecSQL, False);
- end;
- end;
-
- function TQuery.GetQueryCursor(GenHandle: Boolean): HDBICur;
- var
- PCursor: phDBICur;
- begin
- Result := nil;
- if GenHandle then PCursor := @Result
- else PCursor := nil;
- if FParams.Count > 0 then SetParams;
- Check(DbiQExec(StmtHandle, PCursor));
- end;
-
- procedure TQuery.SetParams;
- const
- TypeMap: 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);
- var
- DescBuffer: PFieldDescList;
- I: Integer;
- NumBytes: Word;
- Param: TParam;
- FieldDesc: PFLDDesc;
- RecBuffer: PChar;
- CurPtr, NullPtr: PChar;
- DrvName: array[0..DBIMAXNAMELEN - 1] of Char;
- DrvLocale: TLocale;
- begin
- DescBuffer := AllocMem(FParams.Count * SizeOf(FLDDesc));
- FieldDesc := PFLDDesc(DescBuffer);
- NumBytes := 2;
- DrvName[0] := #0;
- DrvLocale := nil;
- DbiGetProp(HDBIOBJ(StmtHandle), stmtLANGDRVNAME, @DrvName, SizeOf(DrvName), NumBytes);
- if StrLen(DrvName) > 0 then OsLdLoadBySymbName(DrvName, DrvLocale);
- try
- for I := 0 to FParams.Count - 1 do
- Inc(NumBytes, Params[I].GetDataSize);
- RecBuffer := AllocMem(NumBytes);
- NullPtr := RecBuffer + NumBytes - 2;
- Smallint(Pointer(NullPtr)^) := -1;
- CurPtr := RecBuffer;
- try
- for I := 0 to FParams.Count - 1 do
- begin
- Param := Params[I];
- with FieldDesc^ do
- begin
- iFldType := TypeMap[Param.DataType];
- if iFldType = fldUNKNOWN then
- DBErrorFmt(SNoParameterValue, [Param.Name]);
- iFldNum := I + 1;
- iLen := Param.GetDataSize;
- if iFldType = fldZString then iUnits1 := iLen - 1;
- iOffset := CurPtr - RecBuffer;
- if Param.IsNull then iNullOffset := NullPtr - RecBuffer;
- end;
- with Param do
- begin
- GetData(CurPtr);
- if (FieldDesc^.iFldType = fldZString) and (DrvLocale <> nil) then
- AnsiToNativeBuf(DrvLocale, CurPtr, CurPtr, GetDataSize);
- Inc(CurPtr, GetDataSize);
- Inc(FieldDesc);
- end;
- end;
- Check(DbiQSetParams(StmtHandle, FParams.Count,
- PFLDDesc(DescBuffer), RecBuffer));
- finally
- FreeMem(RecBuffer, NumBytes);
- end;
- finally
- FreeMem(DescBuffer, FParams.Count * SizeOf(FLDDesc));
- if DrvLocale <> nil then OsLdUnloadObj(DrvLocale);
- end;
- end;
-
- procedure TQuery.SetDBFlag(Flag: Integer; Value: Boolean);
- var
- NewConnection: Boolean;
- begin
- if Value then
- begin
- NewConnection := DBFlags = [];
- inherited SetDBFlag(Flag, Value);
- if not (csReading in ComponentState) and NewConnection then
- FLocal := not Database.IsSQLBased;
- end
- else begin
- if DBFlags - [Flag] = [] then SetPrepared(False);
- inherited SetDBFlag(Flag, Value);
- end;
- end;
-
- procedure TQuery.PrepareSQL(Value: PChar);
- begin
- GetStatementHandle(Value);
- if not Local then
- Check(DBiSetProp(hDbiObj(StmtHandle), stmtUNIDIRECTIONAL, LongInt(FUniDirectional)));
- end;
-
- procedure TQuery.GetStatementHandle(SQLText: PChar);
- const
- DataType: array[Boolean] of LongInt = (Ord(wantCanned), Ord(wantLive));
- begin
- Check(DbiQAlloc(DBHandle, qrylangSQL, FStmtHandle));
- try
- Check(DBiSetProp(hDbiObj(StmtHandle), stmtLIVENESS,
- DataType[RequestLive and not ForceUpdateCallback]));
- if Local then
- begin
- Check(DBiSetProp(hDbiObj(StmtHandle), stmtAUXTBLS, LongInt(False)));
- if RequestLive and Constrained then
- Check(DBiSetProp(hDbiObj(StmtHandle), stmtCONSTRAINED, LongInt(True)));
- Check(DbiSetProp(hDbiObj(StmtHandle), stmtCANNEDREADONLY, LongInt(True)));
- end;
- while not CheckOpen(DbiQPrepare(FStmtHandle, SQLText)) do
- {Retry};
- except
- DbiQFree(FStmtHandle);
- FStmtHandle := nil;
- raise;
- end;
- end;
-
- function TQuery.GetSQLText: PChar;
- var
- BufLen: Word;
- I: Integer;
- StrEnd: PChar;
- StrBuf: array[0..255] of Char;
- begin
- BufLen := 1;
- for I := 0 to SQL.Count - 1 do
- Inc(BufLen, Length(SQL.Strings[I]) + 1);
- Result := StrAlloc(BufLen);
- try
- StrEnd := Result;
- for I := 0 to SQL.Count - 1 do
- begin
- StrCopy(StrBuf, PChar(SQL.Strings[I]));
- StrEnd := StrECopy(StrEnd, StrBuf);
- StrEnd := StrECopy(StrEnd, ' ');
- end;
- except
- StrDispose(Result);
- raise;
- end;
- end;
-
- function TQuery.GetRowsAffected: Integer;
- var
- Length: Word;
- begin
- if Prepared then
- if DbiGetProp(hDBIObj(StmtHandle), stmtROWCOUNT, @Result, SizeOf(Result),
- Length) <> 0 then
- Result := -1
- else
- else Result := FRowsAffected;
- end;
-
- { TUpdateSQL }
-
- constructor TUpdateSQL.Create(AOwner: TComponent);
- var
- UpdateKind: TUpdateKind;
- begin
- inherited Create(AOwner);
- for UpdateKind := Low(TUpdateKind) to High(TUpdateKind) do
- FSQLText[UpdateKind] := TStringList.Create;
- end;
-
- destructor TUpdateSQL.Destroy;
- var
- UpdateKind: TUpdateKind;
- begin
- if Assigned(FDataSet) and (FDataSet.UpdateObject = Self) then
- FDataSet.UpdateObject := nil;
- for UpdateKind := Low(TUpdateKind) to High(TUpdateKind) do
- FSQLText[UpdateKind].Free;
- inherited Destroy;
- end;
-
- procedure TUpdateSQL.ExecSQL(UpdateKind: TUpdateKind);
- begin
- with Query[UpdateKind] do
- begin
- Prepare;
- ExecSQL;
- if RowsAffected <> 1 then DBError(SUpdateFailed);
- end;
- end;
-
- function TUpdateSQL.GetQuery(UpdateKind: TUpdateKind): TQuery;
- begin
- if not Assigned(FQueries[UpdateKind]) then
- begin
- FQueries[UpdateKind] := TQuery.Create(Self);
- FQueries[UpdateKind].SQL.Assign(FSQLText[UpdateKind]);
- if (FDataSet is TDBDataSet) then
- begin
- FQueries[UpdateKind].SessionName := TDBDataSet(FDataSet).SessionName;
- FQueries[UpdateKind].DatabaseName := TDBDataSet(FDataSet).DataBaseName;
- end;
- end;
- Result := FQueries[UpdateKind];
- end;
-
- function TUpdateSQL.GetSQL(UpdateKind: TUpdateKind): TStrings;
- begin
- Result := FSQLText[UpdateKind];
- end;
-
- function TUpdateSQL.GetSQLIndex(Index: Integer): TStrings;
- begin
- Result := FSQLText[TUpdateKind(Index)];
- end;
-
- function TUpdateSQL.GetDataSet: TDataSet;
- begin
- Result := FDataSet;
- end;
-
- procedure TUpdateSQL.SetDataSet(ADataSet: TDataSet);
- begin
- FDataSet := ADataSet;
- end;
-
- procedure TUpdateSQL.SetSQL(UpdateKind: TUpdateKind; Value: TStrings);
- begin
- FSQLText[UpdateKind].Assign(Value);
- if Assigned(FQueries[UpdateKind]) then
- begin
- FQueries[UpdateKind].Params.Clear;
- FQueries[UpdateKind].SQL.Assign(Value);
- end;
- end;
-
- procedure TUpdateSQL.SetSQLIndex(Index: Integer; Value: TStrings);
- begin
- SetSQL(TUpdateKind(Index), Value);
- end;
-
- procedure TUpdateSQL.SetParams(UpdateKind: TUpdateKind);
- var
- I: Integer;
- Old: Boolean;
- Param: TParam;
- PName: string;
- Field: TField;
- begin
- if not Assigned(FDataSet) then Exit;
- with Query[UpdateKind] do
- begin
- if FSQLText[UpdateKind].Text <> Query[UpdateKind].SQL.Text then
- Query[UpdateKind].SQL.Assign(FSQLText[UpdateKind]);
- for I := 0 to Params.Count - 1 do
- begin
- Param := Params[I];
- PName := Param.Name;
- Old := CompareText(Copy(PName, 1, 4), 'OLD_') = 0;
- if Old then System.Delete(PName, 1, 4);
- Field := FDataSet.FindField(PName);
- if not Assigned(Field) then Continue;
- if Old then
- Param.AssignFieldValue(Field, Field.OldValue) else
- Param.AssignFieldValue(Field, Field.NewValue);
- Param.GetDataSize;
- end;
- end;
- end;
-
- procedure TUpdateSQL.Apply(UpdateKind: TUpdateKind);
- begin
- SetParams(UpdateKind);
- ExecSQL(UpdateKind);
- end;
-
- { TStringField }
-
- constructor TStringField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftString);
- Size := 20;
- Transliterate := True;
- end;
-
- function TStringField.GetAsBoolean: Boolean;
- var
- S: string;
- begin
- S := GetAsString;
- Result := (Length(S) > 0) and (S[1] in ['T', 't', 'Y', 'y']);
- end;
-
- function TStringField.GetAsDateTime: TDateTime;
- begin
- Result := StrToDateTime(GetAsString);
- end;
-
- function TStringField.GetAsFloat: Double;
- begin
- Result := StrToFloat(GetAsString);
- end;
-
- function TStringField.GetAsInteger: Longint;
- begin
- Result := StrToInt(GetAsString);
- end;
-
- function TStringField.GetAsString: string;
- begin
- if not GetValue(Result) then Result := '';
- end;
-
- function TStringField.GetAsVariant: Variant;
- var
- S: string;
- begin
- if GetValue(S) then Result := S else Result := Null;
- end;
-
- function TStringField.GetDefaultWidth: Integer;
- begin
- Result := Size;
- end;
-
- procedure TStringField.GetText(var Text: string; DisplayText: Boolean);
- begin
- if DisplayText and (EditMaskPtr <> '') then
- Text := FormatMaskText(EditMaskPtr, GetAsString) else
- Text := GetAsString;
- end;
-
- function TStringField.GetValue(var Value: string): Boolean;
- var
- Buffer: array[0..dsMaxStringSize] of Char;
- begin
- Result := GetData(@Buffer);
- if Result then
- if Transliterate then
- NativeToAnsi(DataSet.Locale, Buffer, Value) else
- Value := Buffer;
- end;
-
- procedure TStringField.SetAsBoolean(Value: Boolean);
- const
- Values: array[Boolean] of string[1] = ('F', 'T');
- begin
- SetAsString(Values[Value]);
- end;
-
- procedure TStringField.SetAsDateTime(Value: TDateTime);
- begin
- SetAsString(DateTimeToStr(Value));
- end;
-
- procedure TStringField.SetAsFloat(Value: Double);
- begin
- SetAsString(FloatToStr(Value));
- end;
-
- procedure TStringField.SetAsInteger(Value: Longint);
- begin
- SetAsString(IntToStr(Value));
- end;
-
- procedure TStringField.SetAsString(const Value: string);
- var
- Buffer: array[0..dsMaxStringSize] of Char;
- begin
- if Transliterate then
- AnsiToNative(DataSet.Locale, Value, Buffer, Size) else
- StrLCopy(Buffer, PChar(Value), Size);
- SetData(@Buffer);
- end;
-
- procedure TStringField.SetVarValue(const Value: Variant);
- begin
- SetAsString(Value);
- end;
-
- { TNumericField }
-
- constructor TNumericField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- Alignment := taRightJustify;
- end;
-
- procedure TNumericField.RangeError(Value, Min, Max: Extended);
- begin
- DBErrorFmt(SFieldRangeError, [Value, DisplayName, Min, Max]);
- end;
-
- procedure TNumericField.SetDisplayFormat(const Value: string);
- begin
- if FDisplayFormat <> Value then
- begin
- FDisplayFormat := Value;
- PropertyChanged(False);
- end;
- end;
-
- procedure TNumericField.SetEditFormat(const Value: string);
- begin
- if FEditFormat <> Value then
- begin
- FEditFormat := Value;
- PropertyChanged(False);
- end;
- end;
-
- { TIntegerField }
-
- constructor TIntegerField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftInteger);
- FMinRange := Low(Longint);
- FMaxRange := High(Longint);
- end;
-
- procedure TIntegerField.CheckRange(Value, Min, Max: Longint);
- begin
- if (Value < Min) or (Value > Max) then RangeError(Value, Min, Max);
- end;
-
- function TIntegerField.GetAsFloat: Double;
- begin
- Result := GetAsInteger;
- end;
-
- function TIntegerField.GetAsInteger: Longint;
- begin
- if not GetValue(Result) then Result := 0;
- end;
-
- function TIntegerField.GetAsString: string;
- var
- L: Longint;
- begin
- if GetValue(L) then Str(L, Result) else Result := '';
- end;
-
- function TIntegerField.GetAsVariant: Variant;
- var
- L: Longint;
- begin
- if GetValue(L) then Result := L else Result := Null;
- end;
-
- procedure TIntegerField.GetText(var Text: string; DisplayText: Boolean);
- var
- L: Longint;
- FmtStr: string;
- begin
- if GetValue(L) then
- begin
- if DisplayText or (FEditFormat = '') then
- FmtStr := FDisplayFormat else
- FmtStr := FEditFormat;
- if FmtStr = '' then Str(L, Text) else Text := FormatFloat(FmtStr, L);
- end else
- Text := '';
- end;
-
- function TIntegerField.GetValue(var Value: Longint): Boolean;
- var
- Data: record
- case Integer of
- 0: (I: Smallint);
- 1: (W: Word);
- 2: (L: Longint);
- end;
- begin
- Result := GetData(@Data);
- if Result then
- case DataType of
- ftSmallint: Value := Data.I;
- ftWord: Value := Data.W;
- else
- Value := Data.L;
- end;
- end;
-
- function TIntegerField.IsValidChar(Ch: Char): Boolean;
- begin
- Result := Ch in ['+', '-', '0'..'9'];
- end;
-
- procedure TIntegerField.SetAsFloat(Value: Double);
- begin
- SetAsInteger(Round(Value));
- end;
-
- procedure TIntegerField.SetAsInteger(Value: Longint);
- begin
- if (FMinValue <> 0) or (FMaxValue <> 0) then
- CheckRange(Value, FMinValue, FMaxValue) else
- CheckRange(Value, FMinRange, FMaxRange);
- SetData(@Value);
- end;
-
- procedure TIntegerField.SetAsString(const Value: string);
- var
- E: Integer;
- L: Longint;
- begin
- if Value = '' then Clear else
- begin
- Val(Value, L, E);
- if E <> 0 then DBErrorFmt(SInvalidIntegerValue, [Value, DisplayName]);
- SetAsInteger(L);
- end;
- end;
-
- procedure TIntegerField.SetMaxValue(Value: Longint);
- begin
- CheckRange(Value, FMinRange, FMaxRange);
- FMaxValue := Value;
- end;
-
- procedure TIntegerField.SetMinValue(Value: Longint);
- begin
- CheckRange(Value, FMinRange, FMaxRange);
- FMinValue := Value;
- end;
-
- procedure TIntegerField.SetVarValue(const Value: Variant);
- begin
- SetAsInteger(Value);
- end;
-
- { TSmallintField }
-
- constructor TSmallintField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftSmallint);
- FMinRange := Low(Smallint);
- FMaxRange := High(Smallint);
- end;
-
- { TWordField }
-
- constructor TWordField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftWord);
- FMinRange := Low(Word);
- FMaxRange := High(Word);
- end;
-
- { TAutoIncField }
-
- constructor TAutoIncField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftAutoInc);
- end;
-
- { TFloatField }
-
- constructor TFloatField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftFloat);
- FPrecision := 15;
- end;
-
- function TFloatField.GetAsFloat: Double;
- begin
- if not GetData(@Result) then Result := 0;
- end;
-
- function TFloatField.GetAsInteger: Longint;
- begin
- Result := Round(GetAsFloat);
- end;
-
- function TFloatField.GetAsString: string;
- var
- F: Double;
- begin
- if GetData(@F) then Result := FloatToStr(F) else Result := '';
- end;
-
- function TFloatField.GetAsVariant: Variant;
- var
- F: Double;
- begin
- if GetData(@F) then Result := F else Result := Null;
- end;
-
- procedure TFloatField.GetText(var Text: string; DisplayText: Boolean);
- var
- Format: TFloatFormat;
- Digits: Integer;
- FmtStr: string;
- F: Double;
- begin
- if GetData(@F) then
- begin
- if DisplayText or (FEditFormat = '') then
- FmtStr := FDisplayFormat else
- FmtStr := FEditFormat;
- if FmtStr = '' then
- begin
- if FCurrency then
- begin
- if DisplayText then Format := ffCurrency else Format := ffFixed;
- Digits := CurrencyDecimals;
- end
- else begin
- Format := ffGeneral;
- Digits := 0;
- end;
- Text := FloatToStrF(F, Format, FPrecision, Digits);
- end else
- Text := FormatFloat(FmtStr, F);
- end else
- Text := '';
- end;
-
- function TFloatField.IsValidChar(Ch: Char): Boolean;
- begin
- Result := Ch in [DecimalSeparator, '+', '-', '0'..'9', 'E', 'e'];
- end;
-
- procedure TFloatField.SetAsFloat(Value: Double);
- begin
- if FCheckRange and ((Value < FMinValue) or (Value > FMaxValue)) then
- RangeError(Value, FMinValue, FMaxValue);
- SetData(@Value);
- end;
-
- procedure TFloatField.SetAsInteger(Value: Longint);
- begin
- SetAsFloat(Value);
- end;
-
- procedure TFloatField.SetAsString(const Value: string);
- var
- F: Extended;
- begin
- if Value = '' then Clear else
- begin
- if not TextToFloat(PChar(Value), F, fvExtended) then
- DBErrorFmt(SInvalidFloatValue, [Value, DisplayName]);
- SetAsFloat(F);
- end;
- end;
-
- procedure TFloatField.SetCurrency(Value: Boolean);
- begin
- if FCurrency <> Value then
- begin
- FCurrency := Value;
- PropertyChanged(False);
- end;
- end;
-
- procedure TFloatField.SetMaxValue(Value: Double);
- begin
- FMaxValue := Value;
- UpdateCheckRange;
- end;
-
- procedure TFloatField.SetMinValue(Value: Double);
- begin
- FMinValue := Value;
- UpdateCheckRange;
- end;
-
- procedure TFloatField.SetPrecision(Value: Integer);
- begin
- if Value < 2 then Value := 2;
- if Value > 15 then Value := 15;
- if FPrecision <> Value then
- begin
- FPrecision := Value;
- PropertyChanged(False);
- end;
- end;
-
- procedure TFloatField.SetVarValue(const Value: Variant);
- begin
- SetAsFloat(Value);
- end;
-
- procedure TFloatField.UpdateCheckRange;
- begin
- FCheckRange := (FMinValue <> 0) or (FMaxValue <> 0);
- end;
-
- { TCurrencyField }
-
- constructor TCurrencyField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftCurrency);
- FCurrency := True;
- end;
-
- { TBCDField }
-
- constructor TBCDField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftBCD);
- Size := 4;
- end;
-
- function TBCDField.GetAsCurrency: Currency;
- begin
- if not GetValue(Result) then Result := 0;
- end;
-
- function TBCDField.GetAsFloat: Double;
- begin
- Result := GetAsCurrency;
- end;
-
- function TBCDField.GetAsInteger: Longint;
- begin
- Result := Round(GetAsCurrency);
- end;
-
- function TBCDField.GetAsString: string;
- var
- C: System.Currency;
- begin
- if GetValue(C) then Result := CurrToStr(C) else Result := '';
- end;
-
- function TBCDField.GetAsVariant: Variant;
- var
- C: System.Currency;
- begin
- if GetValue(C) then Result := C else Result := Null;
- end;
-
- procedure TBCDField.GetText(var Text: string; DisplayText: Boolean);
- var
- Format: TFloatFormat;
- Digits: Integer;
- FmtStr: string;
- BCD: FMTBcd;
- C: System.Currency;
- begin
- if GetData(@BCD) then
- if BCDToCurr(BCD, C) then
- begin
- if DisplayText or (FEditFormat = '') then
- FmtStr := FDisplayFormat else
- FmtStr := FEditFormat;
- if FmtStr = '' then
- begin
- if FCurrency then
- begin
- if DisplayText then Format := ffCurrency else Format := ffFixed;
- Digits := CurrencyDecimals;
- end
- else begin
- Format := ffGeneral;
- Digits := 0;
- end;
- Text := CurrToStrF(C, Format, Digits);
- end else
- Text := FormatCurr(FmtStr, C);
- end else
- Text := LoadStr(SBCDOverflow)
- else
- Text := '';
- end;
-
- function TBCDField.GetValue(var Value: Currency): Boolean;
- var
- BCD: FMTBcd;
- begin
- Result := GetData(@BCD);
- if Result then
- if not BCDToCurr(BCD, Value) then
- DBErrorFmt(SFieldOutOfRange, [DisplayName]);
- end;
-
- function TBCDField.IsValidChar(Ch: Char): Boolean;
- begin
- Result := Ch in [DecimalSeparator, '+', '-', '0'..'9'];
- end;
-
- procedure TBCDField.SetAsCurrency(Value: Currency);
- var
- BCD: FMTBcd;
- begin
- if FCheckRange and ((Value < FMinValue) or (Value > FMaxValue)) then
- RangeError(Value, FMinValue, FMaxValue);
- CurrToBCD(Value, BCD, 32, Size);
- SetData(@BCD);
- end;
-
- procedure TBCDField.SetAsFloat(Value: Double);
- begin
- SetAsCurrency(Value);
- end;
-
- procedure TBCDField.SetAsInteger(Value: Longint);
- begin
- SetAsCurrency(Value);
- end;
-
- procedure TBCDField.SetAsString(const Value: string);
- var
- C: System.Currency;
- begin
- if Value = '' then Clear else
- begin
- if not TextToFloat(PChar(Value), C, fvCurrency) then
- DBErrorFmt(SInvalidFloatValue, [Value, DisplayName]);
- SetAsCurrency(C);
- end;
- end;
-
- procedure TBCDField.SetCurrency(Value: Boolean);
- begin
- if FCurrency <> Value then
- begin
- FCurrency := Value;
- PropertyChanged(False);
- end;
- end;
-
- procedure TBCDField.SetMaxValue(Value: Currency);
- begin
- FMaxValue := Value;
- UpdateCheckRange;
- end;
-
- procedure TBCDField.SetMinValue(Value: Currency);
- begin
- FMinValue := Value;
- UpdateCheckRange;
- end;
-
- procedure TBCDField.SetVarValue(const Value: Variant);
- begin
- SetAsCurrency(Value);
- end;
-
- procedure TBCDField.UpdateCheckRange;
- begin
- FCheckRange := (FMinValue <> 0) or (FMaxValue <> 0);
- end;
-
- { TBooleanField }
-
- constructor TBooleanField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftBoolean);
- LoadTextValues;
- end;
-
- function TBooleanField.GetAsBoolean: Boolean;
- var
- B: WordBool;
- begin
- if GetData(@B) then Result := B else Result := False;
- end;
-
- function TBooleanField.GetAsString: string;
- var
- B: WordBool;
- begin
- if GetData(@B) then Result := FTextValues[B] else Result := '';
- end;
-
- function TBooleanField.GetAsVariant: Variant;
- var
- B: WordBool;
- begin
- if GetData(@B) then Result := B else Result := Null;
- end;
-
- function TBooleanField.GetDefaultWidth: Integer;
- begin
- if Length(FTextValues[False]) > Length(FTextValues[True]) then
- Result := Length(FTextValues[False]) else
- Result := Length(FTextValues[True]);
- end;
-
- procedure TBooleanField.LoadTextValues;
- begin
- FTextValues[False] := LoadStr(STextFalse);
- FTextValues[True] := LoadStr(STextTrue);
- end;
-
- procedure TBooleanField.SetAsBoolean(Value: Boolean);
- var
- B: WordBool;
- begin
- B := Value;
- SetData(@B);
- end;
-
- procedure TBooleanField.SetAsString(const Value: string);
- var
- L: Integer;
- begin
- L := Length(Value);
- if L = 0 then
- begin
- if Length(FTextValues[False]) = 0 then SetAsBoolean(False) else
- if Length(FTextValues[True]) = 0 then SetAsBoolean(True) else
- Clear;
- end else
- begin
- if AnsiCompareText(Value, Copy(FTextValues[False], 1, L)) = 0 then
- SetAsBoolean(False)
- else
- if AnsiCompareText(Value, Copy(FTextValues[True], 1, L)) = 0 then
- SetAsBoolean(True)
- else
- DBErrorFmt(SInvalidBoolValue, [Value, DisplayName]);
- end;
- end;
-
- procedure TBooleanField.SetDisplayValues(const Value: string);
- var
- P: Integer;
- begin
- if FDisplayValues <> Value then
- begin
- FDisplayValues := Value;
- if Value = '' then LoadTextValues else
- begin
- P := Pos(';', Value);
- if P = 0 then P := 256;
- FTextValues[False] := Copy(Value, P + 1, 255);
- FTextValues[True] := Copy(Value, 1, P - 1);
- end;
- PropertyChanged(True);
- end;
- end;
-
- procedure TBooleanField.SetVarValue(const Value: Variant);
- begin
- SetAsBoolean(Value);
- end;
-
- { TDateTimeField }
-
- constructor TDateTimeField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftDateTime);
- end;
-
- function TDateTimeField.GetAsDateTime: TDateTime;
- begin
- if not GetValue(Result) then Result := 0;
- end;
-
- function TDateTimeField.GetAsFloat: Double;
- begin
- Result := GetAsDateTime;
- end;
-
- function TDateTimeField.GetAsString: string;
- begin
- GetText(Result, False);
- end;
-
- function TDateTimeField.GetAsVariant: Variant;
- var
- D: TDateTime;
- begin
- if GetValue(D) then Result := VarFromDateTime(D) else Result := Null;
- end;
-
- procedure TDateTimeField.GetText(var Text: string; DisplayText: Boolean);
- var
- F: string;
- D: TDateTime;
- begin
- if GetValue(D) then
- begin
- if DisplayText and (FDisplayFormat <> '') then
- F := FDisplayFormat
- else
- case DataType of
- ftDate: F := ShortDateFormat;
- ftTime: F := LongTimeFormat;
- end;
- DateTimeToString(Text, F, D);
- end else
- Text := '';
- end;
-
- function TDateTimeField.GetValue(var Value: TDateTime): Boolean;
- var
- TimeStamp: TTimeStamp;
- Data: TDateTimeRec;
- begin
- Result := GetData(@Data);
- if Result then
- begin
- case DataType of
- ftDate:
- begin
- TimeStamp.Time := 0;
- TimeStamp.Date := Data.Date;
- end;
- ftTime:
- begin
- TimeStamp.Time := Data.Time;
- TimeStamp.Date := DateDelta;
- end;
- else
- try
- TimeStamp := MSecsToTimeStamp(Data.DateTime);
- except
- TimeStamp.Time := 0;
- TimeStamp.Date := 0;
- end;
- end;
- Value := TimeStampToDateTime(TimeStamp);
- end;
- end;
-
- procedure TDateTimeField.SetAsDateTime(Value: TDateTime);
- var
- TimeStamp: TTimeStamp;
- Data: TDateTimeRec;
- begin
- TimeStamp := DateTimeToTimeStamp(Value);
- case DataType of
- ftDate: Data.Date := TimeStamp.Date;
- ftTime: Data.Time := TimeStamp.Time;
- else
- Data.DateTime := TimeStampToMSecs(TimeStamp);
- end;
- SetData(@Data);
- end;
-
- procedure TDateTimeField.SetAsFloat(Value: Double);
- begin
- SetAsDateTime(Value);
- end;
-
- procedure TDateTimeField.SetAsString(const Value: string);
- var
- DateTime: TDateTime;
- begin
- if Value = '' then Clear else
- begin
- case DataType of
- ftDate: DateTime := StrToDate(Value);
- ftTime: DateTime := StrToTime(Value);
- else
- DateTime := StrToDateTime(Value);
- end;
- SetAsDateTime(DateTime);
- end;
- end;
-
- procedure TDateTimeField.SetDisplayFormat(const Value: string);
- begin
- if FDisplayFormat <> Value then
- begin
- FDisplayFormat := Value;
- PropertyChanged(False);
- end;
- end;
-
- procedure TDateTimeField.SetVarValue(const Value: Variant);
- begin
- SetAsDateTime(VarToDateTime(Value));
- end;
-
- { TDateField }
-
- constructor TDateField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftDate);
- end;
-
- { TTimeField }
-
- constructor TTimeField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftTime);
- end;
-
- { TBinaryField }
-
- constructor TBinaryField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- end;
-
- function TBinaryField.GetAsVariant: Variant;
- var
- Data: Pointer;
- begin
- Result := VarArrayCreate([0, DataSize - 1], varByte);
- Data := VarArrayLock(Result);
- try
- GetData(Data);
- finally
- VarArrayUnlock(Result);
- end;
- end;
-
- procedure TBinaryField.SetVarValue(const Value: Variant);
- var
- Data: Pointer;
- begin
- if not (VarIsArray(Value) and (VarArrayDimCount(Value) = 1) and
- ((VarType(Value) and VarTypeMask) = varByte) and
- ((VarArrayHighBound(Value, 1) - VarArrayLowBound(Value, 1) + 1) = DataSize)) then
- DBError(SInvalidVarByteArray);
- Data := VarArrayLock(Value);
- try
- SetData(Data);
- finally
- VarArrayUnlock(Value);
- end;
- end;
-
- { TBytesField }
-
- constructor TBytesField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftBytes);
- Size := 16;
- end;
-
- { TVarBytesField }
-
- constructor TVarBytesField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftVarBytes);
- Size := 16;
- end;
-
- { TBlobField }
-
- constructor TBlobField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftBlob);
- end;
-
- procedure TBlobField.Assign(Source: TPersistent);
- begin
- if Source is TBlobField then
- begin
- LoadFromBlob(TBlobField(Source));
- Exit;
- end;
- if Source is TStrings then
- begin
- LoadFromStrings(TStrings(Source));
- Exit;
- end;
- if Source is TBitmap then
- begin
- LoadFromBitmap(TBitmap(Source));
- Exit;
- end;
- if (Source is TPicture) and (TPicture(Source).Graphic is TBitmap) then
- begin
- LoadFromBitmap(TBitmap(TPicture(Source).Graphic));
- Exit;
- end;
- inherited Assign(Source);
- end;
-
- procedure TBlobField.AssignTo(Dest: TPersistent);
- begin
- if Dest is TStrings then
- begin
- SaveToStrings(TStrings(Dest));
- Exit;
- end;
- if Dest is TBitmap then
- begin
- SaveToBitmap(TBitmap(Dest));
- Exit;
- end;
- if Dest is TPicture then
- begin
- SaveToBitmap(TPicture(Dest).Bitmap);
- Exit;
- end;
- inherited AssignTo(Dest);
- end;
-
- procedure TBlobField.Clear;
- begin
- TBlobStream.Create(Self, bmWrite).Free;
- end;
-
- procedure TBlobField.FreeBuffers;
- begin
- if FModified then
- begin
- DbiFreeBlob(DataSet.Handle, DataSet.ActiveBuffer, FieldNo);
- FModified := False;
- end;
- end;
-
- function TBlobField.GetAsString: string;
- var
- Len: Integer;
- begin
- with TBlobStream.Create(Self, bmRead) do
- try
- Len := Size;
- SetString(Result, nil, Len);
- ReadBuffer(Pointer(Result)^, Len);
- finally
- Free;
- end;
- end;
-
- function TBlobField.GetAsVariant: Variant;
- begin
- Result := GetAsString;
- end;
-
- function TBlobField.GetBlobType: TBlobType;
- begin
- Result := TBlobType(DataType);
- end;
-
- procedure TBlobField.GetText(var Text: string; DisplayText: Boolean);
- begin
- Text := inherited GetAsString;
- end;
-
- procedure TBlobField.LoadFromBitmap(Bitmap: TBitmap);
- var
- BlobStream: TBlobStream;
- Header: TGraphicHeader;
- begin
- BlobStream := TBlobStream.Create(Self, bmWrite);
- try
- if (DataType = ftGraphic) or (DataType = ftTypedBinary) then
- begin
- Header.Count := 1;
- Header.HType := $0100;
- Header.Size := 0;
- BlobStream.Write(Header, SizeOf(Header));
- Bitmap.SaveToStream(BlobStream);
- Header.Size := BlobStream.Position - SizeOf(Header);
- BlobStream.Position := 0;
- BlobStream.Write(Header, SizeOf(Header));
- end else
- Bitmap.SaveToStream(BlobStream);
- finally
- BlobStream.Free;
- end;
- end;
-
- procedure TBlobField.LoadFromBlob(Blob: TBlobField);
- var
- BlobStream: TBlobStream;
- begin
- BlobStream := TBlobStream.Create(Self, bmWrite);
- try
- Blob.SaveToStream(BlobStream);
- finally
- BlobStream.Free;
- end;
- end;
-
- procedure TBlobField.LoadFromFile(const FileName: string);
- var
- Stream: TStream;
- begin
- Stream := TFileStream.Create(FileName, fmOpenRead);
- try
- LoadFromStream(Stream);
- finally
- Stream.Free;
- end;
- end;
-
- procedure TBlobField.LoadFromStream(Stream: TStream);
- var
- BlobStream: TBlobStream;
- begin
- BlobStream := TBlobStream.Create(Self, bmWrite);
- try
- BlobStream.CopyFrom(Stream, 0);
- finally
- BlobStream.Free;
- end;
- end;
-
- procedure TBlobField.LoadFromStrings(Strings: TStrings);
- var
- BlobStream: TBlobStream;
- begin
- BlobStream := TBlobStream.Create(Self, bmWrite);
- try
- Strings.SaveToStream(BlobStream);
- finally
- BlobStream.Free;
- end;
- end;
-
- procedure TBlobField.SaveToBitmap(Bitmap: TBitmap);
- var
- BlobStream: TBlobStream;
- Size: Longint;
- Header: TGraphicHeader;
- begin
- BlobStream := TBlobStream.Create(Self, bmRead);
- try
- Size := BlobStream.Size;
- if Size >= SizeOf(TGraphicHeader) then
- begin
- BlobStream.Read(Header, SizeOf(Header));
- if (Header.Count <> 1) or (Header.HType <> $0100) or
- (Header.Size <> Size - SizeOf(Header)) then
- BlobStream.Position := 0;
- end;
- Bitmap.LoadFromStream(BlobStream);
- finally
- BlobStream.Free;
- end;
- end;
-
- procedure TBlobField.SaveToFile(const FileName: string);
- var
- Stream: TStream;
- begin
- Stream := TFileStream.Create(FileName, fmCreate);
- try
- SaveToStream(Stream);
- finally
- Stream.Free;
- end;
- end;
-
- procedure TBlobField.SaveToStream(Stream: TStream);
- var
- BlobStream: TBlobStream;
- begin
- BlobStream := TBlobStream.Create(Self, bmRead);
- try
- Stream.CopyFrom(BlobStream, 0);
- finally
- BlobStream.Free;
- end;
- end;
-
- procedure TBlobField.SaveToStrings(Strings: TStrings);
- var
- BlobStream: TBlobStream;
- begin
- BlobStream := TBlobStream.Create(Self, bmRead);
- try
- Strings.LoadFromStream(BlobStream);
- finally
- BlobStream.Free;
- end;
- end;
-
- procedure TBlobField.SetAsString(const Value: string);
- begin
- with TBlobStream.Create(Self, bmWrite) do
- try
- WriteBuffer(Pointer(Value)^, Length(Value));
- finally
- Free;
- end;
- end;
-
- procedure TBlobField.SetBlobType(Value: TBlobType);
- begin
- SetFieldType(Value);
- end;
-
- procedure TBlobField.SetFieldType(Value: TFieldType);
- begin
- if Value in [Low(TBlobType)..High(TBlobType)] then SetDataType(Value);
- end;
-
- procedure TBlobField.SetText(const Value: string);
- begin
- AccessError('Text');
- end;
-
- procedure TBlobField.SetVarValue(const Value: Variant);
- begin
- SetAsString(Value);
- end;
-
- { TMemoField }
-
- constructor TMemoField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftMemo);
- Transliterate := True;
- end;
-
- { TGraphicField }
-
- constructor TGraphicField.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetDataType(ftGraphic);
- end;
-
- { TBlobStream }
-
- constructor TBlobStream.Create(Field: TBlobField; Mode: TBlobStreamMode);
- var
- OpenMode: DbiOpenMode;
- begin
- FField := Field;
- FDataSet := Field.DataSet;
- FRecord := FDataSet.ActiveBuffer;
- FFieldNo := Field.FieldNo;
- if FDataSet.State = dsFilter then
- DBErrorFmt(SNoFieldAccess, [FField.DisplayName]);
- if not FField.FModified then
- begin
- if Mode = bmRead then
- begin
- FBuffer := AllocMem(FDataSet.RecordSize);
- FRecord := FBuffer;
- if not FDataSet.GetCurrentRecord(FBuffer) then Exit;
- OpenMode := dbiReadOnly;
- end else
- begin
- if not (FDataSet.State in [dsEdit, dsInsert]) then DBError(SNotEditing);
- OpenMode := dbiReadWrite;
- end;
- Check(DbiOpenBlob(FDataSet.Handle, FRecord, FFieldNo, OpenMode));
- end;
- FOpened := True;
- if Mode = bmWrite then Truncate;
- end;
-
- destructor TBlobStream.Destroy;
- begin
- if FOpened then
- begin
- if FModified then FField.FModified := True;
- if not FField.FModified then
- DbiFreeBlob(FDataSet.Handle, FRecord, FFieldNo);
- end;
- if FBuffer <> nil then FreeMem(FBuffer, FDataSet.RecordSize);
- if FModified then
- try
- FField.DataChanged;
- except
- Application.HandleException(Self);
- end;
- end;
-
- function TBlobStream.Read(var Buffer; Count: Longint): Longint;
- var
- Status: DBIResult;
- begin
- Result := 0;
- if FOpened then
- begin
- Status := DbiGetBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,
- Count, @Buffer, Result);
- case Status of
- DBIERR_NONE, DBIERR_ENDOFBLOB:
- begin
- if FField.FTransliterate then
- NativeToAnsiBuf(FDataSet.Locale, @Buffer, @Buffer, Result);
- Inc(FPosition, Result);
- end;
- DBIERR_INVALIDBLOBOFFSET:
- {Nothing};
- else
- DbiError(Status);
- end;
- end;
- end;
-
- function TBlobStream.Write(const Buffer; Count: Longint): Longint;
- var
- Temp: Pointer;
- begin
- Result := 0;
- if FOpened then
- begin
- if FField.FTransliterate then
- begin
- GetMem(Temp, Count);
- try
- AnsiToNativeBuf(FDataSet.Locale, @Buffer, Temp, Count);
- Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,
- Count, Temp));
- finally
- FreeMem(Temp, Count);
- end;
- end else
- Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,
- Count, @Buffer));
- Inc(FPosition, Count);
- Result := Count;
- FModified := True;
- end;
- end;
-
- function TBlobStream.Seek(Offset: Longint; Origin: Word): Longint;
- begin
- case Origin of
- 0: FPosition := Offset;
- 1: Inc(FPosition, Offset);
- 2: FPosition := GetBlobSize + Offset;
- end;
- Result := FPosition;
- end;
-
- procedure TBlobStream.Truncate;
- begin
- if FOpened then
- begin
- Check(DbiTruncateBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition));
- FModified := True;
- end;
- end;
-
- function TBlobStream.GetBlobSize: Longint;
- begin
- Result := 0;
- if FOpened then
- Check(DbiGetBlobSize(FDataSet.Handle, FRecord, FFieldNo, Result));
- end;
-
- { TFieldDataLink }
-
- procedure TFieldDataLink.SetEditing(Value: Boolean);
- begin
- if FEditing <> Value then
- begin
- FEditing := Value;
- FModified := False;
- if Assigned(FOnEditingChange) then FOnEditingChange(Self);
- end;
- end;
-
- procedure TFieldDataLink.SetFieldName(const Value: string);
- begin
- if FFieldName <> Value then
- begin
- FFieldName := Value;
- UpdateField;
- end;
- end;
-
- procedure TFieldDataLink.SetField(Value: TField);
- begin
- if FField <> Value then
- begin
- FField := Value;
- EditingChanged;
- RecordChanged(nil);
- end;
- end;
-
- procedure TFieldDataLink.UpdateField;
- begin
- SetField(nil);
- if Active and (FFieldName <> '') then
- SetField(DataSource.DataSet.FieldByName(FFieldName));
- end;
-
- function TFieldDataLink.Edit: Boolean;
- begin
- if CanModify then inherited Edit;
- Result := FEditing;
- end;
-
- function TFieldDataLink.GetCanModify: Boolean;
- begin
- Result := not ReadOnly and (Field <> nil) and Field.CanModify;
- end;
-
- procedure TFieldDataLink.Modified;
- begin
- FModified := True;
- end;
-
- procedure TFieldDataLink.Reset;
- begin
- RecordChanged(nil);
- end;
-
- procedure TFieldDataLink.ActiveChanged;
- begin
- UpdateField;
- if Assigned(FOnActiveChange) then FOnActiveChange(Self);
- end;
-
- procedure TFieldDataLink.EditingChanged;
- begin
- SetEditing(inherited Editing and CanModify);
- end;
-
- procedure TFieldDataLink.FocusControl(Field: TFieldRef);
- begin
- if (Field^ <> nil) and (Field^ = FField) and (FControl <> nil) and
- FControl.CanFocus then
- begin
- Field^ := nil;
- FControl.SetFocus;
- end;
- end;
-
- procedure TFieldDataLink.RecordChanged(Field: TField);
- begin
- if (Field = nil) or (Field = FField) then
- begin
- if Assigned(FOnDataChange) then FOnDataChange(Self);
- FModified := False;
- end;
- end;
-
- procedure TFieldDataLink.LayoutChanged;
- begin
- UpdateField;
- end;
-
- procedure TFieldDataLink.UpdateData;
- begin
- if FModified then
- begin
- if (Field <> nil) and Assigned(FOnUpdateData) then FOnUpdateData(Self);
- FModified := False;
- end;
- end;
-
- end.
-