home *** CD-ROM | disk | FTP | other *** search
-
- {*******************************************************}
- { }
- { Borland Delphi Visual Component Library }
- { BDE Data Access }
- { }
- { Copyright (c) 1995,99 Inprise Corporation }
- { }
- {*******************************************************}
-
- unit DBTables;
-
- {$R-,T-,H+,X+}
-
- interface
-
- uses Windows, SysUtils, Graphics, Classes, Controls, Db, DBCommon, Bde, SMIntf;
-
- const
-
- { SQL Trace buffer size }
-
- smTraceBufSize = 32767 + SizeOf(TraceDesc);
-
- { TDBDataSet flags }
-
- dbfOpened = 0;
- dbfPrepared = 1;
- dbfExecSQL = 2;
- dbfTable = 3;
- dbfFieldList = 4;
- dbfIndexList = 5;
- dbfStoredProc = 6;
- dbfExecProc = 7;
- dbfProcDesc = 8;
- dbfDatabase = 9;
- dbfProvider = 10;
-
- { FieldType Mappings }
-
- const
- FldTypeMap: TFieldMap = (
- fldUNKNOWN, fldZSTRING, fldINT16, fldINT32, fldUINT16, fldBOOL,
- fldFLOAT, fldFLOAT, fldBCD, fldDATE, fldTIME, fldTIMESTAMP, fldBYTES,
- fldVARBYTES, fldINT32, fldBLOB, fldBLOB, fldBLOB, fldBLOB, fldBLOB,
- fldBLOB, fldBLOB, fldCURSOR, fldZSTRING, fldZSTRING, fldINT64, fldADT,
- fldArray, fldREF, fldTABLE, fldBLOB, fldBLOB, fldUNKNOWN, fldUNKNOWN,
- fldUNKNOWN, fldZSTRING);
-
- FldSubTypeMap: array[TFieldType] of Word = (
- 0, 0, 0, 0, 0, 0, 0, fldstMONEY, 0, 0, 0, 0, 0, 0, fldstAUTOINC,
- fldstBINARY, fldstMEMO, fldstGRAPHIC, fldstFMTMEMO, fldstOLEOBJ,
- fldstDBSOLEOBJ, fldstTYPEDBINARY, 0, fldstFIXED, fldstUNICODE,
- 0, 0, 0, 0, 0, fldstHBINARY, fldstHMEMO, 0, 0, 0, 0);
-
- DataTypeMap: array[0..MAXLOGFLDTYPES - 1] of TFieldType = (
- ftUnknown, ftString, ftDate, ftBlob, ftBoolean, ftSmallint,
- ftInteger, ftFloat, ftBCD, ftBytes, ftTime, ftDateTime,
- ftWord, ftInteger, ftUnknown, ftVarBytes, ftUnknown, ftUnknown,
- ftLargeInt, ftLargeInt, ftADT, ftArray, ftReference, ftDataSet);
-
- BlobTypeMap: array[fldstMEMO..fldstBFILE] of TFieldType = (
- ftMemo, ftBlob, ftFmtMemo, ftParadoxOle, ftGraphic, ftDBaseOle,
- ftTypedBinary, ftBlob, ftBlob, ftBlob, ftBlob, ftOraClob, ftOraBlob,
- ftBlob, ftBlob);
-
- type
-
- { Forward declarations }
-
- TDBError = class;
- TSession = class;
- TDatabase = class;
- TBDEDataSet = class;
- TDBDataSet = class;
- TTable = class;
-
- { Exception classes }
-
- EDBEngineError = class(EDatabaseError)
- private
- FErrors: TList;
- function GetError(Index: Integer): TDBError;
- function GetErrorCount: Integer;
- public
- constructor Create(ErrorCode: DBIResult);
- destructor Destroy; override;
- property ErrorCount: Integer read GetErrorCount;
- property Errors[Index: Integer]: TDBError read GetError;
- end;
-
- ENoResultSet = class(EDatabaseError);
-
- { BDE error information type }
-
- TDBError = class
- private
- FErrorCode: DBIResult;
- FNativeError: Longint;
- FMessage: string;
- function GetCategory: Byte;
- function GetSubCode: Byte;
- public
- constructor Create(Owner: EDBEngineError; ErrorCode: DBIResult;
- NativeError: Longint; Message: PChar);
- property Category: Byte read GetCategory;
- property ErrorCode: DBIResult read FErrorCode;
- property SubCode: Byte read GetSubCode;
- property Message: string read FMessage;
- property NativeError: Longint read FNativeError;
- end;
-
- { TLocale }
-
- TLocale = Pointer;
-
- { TBDECallback }
-
- TBDECallbackEvent = function(CBInfo: Pointer): CBRType of Object;
-
- TBDECallback = class
- private
- FHandle: hDBICur;
- FOwner: TObject;
- FCBType: CBType;
- FOldCBData: Longint;
- FOldCBBuf: Pointer;
- FOldCBBufLen: Word;
- FOldCBFunc: pfDBICallBack;
- FInstalled: Boolean;
- FCallbackEvent: TBDECallbackEvent;
- protected
- function Invoke(CallType: CBType; CBInfo: Pointer): CBRType;
- public
- constructor Create(AOwner: TObject; Handle: hDBICur; CBType: CBType;
- CBBuf: Pointer; CBBufSize: Integer; CallbackEvent: TBDECallbackEvent;
- Chain: Boolean);
- destructor Destroy; override;
- end;
-
- { TSessionList }
-
- TSessionList = class(TObject)
- private
- FSessions: TThreadList;
- FSessionNumbers: TBits;
- procedure AddSession(ASession: TSession);
- procedure CloseAll;
- function GetCount: Integer;
- function GetSession(Index: Integer): TSession;
- function GetCurrentSession: TSession;
- function GetSessionByName(const SessionName: string): TSession;
- procedure SetCurrentSession(Value: TSession);
- public
- constructor Create;
- destructor Destroy; override;
- property CurrentSession: TSession read GetCurrentSession write SetCurrentSession;
- function FindSession(const SessionName: string): TSession;
- procedure GetSessionNames(List: TStrings);
- function OpenSession(const SessionName: string): TSession;
- property Count: Integer read GetCount;
- property Sessions[Index: Integer]: TSession read GetSession; default;
- property List[const SessionName: string]: TSession read GetSessionByName;
- end;
-
- { TSession }
-
- TConfigModes = (cfmVirtual, cfmPersistent, cfmSession);
- TConfigMode = set of TConfigModes;
-
- TPasswordEvent = procedure(Sender: TObject; var Continue: Boolean) of Object;
-
- TDatabaseEvent = (dbOpen, dbClose, dbAdd, dbRemove, dbAddAlias, dbDeleteAlias,
- dbAddDriver, dbDeleteDriver);
-
- TDatabaseNotifyEvent = procedure(DBEvent: TDatabaseEvent; const Param) of object;
-
- TBDEInitProc = procedure(Session: TSession);
-
- TTraceFlag = (tfQPrepare, tfQExecute, tfError, tfStmt, tfConnect,
- tfTransact, tfBlob, tfMisc, tfVendor, tfDataIn, tfDataOut);
-
- TTraceFlags = set of TTraceFlag;
-
- TSession = class(TComponent)
- private
- FHandle: HDBISes;
- FDatabases: TList;
- FCallbacks: TList;
- FLocale: TLocale;
- FSMClient: ISMClient;
- FSMBuffer: PTraceDesc;
- FTraceFlags: TTraceFlags;
- FSMLoadFailed: Boolean;
- FStreamedActive: Boolean;
- FKeepConnections: Boolean;
- FDefault: Boolean;
- FSQLHourGlass: Boolean;
- FAutoSessionName: Boolean;
- FUpdatingAutoSessionName: Boolean;
- FDLLDetach: Boolean;
- FBDEOwnsLoginCbDb: Boolean;
- FSessionName: string;
- FSessionNumber: Integer;
- FNetFileDir: string;
- FPrivateDir: string;
- FCBSCType: CBSCType;
- FLockCount: Integer;
- FReserved: Integer;
- FCBDBLogin: TCBDBLogin;
- FOnPassword: TPasswordEvent;
- FOnStartup: TNotifyEvent;
- FOnDBNotify: TDatabaseNotifyEvent;
- procedure AddDatabase(Value: TDatabase);
- procedure CallBDEInitProcs;
- procedure CheckInactive;
- procedure CheckConfigMode(CfgMode: TConfigMode);
- procedure CloseDatabaseHandle(Database: TDatabase);
- function DBLoginCallback(CBInfo: Pointer): CBRType;
- procedure DBNotification(DBEvent: TDatabaseEvent; const Param);
- procedure DeleteConfigPath(const Path, Node: string);
- function DoFindDatabase(const DatabaseName: string; AOwner: TComponent): TDatabase;
- function DoOpenDatabase(const DatabaseName: string; AOwner: TComponent): TDatabase;
- function FindDatabaseHandle(const DatabaseName: string): HDBIDB;
- function GetActive: Boolean;
- function GetConfigMode: TConfigMode;
- function GetDatabase(Index: Integer): TDatabase;
- function GetDatabaseCount: Integer;
- function GetHandle: HDBISes;
- function GetNetFileDir: string;
- function GetPrivateDir: string;
- procedure InitializeBDE;
- procedure InternalAddAlias(const Name, Driver: string; List: TStrings;
- CfgMode: TConfigMode; RestoreMode: Boolean);
- procedure InternalDeleteAlias(const Name: string; CfgMode: TConfigMode;
- RestoreMode: Boolean);
- function SessionNameStored: Boolean;
- procedure LoadSMClient(DesignTime: Boolean);
- procedure LockSession;
- procedure MakeCurrent;
- procedure RegisterCallbacks(Value: Boolean);
- procedure RemoveDatabase(Value: TDatabase);
- function ServerCallback(CBInfo: Pointer): CBRType;
- procedure SetActive(Value: Boolean);
- procedure SetAutoSessionName(Value: Boolean);
- procedure SetConfigMode(Value: TConfigMode);
- procedure SetConfigParams(const Path, Node: string; List: TStrings);
- procedure SetNetFileDir(const Value: string);
- procedure SetPrivateDir(const Value: string);
- procedure SetSessionName(const Value: string);
- procedure SetSessionNames;
- procedure SetTraceFlags(Value: TTraceFlags);
- procedure SMClientSignal(Sender: TObject; Data: Integer);
- function SqlTraceCallback(CBInfo: Pointer): CBRType;
- procedure StartSession(Value: Boolean);
- procedure UnlockSession;
- procedure UpdateAutoSessionName;
- procedure ValidateAutoSession(AOwner: TComponent; AllSessions: Boolean);
- protected
- procedure Loaded; override;
- procedure ModifyConfigParams(const Path, Node: string; List: TStrings);
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- property OnDBNotify: TDatabaseNotifyEvent read FOnDBNotify write FOnDBNotify;
- property BDEOwnsLoginCbDb: Boolean read FBDEOwnsLoginCbDb write FBDEOwnsLoginCbDb;
- procedure SetName(const NewName: TComponentName); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure AddAlias(const Name, Driver: string; List: TStrings);
- procedure AddDriver(const Name: string; List: TStrings);
- procedure AddStandardAlias(const Name, Path, DefaultDriver: string);
- property ConfigMode: TConfigMode read GetConfigMode write SetConfigMode;
- procedure AddPassword(const Password: string);
- procedure Close;
- procedure CloseDatabase(Database: TDatabase);
- procedure DeleteAlias(const Name: string);
- procedure DeleteDriver(const Name: string);
- procedure DropConnections;
- function FindDatabase(const DatabaseName: string): TDatabase;
- procedure GetAliasNames(List: TStrings);
- procedure GetAliasParams(const AliasName: string; List: TStrings);
- function GetAliasDriverName(const AliasName: string): string;
- procedure GetConfigParams(const Path, Section: string; List: TStrings);
- procedure GetDatabaseNames(List: TStrings);
- procedure GetDriverNames(List: TStrings);
- procedure GetDriverParams(const DriverName: string; List: TStrings);
- function GetPassword: Boolean;
- procedure GetTableNames(const DatabaseName, Pattern: string;
- Extensions, SystemTables: Boolean; List: TStrings);
- procedure GetStoredProcNames(const DatabaseName: string; List: TStrings);
- function IsAlias(const Name: string): Boolean;
- procedure ModifyAlias(Name: string; List: TStrings);
- procedure ModifyDriver(Name: string; List: TStrings);
- procedure Open;
- function OpenDatabase(const DatabaseName: string): TDatabase;
- procedure RemoveAllPasswords;
- procedure RemovePassword(const Password: string);
- procedure SaveConfigFile;
- property DatabaseCount: Integer read GetDatabaseCount;
- property Databases[Index: Integer]: TDatabase read GetDatabase;
- property Handle: HDBISES read GetHandle;
- property Locale: TLocale read FLocale;
- property TraceFlags: TTraceFlags read FTraceFlags write SetTraceFlags;
- published
- property Active: Boolean read GetActive write SetActive default False;
- property AutoSessionName: Boolean read FAutoSessionName write SetAutoSessionName default False;
- property KeepConnections: Boolean read FKeepConnections write FKeepConnections default True;
- property NetFileDir: string read GetNetFileDir write SetNetFileDir;
- property PrivateDir: string read GetPrivateDir write SetPrivateDir;
- property SessionName: string read FSessionName write SetSessionName stored SessionNameStored;
- property SQLHourGlass: Boolean read FSQLHourGlass write FSQLHourGlass default True;
- property OnPassword: TPasswordEvent read FOnPassword write FOnPassword;
- property OnStartup: TNotifyEvent read FOnStartup write FOnStartup;
- end;
-
- { TParamList }
-
- TFieldDescList = array of FLDDesc;
-
- TParamList = class(TObject)
- private
- FFieldCount: Integer;
- FFieldDescs: TFieldDescList;
- FBuffer: PChar;
- FBufSize: Word;
- public
- constructor Create(Params: TStrings);
- destructor Destroy; override;
- property Buffer: PChar read FBuffer;
- property FieldCount: Integer read FFieldCount;
- property FieldDescs: TFieldDescList read FFieldDescs;
- end;
-
- { TDatabase }
-
- TTransIsolation = (tiDirtyRead, tiReadCommitted, tiRepeatableRead);
-
- TDatabaseLoginEvent = procedure(Database: TDatabase;
- LoginParams: TStrings) of object;
-
- TDatabase = class(TCustomConnection)
- private
- FTransIsolation: TTransIsolation;
- FKeepConnection: Boolean;
- FTemporary: Boolean;
- FSessionAlias: Boolean;
- FLocaleLoaded: Boolean;
- FAliased: Boolean;
- FSQLBased: Boolean;
- FAcquiredHandle: Boolean;
- FPseudoIndexes: Boolean;
- FHandleShared: Boolean;
- FExclusive: Boolean;
- FReadOnly: Boolean;
- FRefCount: Integer;
- FHandle: HDBIDB;
- FLocale: TLocale;
- FSession: TSession;
- FParams: TStrings;
- FStmtList: TList;
- FSessionName: string;
- FDatabaseName: string;
- FDatabaseType: string;
- FOnLogin: TDatabaseLoginEvent;
- procedure CheckActive;
- procedure CheckInactive;
- procedure CheckDatabaseName;
- procedure CheckDatabaseAlias(var Password: string);
- procedure CheckSessionName(Required: Boolean);
- procedure ClearStatements;
- procedure EndTransaction(TransEnd: EXEnd);
- function GetAliasName: string;
- function GetDirectory: string;
- function GetDriverName: string;
- function GetInTransaction: Boolean;
- function GetObjectContext: IUnknown;
- function GetTraceFlags: TTraceFlags;
- procedure LoadLocale;
- procedure Login(LoginParams: TStrings);
- function OpenFromExistingDB: Boolean;
- procedure ParamsChanging(Sender: TObject);
- procedure SetAliasName(const Value: string);
- procedure SetDatabaseFlags;
- procedure SetDatabaseName(const Value: string);
- procedure SetDatabaseType(const Value: string; Aliased: Boolean);
- procedure SetDirectory(const Value: string);
- procedure SetDriverName(const Value: string);
- procedure SetExclusive(Value: Boolean);
- procedure SetHandle(Value: HDBIDB);
- procedure SetKeepConnection(Value: Boolean);
- procedure SetParams(Value: TStrings);
- procedure SetReadOnly(Value: Boolean);
- procedure SetTraceFlags(Value: TTraceFlags);
- procedure SetSessionName(const Value: string);
- protected
- procedure DoConnect; override;
- procedure DoDisconnect; override;
- function GetConnected: Boolean; override;
- function GetDataSet(Index: Integer): TDBDataSet; reintroduce;
- procedure Loaded; override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure ApplyUpdates(const DataSets: array of TDBDataSet);
- procedure CloseDataSets;
- procedure Commit;
- function Execute(const SQL: string; Params: TParams = nil;
- Cache: Boolean = False; Cursor: phDBICur = nil): Integer;
- procedure FlushSchemaCache(const TableName: string);
- procedure Rollback;
- procedure StartTransaction;
- procedure ValidateName(const Name: string);
- property DataSets[Index: Integer]: TDBDataSet read GetDataSet;
- property Directory: string read GetDirectory write SetDirectory;
- property Handle: HDBIDB read FHandle write SetHandle;
- property IsSQLBased: Boolean read FSQLBased;
- property InTransaction: Boolean read GetInTransaction;
- property Locale: TLocale read FLocale;
- property Session: TSession read FSession;
- property Temporary: Boolean read FTemporary write FTemporary;
- property SessionAlias: Boolean read FSessionAlias;
- property TraceFlags: TTraceFlags read GetTraceFlags write SetTraceFlags;
- published
- property AliasName: string read GetAliasName write SetAliasName;
- property Connected;
- property DatabaseName: string read FDatabaseName write SetDatabaseName;
- property DriverName: string read GetDriverName write SetDriverName;
- property Exclusive: Boolean read FExclusive write SetExclusive default False;
- property HandleShared: Boolean read FHandleShared write FHandleShared default False;
- property KeepConnection: Boolean read FKeepConnection write SetKeepConnection default True;
- property LoginPrompt default True;
- property Params: TStrings read FParams write SetParams;
- property ReadOnly: Boolean read FReadOnly write SetReadOnly default False;
- property SessionName: string read FSessionName write SetSessionName;
- property TransIsolation: TTransIsolation read FTransIsolation write FTransIsolation default tiReadCommitted;
- property AfterConnect;
- property AfterDisconnect;
- property BeforeConnect;
- property BeforeDisconnect;
- property OnLogin: TDatabaseLoginEvent read FOnLogin write FOnLogin;
- end;
-
- { TBDEDataSet }
-
- TRecNoStatus = (rnDbase, rnParadox, rnNotSupported);
-
- TDataSetUpdateObject = class(TComponent)
- protected
- function GetDataSet: TBDEDataSet; virtual; abstract;
- procedure SetDataSet(ADataSet: TBDEDataSet); virtual; abstract;
- procedure Apply(UpdateKind: TUpdateKind); virtual; abstract;
- property DataSet: TBDEDataSet read GetDataSet write SetDataSet;
- end;
-
- TSQLUpdateObject = class(TDataSetUpdateObject)
- protected
- function GetSQL(UpdateKind: TUpdateKind): TStrings; virtual; abstract;
- end;
-
- TKeyIndex = (kiLookup, kiRangeStart, kiRangeEnd, kiCurRangeStart,
- kiCurRangeEnd, kiSave);
-
- PKeyBuffer = ^TKeyBuffer;
- TKeyBuffer = packed record
- Modified: Boolean;
- Exclusive: Boolean;
- FieldCount: Integer;
- end;
-
- PRecInfo = ^TRecInfo;
- TRecInfo = packed record
- RecordNumber: Longint;
- UpdateStatus: TUpdateStatus;
- BookmarkFlag: TBookmarkFlag;
- end;
-
- TBlobDataArray = array of TBlobData;
-
- TBDEDataSet = class(TDataSet)
- private
- FHandle: HDBICur;
- FStmtHandle: HDBIStmt;
- FRecProps: RecProps;
- FLocale: TLocale;
- FExprFilter: HDBIFilter;
- FFuncFilter: HDBIFilter;
- FFilterBuffer: PChar;
- FIndexFieldMap: DBIKey;
- FExpIndex: Boolean;
- FCaseInsIndex: Boolean;
- FCachedUpdates: Boolean;
- FInUpdateCallback: Boolean;
- FCanModify: Boolean;
- FCacheBlobs: Boolean;
- FKeySize: Word;
- FUpdateCBBuf: PDELAYUPDCbDesc;
- FUpdateCallback: TBDECallback;
- FKeyBuffers: array[TKeyIndex] of PKeyBuffer;
- FKeyBuffer: PKeyBuffer;
- FRecNoStatus: TRecNoStatus;
- FIndexFieldCount: Integer;
- FConstDisableCount: Integer;
- FRecordSize: Word;
- FBookmarkOfs: Word;
- FRecInfoOfs: Word;
- FBlobCacheOfs: Word;
- FRecBufSize: Word;
- FConstraintLayer: Boolean;
- FBlockBufSize: Integer;
- FBlockBufOfs: Integer;
- FBlockBufCount: Integer;
- FBlockReadCount: Integer;
- FLastParentPos: Integer;
- FBlockReadBuf: PChar;
- FParentDataSet: TBDEDataSet;
- FUpdateObject: TDataSetUpdateObject;
- FOnUpdateError: TUpdateErrorEvent;
- FOnUpdateRecord: TUpdateRecordEvent;
- procedure ClearBlobCache(Buffer: PChar);
- function GetActiveRecBuf(var RecBuf: PChar): Boolean;
- function GetBlobData(Field: TField; Buffer: PChar): TBlobData;
- function GetOldRecord: PChar;
- procedure InitBufferPointers(GetProps: Boolean);
- function RecordFilter(RecBuf: Pointer; RecNo: Integer): Smallint; stdcall;
- procedure SetBlobData(Field: TField; Buffer: PChar; Value: TBlobData);
- function HasConstraints: Boolean;
- protected
- { IProviderSupport }
- function PSGetUpdateException(E: Exception; Prev: EUpdateError): EUpdateError; override;
- function PSIsSQLSupported: Boolean; override;
- procedure PSReset; override;
- function PSUpdateRecord(UpdateKind: TUpdateKind; Delta: TDataSet): Boolean; override;
- protected
- procedure ActivateFilters;
- procedure AddFieldDesc(FieldDescs: TFieldDescList; var DescNo: Integer;
- var FieldID: Integer; RequiredFields: TBits; FieldDefs: TFieldDefs);
- procedure AllocCachedUpdateBuffers(Allocate: Boolean);
- procedure AllocKeyBuffers;
- function AllocRecordBuffer: PChar; override;
- function CachedUpdateCallBack(CBInfo: Pointer): CBRType;
- procedure CheckCachedUpdateMode;
- procedure CheckSetKeyMode;
- procedure ClearCalcFields(Buffer: PChar); override;
- procedure CloseCursor; override;
- procedure CloseBlob(Field: TField); override;
- function CreateExprFilter(const Expr: string;
- Options: TFilterOptions; Priority: Integer): HDBIFilter;
- function CreateFuncFilter(FilterFunc: Pointer;
- Priority: Integer): HDBIFilter;
- function CreateHandle: HDBICur; virtual;
- function CreateLookupFilter(Fields: TList; const Values: Variant;
- Options: TLocateOptions; Priority: Integer): HDBIFilter;
- procedure DataEvent(Event: TDataEvent; Info: Longint); override;
- procedure DeactivateFilters;
- procedure DestroyHandle; virtual;
- procedure DestroyLookupCursor; virtual;
- function FindRecord(Restart, GoForward: Boolean): Boolean; override;
- function ForceUpdateCallback: Boolean;
- procedure FreeKeyBuffers;
- procedure FreeRecordBuffer(var Buffer: PChar); override;
- procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
- function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
- function GetCanModify: Boolean; override;
- function GetFieldFullName(Field: TField): string; override;
- function GetIndexField(Index: Integer): TField;
- function GetIndexFieldCount: Integer;
- function GetIsIndexField(Field: TField): Boolean; override;
- function GetKeyBuffer(KeyIndex: TKeyIndex): PKeyBuffer;
- function GetKeyExclusive: Boolean;
- function GetKeyFieldCount: Integer;
- function GetLookupCursor(const KeyFields: string;
- CaseInsensitive: Boolean): HDBICur; virtual;
- function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
- function GetRecordCount: Integer; override;
- function GetRecNo: Integer; override;
- function GetRecordSize: Word; override;
- function GetStateFieldValue(State: TDataSetState; Field: TField): Variant; override;
- procedure GetObjectTypeNames(Fields: TFields);
- function GetUpdatesPending: Boolean;
- function GetUpdateRecordSet: TUpdateRecordTypes;
- function InitKeyBuffer(Buffer: PKeyBuffer): PKeyBuffer;
- procedure InitRecord(Buffer: PChar); override;
- procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override;
- procedure InternalCancel; override;
- procedure InternalClose; override;
- procedure InternalDelete; override;
- procedure InternalEdit; override;
- procedure InternalFirst; override;
- procedure InternalGotoBookmark(Bookmark: TBookmark); override;
- procedure InternalHandleException; override;
- procedure InternalInitFieldDefs; override;
- procedure InternalInitRecord(Buffer: PChar); override;
- procedure InternalInsert; override;
- procedure InternalLast; override;
- procedure InternalOpen; override;
- procedure InternalPost; override;
- procedure InternalRefresh; override;
- procedure InternalSetToRecord(Buffer: PChar); override;
- function IsCursorOpen: Boolean; override;
- function LocateRecord(const KeyFields: string; const KeyValues: Variant;
- Options: TLocateOptions; SyncCursor: Boolean): Boolean;
- function MapsToIndex(Fields: TList; CaseInsensitive: Boolean): Boolean;
- procedure OpenCursor(InfoQuery: Boolean); override;
- procedure PostKeyBuffer(Commit: Boolean);
- procedure PrepareCursor; virtual;
- function ProcessUpdates(UpdCmd: DBIDelayedUpdCmd): DBIResult;
- function ResetCursorRange: Boolean;
- procedure BlockReadNext; override;
- procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;
- procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
- procedure SetCachedUpdates(Value: Boolean);
- function SetCursorRange: Boolean;
- procedure SetBlockReadSize(Value: Integer); override;
- procedure SetFieldData(Field: TField; Buffer: Pointer); override;
- procedure SetFilterData(const Text: string; Options: TFilterOptions);
- procedure SetFilterHandle(var Filter: HDBIFilter; Value: HDBIFilter);
- procedure SetFiltered(Value: Boolean); override;
- procedure SetFilterOptions(Value: TFilterOptions); override;
- procedure SetFilterText(const Value: string); override;
- procedure SetIndexField(Index: Integer; Value: TField);
- procedure SetKeyBuffer(KeyIndex: TKeyIndex; Clear: Boolean);
- procedure SetKeyExclusive(Value: Boolean);
- procedure SetKeyFieldCount(Value: Integer);
- procedure SetKeyFields(KeyIndex: TKeyIndex; const Values: array of const);
- procedure SetLinkRanges(MasterFields: TList);
- procedure SetLocale(Value: TLocale);
- procedure SetStateFieldValue(State: TDataSetState; Field: TField; const Value: Variant); override;
- procedure SetOnFilterRecord(const Value: TFilterRecordEvent); override;
- procedure SetOnUpdateError(UpdateEvent: TUpdateErrorEvent);
- procedure SetRecNo(Value: Integer); override;
- procedure SetupCallBack(Value: Boolean);
- procedure SetUpdateRecordSet(RecordTypes: TUpdateRecordTypes);
- procedure SetUpdateObject(Value: TDataSetUpdateObject);
- procedure SwitchToIndex(const IndexName, TagName: string);
- function UpdateCallbackRequired: Boolean;
- property StmtHandle: HDBIStmt read FStmtHandle write FStmtHandle;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure ApplyUpdates;
- function BookmarkValid(Bookmark: TBookmark): Boolean; override;
- procedure Cancel; override;
- procedure CancelUpdates;
- property CacheBlobs: Boolean read FCacheBlobs write FCacheBlobs default True;
- function CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Integer; override;
- procedure CommitUpdates;
- function ConstraintCallBack(Req: DsInfoReq; var ADataSources: DataSources): DBIResult; stdcall;
- function ConstraintsDisabled: Boolean;
- function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
- procedure DisableConstraints;
- procedure EnableConstraints;
- procedure FetchAll;
- procedure FlushBuffers;
- function GetCurrentRecord(Buffer: PChar): Boolean; override;
- function GetBlobFieldData(FieldNo: Integer; var Buffer: TBlobByteData): Integer; override;
- function GetFieldData(Field: TField; Buffer: Pointer): Boolean; overload; override;
- function GetFieldData(FieldNo: Integer; Buffer: Pointer): Boolean; overload; override;
- procedure GetIndexInfo;
- function Locate(const KeyFields: string; const KeyValues: Variant;
- Options: TLocateOptions): Boolean; override;
- function Lookup(const KeyFields: string; const KeyValues: Variant;
- const ResultFields: string): Variant; override;
- function IsSequenced: Boolean; override;
- procedure Post; override;
- procedure RevertRecord;
- function UpdateStatus: TUpdateStatus; override;
- function Translate(Src, Dest: PChar; ToOem: Boolean): Integer; override;
- property ExpIndex: Boolean read FExpIndex;
- property Handle: HDBICur read FHandle;
- property KeySize: Word read FKeySize;
- property Locale: TLocale read FLocale;
- property UpdateObject: TDataSetUpdateObject read FUpdateObject write SetUpdateObject;
- property UpdatesPending: Boolean read GetUpdatesPending;
- property UpdateRecordTypes: TUpdateRecordTypes read GetUpdateRecordSet write SetUpdateRecordSet;
- published
- property Active;
- property AutoCalcFields;
- property CachedUpdates: Boolean read FCachedUpdates write SetCachedUpdates default False;
- property ObjectView default False;
- property BeforeOpen;
- property AfterOpen;
- property BeforeClose;
- property AfterClose;
- property BeforeInsert;
- property AfterInsert;
- property BeforeEdit;
- property AfterEdit;
- property BeforePost;
- property AfterPost;
- property BeforeCancel;
- property AfterCancel;
- property BeforeDelete;
- property AfterDelete;
- property BeforeScroll;
- property AfterScroll;
- property BeforeRefresh;
- property AfterRefresh;
- property OnCalcFields;
- property OnDeleteError;
- property OnEditError;
- property OnNewRecord;
- property OnPostError;
- property OnUpdateError: TUpdateErrorEvent read FOnUpdateError write SetOnUpdateError;
- property OnUpdateRecord: TUpdateRecordEvent read FOnUpdateRecord write FOnUpdateRecord;
- end;
-
- { TNestedTable }
-
- TNestedTable = class(TBDEDataSet)
- protected
- function CreateHandle: HDBICur; override;
- procedure DoAfterPost; override;
- procedure DoBeforeInsert; override;
- procedure InternalPost; override;
- public
- constructor Create(AOwner: TComponent); override;
- published
- property DataSetField;
- property ObjectView default True;
- end;
-
- { TDBDataSet }
-
- TDBFlags = set of 0..15;
-
- TDBDataSet = class(TBDEDataSet)
- private
- FAutoRefresh: Boolean;
- FDBFlags: TDBFlags;
- FUpdateMode: TUpdateMode;
- FDatabase: TDatabase;
- FDatabaseName: string;
- FSessionName: string;
- procedure CheckDBSessionName;
- function GetDBHandle: HDBIDB;
- function GetDBLocale: TLocale;
- function GetDBSession: TSession;
- procedure SetDatabaseName(const Value: string);
- procedure SetSessionName(const Value: string);
- procedure SetUpdateMode(const Value: TUpdateMode);
- procedure SetAutoRefresh(const Value: Boolean);
- procedure SetupAutoRefresh;
- protected
- { IProviderSupport }
- procedure PSEndTransaction(Commit: Boolean); override;
- function PSExecuteStatement(const ASQL: string; AParams: TParams;
- ResultSet: Pointer = nil): Integer; override;
- procedure PSGetAttributes(List: TList); override;
- function PSGetQuoteChar: string; override;
- function PSInTransaction: Boolean; override;
- function PSIsSQLBased: Boolean; override;
- procedure PSStartTransaction; override;
- function PSUpdateRecord(UpdateKind: TUpdateKind; Delta: TDataSet): Boolean; override;
- protected
- procedure CloseCursor; override;
- function ConstraintsStored: Boolean;
- procedure Disconnect; virtual;
- procedure OpenCursor(InfoQuery: Boolean); override;
- function SetDBFlag(Flag: Integer; Value: Boolean): Boolean; virtual;
- procedure SetHandle(Value: HDBICur);
- property DBFlags: TDBFlags read FDBFlags;
- property UpdateMode: TUpdateMode read FUpdateMode write SetUpdateMode default upWhereAll;
- public
- constructor Create(AOwner: TComponent); override;
- function CheckOpen(Status: DBIResult): Boolean;
- procedure CloseDatabase(Database: TDatabase);
- function OpenDatabase: TDatabase;
- property Database: TDatabase read FDatabase;
- property DBHandle: HDBIDB read GetDBHandle;
- property DBLocale: TLocale read GetDBLocale;
- property DBSession: TSession read GetDBSession;
- property Handle: HDBICur read FHandle write SetHandle;
- published
- property AutoRefresh: Boolean read FAutoRefresh write SetAutoRefresh default False;
- property DatabaseName: string read FDatabaseName write SetDatabaseName;
- property Filter;
- property Filtered;
- property FilterOptions;
- property SessionName: string read FSessionName write SetSessionName;
- property OnFilterRecord;
- end;
-
- { TTable }
-
- TBatchMode = (batAppend, batUpdate, batAppendUpdate, batDelete, batCopy);
- TTableType = (ttDefault, ttParadox, ttDBase, ttFoxPro, ttASCII);
- TLockType = (ltReadLock, ltWriteLock);
- TIndexName = type string;
-
- TIndexDescList = array of IDXDesc;
-
- TValCheckList = array of VCHKDesc;
-
- 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
- FStoreDefs: Boolean;
- FIndexDefs: TIndexDefs;
- FMasterLink: TMasterDataLink;
- FDefaultIndex: Boolean;
- FExclusive: Boolean;
- FReadOnly: Boolean;
- FTableType: TTableType;
- FFieldsIndex: Boolean;
- FTableName: TFileName;
- FIndexName: TIndexName;
- FIndexFiles: TStrings;
- FLookupHandle: HDBICur;
- FLookupKeyFields: string;
- FTableLevel: Integer;
- FLookupCaseIns: Boolean;
- FNativeTableName: DBITBLNAME;
- procedure CheckMasterRange;
- procedure DecodeIndexDesc(const IndexDesc: IDXDesc;
- var Source, Name, FieldExpression, DescFields: string;
- var Options: TIndexOptions);
- function FieldDefsStored: Boolean;
- function GetDriverTypeName(Buffer: PChar): PChar;
- function GetExists: Boolean;
- function GetIndexFieldNames: string;
- function GetIndexName: string;
- procedure GetIndexParams(const IndexName: string; FieldsIndex: Boolean;
- var IndexedName, IndexTag: string);
- function GetMasterFields: string;
- function GetTableTypeName: PChar;
- function GetTableLevel: Integer;
- function IndexDefsStored: Boolean;
- function IsXBaseTable: Boolean;
- procedure MasterChanged(Sender: TObject);
- procedure MasterDisabled(Sender: TObject);
- procedure SetDataSource(Value: TDataSource);
- procedure SetExclusive(Value: Boolean);
- procedure SetIndexDefs(Value: TIndexDefs);
- 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);
- function SetTempLocale(ActiveCheck: Boolean): TLocale;
- procedure RestoreLocale(LocaleSave: TLocale);
- procedure UpdateRange;
- protected
- { IProviderSupport }
- function PSGetDefaultOrder: TIndexDef; override;
- function PSGetKeyFields: string; override;
- function PSGetTableName: string; override;
- function PSGetIndexDefs(IndexTypes: TIndexOptions): TIndexDefs; override;
- procedure PSSetCommandText(const CommandText: string); override;
- procedure PSSetParams(AParams: TParams); override;
- protected
- function CreateHandle: HDBICur; override;
- procedure DataEvent(Event: TDataEvent; Info: Longint); override;
- procedure DefChanged(Sender: TObject); override;
- procedure DestroyHandle; override;
- procedure DestroyLookupCursor; override;
- procedure DoOnNewRecord; override;
- procedure EncodeFieldDesc(var FieldDesc: FLDDesc;
- const Name: string; DataType: TFieldType; Size, Precision: Integer);
- procedure EncodeIndexDesc(var IndexDesc: IDXDesc;
- const Name, FieldExpression: string; Options: TIndexOptions;
- const DescFields: string = '');
- 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 GetFileName: string;
- function GetTableType: TTableType;
- function IsProductionIndex(const IndexName: string): Boolean;
- function NativeTableName: PChar;
- procedure PrepareCursor; override;
- procedure UpdateIndexDefs; override;
- property MasterLink: TMasterDataLink read FMasterLink;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- function BatchMove(ASource: TBDEDataSet; AMode: TBatchMode): Longint;
- procedure AddIndex(const Name, Fields: string; Options: TIndexOptions;
- const DescFields: string = '');
- 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 GetDetailLinkFields(MasterFields, DetailFields: TList); override;
- 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 Exists: Boolean read GetExists;
- property Handle: HDBICur read FHandle;
- 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;
- property TableLevel: Integer read GetTableLevel write FTableLevel;
- published
- property Constraints stored ConstraintsStored;
- property DefaultIndex: Boolean read FDefaultIndex write FDefaultIndex default True;
- property Exclusive: Boolean read FExclusive write SetExclusive default False;
- property FieldDefs stored FieldDefsStored;
- property IndexDefs: TIndexDefs read FIndexDefs write SetIndexDefs stored IndexDefsStored;
- 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 StoreDefs: Boolean read FStoreDefs write FStoreDefs 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: TBDEDataSet;
- 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 SetMappings(Value: TStrings);
- procedure SetSource(Value: TBDEDataSet);
- 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: TBDEDataSet read FSource write SetSource;
- property Transliterate: Boolean read FTransliterate write FTransliterate default True;
- end;
-
- { TStoredProc }
-
- TParamBindMode = (pbByName, pbByNumber);
-
- TServerDesc = record
- ParamName: string[DBIMAXSPNAMELEN];
- BindType: TFieldType;
- end;
-
- TServerDescList = array of TServerDesc;
- TSPParamDescList = array of SPParamDesc;
-
- TStoredProc = class(TDBDataSet)
- private
- FProcName: string;
- FParams: TParams;
- FParamDescs: TSPParamDescList;
- FServerDescs: TServerDescList;
- FRecordBuffer: array of Char;
- FOverLoad: Word;
- FPrepared: Boolean;
- FQueryMode: Boolean;
- FBindMode: TParamBindMode;
- procedure BindParams;
- function CheckServerParams: Boolean;
- function CreateCursor(GenHandle: Boolean): HDBICur;
- procedure CreateParamDesc;
- procedure FreeStatement;
- function GetCursor(GenHandle: Boolean): HDBICur;
- procedure PrepareProc;
- procedure ReadParamData(Reader: TReader);
- procedure SetParamsList(Value: TParams);
- procedure SetServerParams;
- procedure WriteParamData(Writer: TWriter);
- protected
- { IProviderSupport }
- procedure PSExecute; override;
- function PSGetTableName: string; override;
- function PSGetParams: TParams; override;
- procedure PSSetCommandText(const CommandText: string); override;
- procedure PSSetParams(AParams: TParams); override;
- protected
- function CreateHandle: HDBICur; override;
- procedure DefineProperties(Filer: TFiler); override;
- procedure Disconnect; override;
- function GetParamsCount: Word;
- function SetDBFlag(Flag: Integer; Value: Boolean): 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 Handle: HDBICur read FHandle;
- property ParamCount: Word read GetParamsCount;
- property StmtHandle;
- 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 stored False;
- property ParamBindMode: TParamBindMode read FBindMode write FBindMode default pbByName;
- property UpdateObject;
- end;
-
- { TQuery }
-
- TQuery = class(TDBDataSet)
- private
- FSQL: TStrings;
- FPrepared: Boolean;
- FParams: TParams;
- FText: string;
- FDataLink: TDataLink;
- FLocal: Boolean;
- FRowsAffected: Integer;
- FUniDirectional: Boolean;
- FRequestLive: Boolean;
- FSQLBinary: PChar;
- FConstrained: Boolean;
- FParamCheck: Boolean;
- FExecSQL: Boolean;
- FCheckRowsAffected: Boolean;
- function CreateCursor(GenHandle: Boolean): HDBICur;
- function GetQueryCursor(GenHandle: Boolean): HDBICur;
- function GetRowsAffected: Integer;
- procedure PrepareSQL(Value: PChar);
- procedure QueryChanged(Sender: TObject);
- procedure ReadBinaryData(Stream: TStream);
- procedure ReadParamData(Reader: TReader);
- procedure RefreshParams;
- procedure SetDataSource(Value: TDataSource);
- procedure SetQuery(Value: TStrings);
- procedure SetParamsList(Value: TParams);
- procedure SetParamsFromCursor;
- procedure SetPrepared(Value: Boolean);
- procedure SetPrepare(Value: Boolean);
- procedure WriteBinaryData(Stream: TStream);
- procedure WriteParamData(Writer: TWriter);
- protected
- { IProviderSupport }
- procedure PSExecute; override;
- function PSGetDefaultOrder: TIndexDef; override;
- function PSGetParams: TParams; override;
- function PSGetTableName: string; override;
- procedure PSSetCommandText(const CommandText: string); override;
- procedure PSSetParams(AParams: TParams); override;
- protected
- function CreateHandle: HDBICur; override;
- procedure DefineProperties(Filer: TFiler); override;
- procedure Disconnect; override;
- procedure FreeStatement; virtual;
- function GetDataSource: TDataSource; override;
- function GetParamsCount: Word;
- function SetDBFlag(Flag: Integer; Value: Boolean): Boolean; override;
- procedure GetStatementHandle(SQLText: PChar); virtual;
- property DataLink: TDataLink read FDataLink;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure ExecSQL;
- procedure GetDetailLinkFields(MasterFields, DetailFields: TList); override;
- function ParamByName(const Value: string): TParam;
- procedure Prepare;
- procedure UnPrepare;
- property Handle: HDBICur read FHandle;
- property Prepared: Boolean read FPrepared write SetPrepare;
- property ParamCount: Word read GetParamsCount;
- property Local: Boolean read FLocal;
- property StmtHandle;
- 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 Constraints stored ConstraintsStored;
- property DataSource: TDataSource read GetDataSource write SetDataSource;
- 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;
- { This property must be listed after the SQL property for Delphi 1.0 compatibility }
- property Params: TParams read FParams write SetParamsList stored False;
- property UniDirectional: Boolean read FUniDirectional write FUniDirectional default False;
- property UpdateMode;
- property UpdateObject;
- end;
-
- { TUpdateSQL }
-
- TUpdateSQL = class(TSQLUpdateObject)
- private
- FDataSet: TBDEDataSet;
- FQueries: array[TUpdateKind] of TQuery;
- FSQLText: array[TUpdateKind] of TStrings;
- function GetQuery(UpdateKind: TUpdateKind): TQuery;
- function GetSQLIndex(Index: Integer): TStrings;
- procedure SetSQL(UpdateKind: TUpdateKind; Value: TStrings);
- procedure SetSQLIndex(Index: Integer; Value: TStrings);
- protected
- function GetSQL(UpdateKind: TUpdateKind): TStrings; override;
- function GetDataSet: TBDEDataSet; override;
- procedure SetDataSet(ADataSet: TBDEDataSet); override;
- procedure SQLChanged(Sender: TObject);
- 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;
-
- { TBlobStream }
-
- TBlobStream = class(TStream)
- private
- FField: TBlobField;
- FDataSet: TBDEDataSet;
- FBuffer: PChar;
- FMode: TBlobStreamMode;
- FFieldNo: Integer;
- FOpened: Boolean;
- FModified: Boolean;
- FPosition: Longint;
- FBlobData: TBlobData;
- FCached: Boolean;
- FCacheSize: 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;
-
- function AnsiToNative(Locale: TLocale; const AnsiStr: string;
- NativeStr: PChar; MaxLen: Integer): PChar;
- procedure NativeToAnsi(Locale: TLocale; NativeStr: PChar;
- var AnsiStr: string);
- procedure AnsiToNativeBuf(Locale: TLocale; Source, Dest: PChar; Len: Integer);
- procedure NativeToAnsiBuf(Locale: TLocale; Source, Dest: PChar; Len: Integer);
-
- function NativeCompareStr(Locale: TLocale; const S1, S2: string; Len: Integer): Integer;
- function NativeCompareStrBuf(Locale: TLocale; const S1, S2: PChar; Len: Integer): Integer;
- function NativeCompareText(Locale: TLocale; const S1, S2: string; Len: Integer): Integer;
- function NativeCompareTextBuf(Locale: TLocale; const S1, S2: PChar; Len: Integer): Integer;
-
- function GetFieldSource(ADataSet: TDataSet; var ADataSources: DataSources): Boolean;
-
- procedure DbiError(ErrorCode: DBIResult);
- procedure Check(Status: DBIResult);
- procedure RegisterBDEInitProc(const InitProc: TBDEInitProc);
-
- const
- { Backward compatibility for TConfigMode }
- cmVirtual = [cfmVirtual];
- cmPersistent = [cfmPersistent];
- cmSession = [cfmSession];
- cmAll = [cfmVirtual, cfmPersistent, cfmSession];
-
- var
- Session: TSession;
- Sessions: TSessionList;
- GetObjectContextProc: function: IUnknown;
-
- implementation
-
- uses Forms, DBPWDlg, DBLogDlg, DBConsts, BDEConst, ActiveX;
-
- const
- TableTypeDriverNames: array[TTableType] of PChar =
- (szPARADOX, szPARADOX, szDBASE, szFOXPRO, szASCII);
-
- var
- FCSect: TRTLCriticalSection;
- TimerID: Word = 0;
- SQLDelay: DWORD = 50;
- StartTime: DWORD = 0;
- BDEInitProcs: TList;
-
- { TQueryDataLink }
-
- type
- TQueryDataLink = class(TDetailDataLink)
- private
- FQuery: TQuery;
- protected
- procedure ActiveChanged; override;
- procedure RecordChanged(Field: TField); override;
- function GetDetailDataSet: TDataSet; override;
- procedure CheckBrowseMode; override;
- public
- constructor Create(AQuery: TQuery);
- end;
-
- { Utility routines }
-
- function DefaultSession: TSession;
- begin
- Result := DBTables.Session;
- end;
-
- procedure RegisterBDEInitProc(const InitProc: TBDEInitProc);
- begin
- if not Assigned(BDEInitProcs) then
- BDEInitProcs := TList.Create;
- BDEInitProcs.Add(@InitProc);
- end;
-
- procedure CheckIndexOpen(Status: DBIResult);
- begin
- if (Status <> 0) and (Status <> DBIERR_INDEXOPEN) then
- DbiError(Status);
- end;
-
- function GetFieldSource(ADataSet: TDataSet; var ADataSources: DataSources): Boolean;
- var
- Current: PChar;
- Field: TField;
- Values: array[0..4] of string;
- I: Integer;
-
- function GetPChar(const S: string): PChar;
- begin
- if S <> '' then Result := PChar(Pointer(S)) else Result := '';
- end;
-
- procedure Split(const S: string);
- begin
- Current := PChar(Pointer(S));
- end;
-
- function NextItem: string;
- var
- C: PChar;
- I: PChar;
- Terminator: Char;
- Ident: array[0..1023] of Char;
- begin
- Result := '';
- C := Current;
- I := Ident;
- while C^ in ['.',' ',#0] do
- if C^ = #0 then Exit else Inc(C);
- Terminator := '.';
- if C^ = '"' then
- begin
- Terminator := '"';
- Inc(C);
- end;
- while not (C^ in [Terminator, #0]) do
- begin
- if C^ in LeadBytes then
- begin
- I^ := C^;
- Inc(C);
- Inc(I);
- end
- else if C^ = '\' then
- begin
- Inc(C);
- if C^ in LeadBytes then
- begin
- I^ := C^;
- Inc(C);
- Inc(I);
- end;
- if C^ = #0 then Dec(C);
- end;
- I^ := C^;
- Inc(C);
- Inc(I);
- end;
- SetString(Result, Ident, I - Ident);
- if (Terminator = '"') and (C^ <> #0) then Inc(C);
- Current := C;
- end;
-
- function PopValue: PChar;
- begin
- if I >= 0 then
- begin
- Result := GetPChar(Values[I]);
- Dec(I);
- end else Result := '';
- end;
-
- begin
- Result := False;
- Field := ADataSet.FindField(ADataSources.szSourceFldName);
- if (Field = nil) or (Field.Origin = '') then Exit;
- Split(Field.Origin);
- I := -1;
- repeat
- Inc(I);
- Values[I] := NextItem;
- until (Values[I] = '') or (I = High(Values));
- if I = High(Values) then Exit;
- Dec(I);
- StrCopy(ADataSources.szOrigFldName, PopValue);
- StrCopy(ADataSources.szTblName, PopValue);
- StrCopy(ADataSources.szDbName, PopValue);
- Result := (ADataSources.szOrigFldName[0] <> #0) and
- (ADataSources.szTblName[0] <> #0);
- end;
-
- { Parameter binding routines }
-
- function GetParamDataSize(Param: TParam): Integer;
- begin
- with Param do
- if ((DataType in [ftString, ftFixedChar]) and (Length(VarToStr(Value)) > 255)) or
- (DataType in [ftBlob..ftTypedBinary,ftOraBlob,ftOraClob]) then
- Result := SizeOf(BlobParamDesc) else
- Result := GetDataSize;
- end;
-
- procedure GetParamData(Param: TParam; Buffer: Pointer; const DrvLocale: TLocale);
-
- function GetNativeStr: PChar;
- begin
- Param.NativeStr := VarToStr(Param.Value);
- Result := PChar(Param.NativeStr);
- if DrvLocale <> nil then
- AnsiToNativeBuf(DrvLocale, Result, Result, StrLen(Result));
- end;
-
- begin
- with Param do
- if DataType in [ftString, ftFixedChar, ftMemo] then
- begin
- NativeStr := VarToStr(Value);
- if (Length(NativeStr) > 255) or (DataType = ftMemo) then
- begin
- with BlobParamDesc(Buffer^) do
- begin
- if DrvLocale <> nil then
- AnsiToNativeBuf(DrvLocale, PChar(NativeStr), PChar(NativeStr), Length(NativeStr));
- pBlobBuffer := PChar(NativeStr);
- ulBlobLen := StrLen(pBlobBuffer);
- end;
- end else
- begin
- if (DrvLocale <> nil) then
- AnsiToNativeBuf(DrvLocale, PChar(NativeStr), Buffer, Length(NativeStr) + 1) else
- GetData(Buffer);
- end;
- end
- else if (DataType in [ftBlob..ftTypedBinary,ftOraBlob,ftOraClob]) then
- begin
- with BlobParamDesc(Buffer^) do
- begin
- NativeStr := VarToStr(Value);
- ulBlobLen := Length(NativeStr);
- pBlobBuffer := PChar(NativeStr);
- end;
- end else
- GetData(Buffer);
- end;
-
- function GetStatementLocale(StmtHandle: HDBIStmt): TLocale;
- var
- DrvName: DBINAME;
- NumBytes: Word;
- begin
- DrvName[0] := #0;
- Result := nil;
- DbiGetProp(HDBIOBJ(StmtHandle), stmtLANGDRVNAME, @DrvName, SizeOf(DrvName), NumBytes);
- if StrLen(DrvName) > 0 then OsLdLoadBySymbName(DrvName, Result);
- end;
-
- procedure FreeStatementLocale(var Value: TLocale);
- begin
- if Value <> nil then OsLdUnloadObj(Value);
- Value := nil;
- end;
-
- { Any fixes made to this utility procedure should also be investigated for the
- TStoredProcedure. }
- procedure SetQueryParams(Sender: TComponent; StmtHandle: HDBIStmt; Params: TParams);
- var
- I: Integer;
- NumBytes: Word;
- FieldDescs: TFieldDescList;
- RecBuffer: PChar;
- CurPtr, NullPtr: PChar;
- DrvLocale: TLocale;
- begin
- SetLength(FieldDescs, Params.Count);
- NumBytes := SizeOf(SmallInt);
- for I := 0 to Params.Count - 1 do
- Inc(NumBytes, GetParamDataSize(Params[I]));
- RecBuffer := AllocMem(NumBytes);
- NullPtr := RecBuffer + NumBytes - SizeOf(SmallInt);
- Smallint(Pointer(NullPtr)^) := -1;
- CurPtr := RecBuffer;
- try
- DrvLocale := GetStatementLocale(StmtHandle);
- try
- for I := 0 to Params.Count - 1 do
- with FieldDescs[I], Params[I] do
- begin
- iFldType := FldTypeMap[DataType];
- if iFldType in [fldBlob, fldZString] then
- iSubType := FldSubTypeMap[DataType]
- else if iFldType = fldUNKNOWN then
- DatabaseErrorFmt(SNoParameterValue, [Name], Sender);
- iFldNum := I + 1;
- iLen := GetParamDataSize(Params[I]);
- GetParamData(Params[i], CurPtr, DrvLocale);
- iOffset := CurPtr - RecBuffer;
- if IsNull then
- iNullOffset := NullPtr - RecBuffer
- else if iFldType = fldZString then
- iUnits1 := GetDataSize - 1 {Do not include null terminator}
- else if iFldType = fldBYTES then
- iUnits1 := GetDataSize
- else if iFldType = fldVARBYTES then
- iUnits1 := GetDataSize - 2
- else if iFldType = fldBlob then
- iSubType := FldSubTypeMap[DataType];
- Inc(CurPtr, iLen);
- end;
- Check(DbiQSetParams(StmtHandle, High(FieldDescs)+1,
- PFLDDesc(FieldDescs), RecBuffer));
- finally
- FreeStatementLocale(DrvLocale);
- end;
- finally
- FreeMem(RecBuffer);
- end;
- end;
-
- { Timer callback function }
-
- procedure FreeTimer(ForceKill: Boolean = False);
- begin
- if (TimerID <> 0) and (ForceKill or (GetTickCount - StartTime > SQLDelay)) then
- begin
- KillTimer(0, TimerID);
- TimerID := 0;
- StartTime := 0;
- Screen.Cursor := crDefault;
- end;
- end;
-
- procedure TimerCallBack(hWnd: HWND; Message: Word; TimerID: Word;
- SysTime: LongInt); stdcall;
- begin
- FreeTimer;
- end;
-
- { BdeCallbacks }
-
- function BdeCallBack(CallType: CBType; Data: Longint;
- CBInfo: Pointer): CBRType; stdcall;
- begin
- if (Data <> 0) then
- Result := TBDECallback(Data).Invoke(CallType, CBInfo) else
- Result := cbrUSEDEF;
- end;
-
- function DLLDetachCallBack(CallType: CBType; Data: Longint;
- CBInfo: Pointer): CBRType; stdcall;
- begin
- Session.FDLLDetach := True;
- Sessions.CloseAll;
- Result := cbrUSEDEF
- end;
-
- constructor TBDECallback.Create(AOwner: TObject; Handle: hDBICur; CBType: CBType;
- CBBuf: Pointer; CBBufSize: Integer; CallbackEvent: TBDECallbackEvent;
- Chain: Boolean);
- begin
- FOwner := AOwner;
- FHandle := Handle;
- FCBType := CBType;
- FCallbackEvent := CallbackEvent;
- DbiGetCallBack(Handle, FCBType, @FOldCBData, @FOldCBBufLen, @FOldCBBuf, FOldCBFunc);
- if not Assigned(FOldCBFunc) or Chain then
- begin
- Check(DbiRegisterCallback(FHandle, FCBType, Longint(Self), CBBufSize,
- CBBuf, BdeCallBack));
- FInstalled := True;
- end;
- end;
-
- destructor TBDECallback.Destroy;
- begin
- if FInstalled then
- begin
- if Assigned(FOldCBFunc) then
- try
- DbiRegisterCallback(FHandle, FCBType, FOldCBData, FOldCBBufLen,
- FOldCBBuf, FOldCBFunc);
- except
- end
- else
- DbiRegisterCallback(FHandle, FCBType, 0, 0, nil, nil);
- end;
- end;
-
- function TBDECallback.Invoke(CallType: CBType; CBInfo: Pointer): CBRType;
- begin
- if CallType = FCBType then
- Result := FCallbackEvent(CBInfo) else
- Result := cbrUSEDEF;
- if Assigned(FOldCBFunc)
- then Result := FOldCBFunc(CallType, FOldCBData, CBInfo);
- end;
-
- { Utility routines }
-
- function StrToOem(const AnsiStr: string): string;
- begin
- SetLength(Result, Length(AnsiStr));
- if Length(Result) > 0 then
- CharToOem(PChar(AnsiStr), PChar(Result));
- end;
-
- function AnsiToNative(Locale: TLocale; const AnsiStr: string;
- NativeStr: PChar; MaxLen: Integer): PChar;
- var
- Len: Integer;
- begin
- Len := Length(AnsiStr);
- if Len > MaxLen then
- begin
- Len := MaxLen;
- if SysLocale.FarEast and (ByteType(AnsiStr, Len) = mbLeadByte) then
- Dec(Len);
- end;
- NativeStr[Len] := #0;
- if Len > 0 then AnsiToNativeBuf(Locale, Pointer(AnsiStr), NativeStr, Len);
- Result := NativeStr;
- end;
-
- procedure NativeToAnsi(Locale: TLocale; NativeStr: PChar;
- var AnsiStr: string);
- var
- Len: Integer;
- begin
- Len := StrLen(NativeStr);
- SetString(AnsiStr, nil, Len);
- if Len > 0 then NativeToAnsiBuf(Locale, NativeStr, Pointer(AnsiStr), Len);
- end;
-
- procedure AnsiToNativeBuf(Locale: TLocale; Source, Dest: PChar; Len: Integer);
- var
- DataLoss: LongBool;
- begin
- if Len > 0 then
- if Locale <> nil then
- DbiAnsiToNative(Locale, Dest, Source, Len, DataLoss) else
- CharToOemBuff(Source, Dest, Len);
- end;
-
- procedure NativeToAnsiBuf(Locale: TLocale; Source, Dest: PChar; Len: Integer);
- var
- DataLoss: LongBool;
- begin
- if Len > 0 then
- if Locale <> nil then
- DbiNativeToAnsi(Locale, Dest, Source, Len, DataLoss) else
- OemToCharBuff(Source, Dest, Len)
- end;
-
- function NativeCompareStr(Locale: TLocale; const S1, S2: string; Len: Integer): Integer;
- begin
- Result := NativeCompareStrBuf(Locale, PChar(S1), PChar(S2), Len);
- end;
-
- function NativeCompareStrBuf(Locale: TLocale; const S1, S2: PChar; Len: Integer): Integer;
- begin
- if Len > 0 then
- Result := OsLdStrnCmp(Locale, S1, S2, Len) else
- Result := OsLdStrCmp(Locale, S1, S2);
- end;
-
- function NativeCompareText(Locale: TLocale; const S1, S2: string; Len: Integer): Integer;
- begin
- Result := NativeCompareTextBuf(Locale, PChar(S1), PChar(S2), Len);
- end;
-
- function NativeCompareTextBuf(Locale: TLocale; const S1, S2: PChar; Len: Integer): Integer;
- begin
- if Len > 0 then
- Result := OsLdStrnCmpi(Locale, S1, S2, Len) else
- Result := OsLdStrCmpi(Locale, S1, S2);
- end;
-
- function IsDirectory(const DatabaseName: string): Boolean;
- var
- I: Integer;
- begin
- Result := True;
- if (DatabaseName = '') then Exit;
- I := 1;
- while I <= Length(DatabaseName) do
- begin
- if DatabaseName[I] in [':','\'] then Exit;
- if DatabaseName[I] in LeadBytes then Inc(I, 2)
- else Inc(I);
- end;
- Result := False;
- end;
-
- function IsStandardType(AType: PChar): Boolean;
- begin
- Result := (StrIComp(AType, szPARADOX) = 0) or
- (StrIComp(AType, szDBASE) = 0) or
- (StrIComp(AType, szFOXPRO) = 0);
- { Note: szASCII not included }
- end;
-
- function GetIntProp(const Handle: Pointer; PropName: Integer): Integer;
- var
- Length: Word;
- Value: Integer;
- begin
- Value := 0;
- if DbiGetProp(HDBIObj(Handle), PropName, @Value, SizeOf(Value), Length) = DBIERR_NONE then
- Result := Value
- else
- Result := 0;
- end;
-
- function SetBoolProp(const Handle: Pointer; PropName: Integer; Value: Bool): Boolean;
- begin
- Result := DbiSetProp(HDBIObj(Handle), PropName, Abs(Integer(Value))) = DBIERR_NONE;
- end;
-
- function StringListToParams(List: TStrings): string;
- var
- S: String;
- P, I: Integer;
- begin
- for I := 0 to List.Count - 1 do
- begin
- S := List[I];
- P := Pos('=', S);
- if (P >= 0) and (P < Length(S)) then
- Result := Format('%s%s:"%s";', [Result, Copy(S, 1, P-1), Copy(S, P+1, 255)]);
- end;
- Result := StrToOem(Result);
- SetLength(Result, Length(Result) - 1);
- end;
-
- procedure DbiError(ErrorCode: DBIResult);
- begin
- raise EDBEngineError.Create(ErrorCode);
- end;
-
- procedure Check(Status: DBIResult);
- begin
- if Status <> 0 then DbiError(Status);
- end;
-
- { TDBError }
-
- constructor TDBError.Create(Owner: EDBEngineError; ErrorCode: DBIResult;
- NativeError: Longint; Message: PChar);
- begin
- Owner.FErrors.Add(Self);
- FErrorCode := ErrorCode;
- FNativeError := NativeError;
- FMessage := Message;
- end;
-
- function TDBError.GetCategory: Byte;
- begin
- Result := Hi(FErrorCode);
- end;
-
- function TDBError.GetSubCode: Byte;
- begin
- Result := Lo(FErrorCode);
- end;
-
- { EDBEngineError }
-
- constructor EDBEngineError.Create(ErrorCode: DBIResult);
- var
- ErrorIndex: Integer;
- EntryCode: DBIResult;
- NativeError: Longint;
- ContextBuf: DBIMSG;
- Messages: TStrings;
-
- procedure AddMessage(const Msg: string);
- begin
- if (Msg <> '') and (Messages.IndexOf(Msg) = -1) then
- Messages.Add(Msg);
- end;
-
- function GetErrorString(Code: DBIResult): string;
- var
- Msg: DBIMSG;
- begin
- DbiGetErrorString(Code, Msg);
- Result := Msg;
- Trim(Result);
- end;
-
- begin
- FreeTimer(True);
- FErrors := TList.Create;
- if not DefaultSession.Active and (ErrorCode <> DBIERR_INTERFACEVER) then
- begin
- Message := Format(SInitError, [ErrorCode]);
- TDBError.Create(Self, ErrorCode, 0, PChar(Message));
- end else
- begin
- TDBError.Create(Self, ErrorCode, 0, PChar(GetErrorString(ErrorCode)));
- Messages := TStringList.Create;
- try
- if ErrorCode <> DBIERR_USERCONSTRERR then
- AddMessage(Errors[0].Message);
- ErrorIndex := 1;
- while True do
- begin
- EntryCode := DbiGetErrorEntry(ErrorIndex, NativeError, ContextBuf);
- if (EntryCode = DBIERR_NONE) or (EntryCode = DBIERR_NOTINITIALIZED) then
- Break;
- TDBError.Create(Self, EntryCode, NativeError, ContextBuf);
- if (NativeError = 0) and (ErrorCode <> DBIERR_USERCONSTRERR) then
- AddMessage(GetErrorString(EntryCode));
- AddMessage(Trim(ContextBuf));
- Inc(ErrorIndex);
- end;
- Message := Messages.Text;
- if Message <> '' then
- Message := Copy(Message, 1, Length(Message)-2) else
- Message := Format(SBDEError, [ErrorCode]);
- finally
- Messages.Free;
- end;
- end;
- end;
-
- destructor EDBEngineError.Destroy;
- var
- I: Integer;
- begin
- if FErrors <> nil then
- begin
- for I := FErrors.Count - 1 downto 0 do TDBError(FErrors[I]).Free;
- FErrors.Free;
- end;
- inherited Destroy;
- end;
-
- function EDBEngineError.GetError(Index: Integer): TDBError;
- begin
- Result := FErrors[Index];
- end;
-
- function EDBEngineError.GetErrorCount: Integer;
- begin
- Result := FErrors.Count;
- end;
-
- { TSessionList }
-
- constructor TSessionList.Create;
- begin
- inherited Create;
- FSessions := TThreadList.Create;
- FSessionNumbers := TBits.Create;
- InitializeCriticalSection(FCSect);
- end;
-
- destructor TSessionList.Destroy;
- begin
- CloseAll;
- DeleteCriticalSection(FCSect);
- FSessionNumbers.Free;
- FSessions.Free;
- inherited Destroy;
- end;
-
- procedure TSessionList.AddSession(ASession: TSession);
- var
- List: TList;
- begin
- List := FSessions.LockList;
- try
- if List.Count = 0 then ASession.FDefault := True;
- List.Add(ASession);
- finally
- FSessions.UnlockList;
- end;
- end;
-
- procedure TSessionList.CloseAll;
- var
- I: Integer;
- List: TList;
- begin
- List := FSessions.LockList;
- try
- for I := List.Count-1 downto 0 do
- TSession(List[I]).Free;
- finally
- FSessions.UnlockList;
- end;
- end;
-
- function TSessionList.GetCount: Integer;
- var
- List: TList;
- begin
- List := FSessions.LockList;
- try
- Result := List.Count;
- finally
- FSessions.UnlockList;
- end;
- end;
-
- function TSessionList.GetCurrentSession: TSession;
- var
- Handle: HDBISes;
- I: Integer;
- List: TList;
- begin
- List := FSessions.LockList;
- try
- Check(DbiGetCurrSession(Handle));
- for I := 0 to List.Count - 1 do
- if TSession(List[I]).Handle = Handle then
- begin
- Result := TSession(List[I]);
- Exit;
- end;
- Result := nil;
- finally
- FSessions.UnlockList;
- end;
- end;
-
- function TSessionList.GetSession(Index: Integer): TSession;
- var
- List: TList;
- begin
- List := FSessions.LockList;
- try
- Result := TSession(List[Index]);
- finally
- FSessions.UnlockList;
- end;
- end;
-
- function TSessionList.GetSessionByName(const SessionName: string): TSession;
- begin
- if SessionName = '' then
- Result := Session
- else
- Result := FindSession(SessionName);
- if Result = nil then
- DatabaseErrorFmt(SInvalidSessionName, [SessionName]);
- end;
-
- function TSessionList.FindSession(const SessionName: string): TSession;
- var
- I: Integer;
- List: TList;
- begin
- if SessionName = '' then
- Result := Session
- else
- begin
- List := FSessions.LockList;
- try
- for I := 0 to List.Count - 1 do
- begin
- Result := List[I];
- if AnsiCompareText(Result.SessionName, SessionName) = 0 then Exit;
- end;
- Result := nil;
- finally
- FSessions.UnlockList;
- end;
- end;
- end;
-
- procedure TSessionList.GetSessionNames(List: TStrings);
- var
- I: Integer;
- SList: TList;
- begin
- List.BeginUpdate;
- try
- List.Clear;
- SList := FSessions.LockList;
- try
- for I := 0 to SList.Count - 1 do
- with TSession(SList[I]) do
- List.Add(SessionName);
- finally
- FSessions.UnlockList;
- end;
- finally
- List.EndUpdate;
- end;
- end;
-
- function TSessionList.OpenSession(const SessionName: string): TSession;
- begin
- Result := FindSession(SessionName);
- if Result = nil then
- begin
- Result := TSession.Create(nil);
- Result.SessionName := SessionName;
- end;
- Result.SetActive(True);
- end;
-
- procedure TSessionList.SetCurrentSession(Value: TSession);
- begin
- Check(DbiSetCurrSession(Value.FHandle))
- end;
-
- { TSession }
-
- constructor TSession.Create(AOwner: TComponent);
- begin
- ValidateAutoSession(AOwner, False);
- inherited Create(AOwner);
- FDatabases := TList.Create;
- FCallbacks := TList.Create;
- FKeepConnections := True;
- FSQLHourGlass := True;
- Sessions.AddSession(Self);
- FReserved := 0;
- FHandle := nil;
- end;
-
- destructor TSession.Destroy;
- begin
- SetActive(False);
- Sessions.FSessions.Remove(Self);
- inherited Destroy;
- FDatabases.Free;
- FCallbacks.Free;
- end;
-
- procedure TSession.AddAlias(const Name, Driver: string; List: TStrings);
- begin
- InternalAddAlias(Name, Driver, List, ConfigMode, True);
- end;
-
- procedure TSession.AddDriver(const Name: string; List: TStrings);
- var
- Params: string;
- CfgModeSave: TConfigMode;
- begin
- Params := StringListToParams(List);
- LockSession;
- try
- CfgModeSave := ConfigMode;
- try
- CheckConfigMode(ConfigMode);
- Check(DbiAddDriver(nil, PChar(StrToOem(Name)), PChar(Params), Bool(-1)));
- finally
- ConfigMode := cfgModeSave;
- end;
- finally
- UnlockSession;
- end;
- DBNotification(dbAddDriver, Pointer(Name));
- end;
-
- procedure TSession.AddDatabase(Value: TDatabase);
- begin
- FDatabases.Add(Value);
- DBNotification(dbAdd, Value);
- end;
-
- procedure TSession.AddStandardAlias(const Name, Path, DefaultDriver: string);
- var
- AliasParams: TStringList;
- begin
- AliasParams := TStringList.Create;
- try
- AliasParams.Add(Format('%s=%s', [szCFGDBPATH, Path]));
- AliasParams.Add(Format('%s=%s', [szCFGDBDEFAULTDRIVER, DefaultDriver]));
- AddAlias(Name, szCFGDBSTANDARD, AliasParams);
- finally
- AliasParams.Free;
- end;
- end;
-
- procedure TSession.AddPassword(const Password: string);
- var
- Buffer: array[0..255] of Char;
- begin
- LockSession;
- try
- if Password <> '' then
- Check(DbiAddPassword(AnsiToNative(Locale, Password, Buffer,
- SizeOf(Buffer) - 1)));
- finally
- UnlockSession;
- end;
- end;
-
- procedure TSession.CallBDEInitProcs;
- var
- I: Integer;
- begin
- if Assigned(BDEInitProcs) then
- for I := 0 to BDEInitProcs.Count - 1 do
- TBDEInitProc(BDEInitProcs[I])(Self);
- end;
-
- procedure TSession.CheckInactive;
- begin
- if Active then
- DatabaseError(SSessionActive, Self);
- end;
-
- procedure TSession.CheckConfigMode(CfgMode: TConfigMode);
- begin
- if CfgMode = cmAll then CfgMode := cmPersistent;
- ConfigMode := CfgMode;
- end;
-
- procedure TSession.Close;
- begin
- SetActive(False);
- end;
-
- procedure TSession.CloseDatabase(Database: TDatabase);
- begin
- with Database do
- begin
- if FRefCount <> 0 then Dec(FRefCount);
- if (FRefCount = 0) and not KeepConnection then
- if not Temporary then Close else
- if not (csDestroying in ComponentState) then Free;
- end;
- end;
-
- procedure TSession.CloseDatabaseHandle(Database: TDatabase);
- var
- I: Integer;
- DB: TDatabase;
- begin
- for I := 0 to FDatabases.Count - 1 do
- begin
- DB := FDatabases[I];
- if (DB <> Database) and (DB.Handle <> nil) and
- (AnsiCompareText(DB.DatabaseName, Database.DatabaseName) = 0) then
- Exit;
- end;
- DbiCloseDatabase(Database.FHandle);
- end;
-
- function TSession.DBLoginCallback(CBInfo: Pointer): CBRType;
- var
- Database: TDatabase;
- UserName, Password: string;
- AliasParams: TStringList;
- begin
- Result := cbrYES;
- with PCBDBLogin(CBInfo)^ do
- try
- if hDB = nil then
- begin
- if not FBDEOwnsLoginCbDb then
- begin
- Database := OpenDatabase(szDbName);
- if not Database.HandleShared then
- begin
- hDb := Database.Handle;
- bCallbackToClose := True;
- end else
- begin
- CloseDatabase(Database);
- Result := cbrAbort;
- end;
- end else
- begin
- AliasParams := TStringList.Create;
- try
- GetAliasParams(szDbName, AliasParams);
- UserName := AliasParams.Values[szUSERNAME];
- finally
- AliasParams.Free;
- end;
- Password := '';
- if LoginDialogEx(szDbName, UserName, Password, True) then
- begin
- AnsiToNative(Locale, Password, szPassword, SizeOf(szPassword) - 1);
- bCallbackToClose := False;
- end
- else
- Result :=cbrAbort;
- end
- end else
- begin
- Database := FindDatabase(szDbName);
- if Assigned(Database) and (hDB = Database.Handle) then
- CloseDatabase(Database);
- end;
- except
- Result := cbrAbort;
- end;
- end;
-
- procedure TSession.DBNotification(DBEvent: TDatabaseEvent; const Param);
- begin
- if Assigned(FOnDBNotify) then FOnDBNotify(DBEvent, Param);
- end;
-
- procedure TSession.DeleteAlias(const Name: string);
- begin
- InternalDeleteAlias(Name, ConfigMode, True);
- end;
-
- procedure TSession.DeleteDriver(const Name: string);
- begin
- DBNotification(dbDeleteDriver, Pointer(Name));
- LockSession;
- try
- DbiDeleteDriver(nil, PChar(StrToOem(Name)), False);
- finally
- UnlockSession;
- end;
- end;
-
- procedure TSession.DeleteConfigPath(const Path, Node: string);
- var
- CfgPath: string;
- begin
- CfgPath := Format(Path, [Node]);
- if DbiCfgPosition(nil, PChar(CfgPath)) = 0 then
- Check(DbiCfgDropRecord(nil, PChar(CfgPath)));
- end;
-
- procedure TSession.DropConnections;
- var
- I: Integer;
- begin
- for I := FDatabases.Count - 1 downto 0 do
- with TDatabase(FDatabases[I]) do
- if Temporary and (FRefCount = 0) then Free;
- end;
-
- function TSession.FindDatabase(const DatabaseName: string): TDatabase;
- var
- I: Integer;
- begin
- for I := 0 to FDatabases.Count - 1 do
- begin
- Result := FDatabases[I];
- if ((Result.DatabaseName <> '') or Result.Temporary) and
- (AnsiCompareText(Result.DatabaseName, DatabaseName) = 0) then Exit;
- end;
- Result := nil;
- end;
-
- function TSession.DoFindDatabase(const DatabaseName: string;
- AOwner: TComponent): TDatabase;
- var
- I: Integer;
- begin
- if AOwner <> nil then
- for I := 0 to FDatabases.Count - 1 do
- begin
- Result := FDatabases[I];
- if (Result.Owner = AOwner) and (Result.HandleShared) and
- (AnsiCompareText(Result.DatabaseName, DatabaseName) = 0) then Exit;
- end;
- Result := FindDatabase(DatabaseName);
- end;
-
- function TSession.FindDatabaseHandle(const DatabaseName: string): HDBIDB;
- var
- I: Integer;
- DB: TDatabase;
- begin
- for I := 0 to FDatabases.Count - 1 do
- begin
- DB := FDatabases[I];
- if (DB.Handle <> nil) and
- (AnsiCompareText(DB.DatabaseName, DatabaseName) = 0) and
- DB.HandleShared then
- begin
- Result := DB.Handle;
- Exit;
- end;
- end;
- Result := nil;
- end;
-
- function TSession.GetActive: Boolean;
- begin
- Result := FHandle <> nil;
- end;
-
- function TSession.GetAliasDriverName(const AliasName: string): string;
- var
- Desc: DBDesc;
- begin
- LockSession;
- try
- if DbiGetDatabaseDesc(PChar(StrToOem(AliasName)), @Desc) <> 0 then
- DatabaseErrorFmt(SInvalidAliasName, [AliasName]);
- finally
- UnlockSession;
- end;
- if Desc.szDBType[sizeOf(Desc.szDBType) - 1] <> #0 then
- Desc.szDBType[sizeOf(Desc.szDBType) - 1] := #0;
- OemToChar(Desc.szDBType, Desc.szDBType);
- Result := Desc.szDBType;
- end;
-
- procedure TSession.GetAliasNames(List: TStrings);
- var
- Cursor: HDBICur;
- Desc: DBDesc;
- begin
- List.BeginUpdate;
- try
- List.Clear;
- LockSession;
- try
- Check(DbiOpenDatabaseList(Cursor));
- finally
- UnlockSession;
- end;
- try
- while DbiGetNextRecord(Cursor, dbiNOLOCK, @Desc, nil) = 0 do
- begin
- OemToChar(Desc.szName, Desc.szName);
- List.Add(Desc.szName);
- end;
- finally
- DbiCloseCursor(Cursor);
- end;
- finally
- List.EndUpdate;
- end;
- end;
-
- procedure TSession.GetAliasParams(const AliasName: string; List: TStrings);
- var
- SAlias: DBIName;
- Desc: DBDesc;
- begin
- List.BeginUpdate;
- try
- List.Clear;
- StrPLCopy(SAlias, AliasName, SizeOf(SAlias) - 1);
- CharToOEM(SAlias, SAlias);
- LockSession;
- try
- Check(DbiGetDatabaseDesc(SAlias, @Desc));
- finally
- UnlockSession;
- end;
- if Desc.szDBType[sizeOf(Desc.szDBType) - 1] <> #0 then
- Desc.szDBType[sizeOf(Desc.szDBType) - 1] := #0;
- if StrIComp(Desc.szDbType, szCFGDBSTANDARD) = 0 then
- begin
- GetConfigParams('\DATABASES\%s\DB INFO', SAlias, List);
- List.Values[szCFGDBTYPE] := '';
- end
- else
- GetConfigParams('\DATABASES\%s\DB OPEN', SAlias, List);
- finally
- List.EndUpdate;
- end;
- end;
-
- procedure TSession.GetConfigParams(const Path, Section: string; List: TStrings);
- var
- Cursor: HDBICur;
- ConfigDesc: CFGDesc;
- begin
- LockSession;
- try
- Check(DbiOpenCfgInfoList(nil, dbiREADONLY, cfgPERSISTENT, PChar(Format(Path,
- [Section])), Cursor));
- finally
- UnlockSession;
- end;
- try
- while DbiGetNextRecord(Cursor, dbiNOLOCK, @ConfigDesc, nil) = 0 do
- with ConfigDesc do
- begin
- OemToChar(szValue, szValue);
- List.Add(Format('%s=%s', [szNodeName, szValue]));
- end;
- finally
- DbiCloseCursor(Cursor);
- end;
- end;
-
- function TSession.GetDatabase(Index: Integer): TDatabase;
- begin
- Result := FDatabases[Index];
- end;
-
- function TSession.GetDatabaseCount: Integer;
- begin
- Result := FDatabases.Count;
- end;
-
- procedure TSession.GetDatabaseNames(List: TStrings);
- var
- I: Integer;
- Names: TStringList;
- begin
- Names := TStringList.Create;
- try
- Names.Sorted := True;
- GetAliasNames(Names);
- for I := 0 to FDatabases.Count - 1 do
- with TDatabase(FDatabases[I]) do
- if not IsDirectory(DatabaseName) then Names.Add(DatabaseName);
- List.Assign(Names);
- finally
- Names.Free;
- end;
- end;
-
- procedure TSession.GetDriverNames(List: TStrings);
- var
- Cursor: HDBICur;
- Name: DBINAME;
- begin
- List.BeginUpdate;
- try
- List.Clear;
- List.Add(szCFGDBSTANDARD);
- LockSession;
- try
- Check(DbiOpenDriverList(Cursor));
- finally
- UnlockSession;
- end;
- try
- while DbiGetNextRecord(Cursor, dbiNOLOCK, @Name, nil) = 0 do
- if not IsStandardType(Name) then
- begin
- OemToChar(Name, Name);
- List.Add(Name);
- end;
- finally
- DbiCloseCursor(Cursor);
- end;
- finally
- List.EndUpdate;
- end;
- end;
-
- procedure TSession.GetDriverParams(const DriverName: string;
- List: TStrings);
- begin
- List.BeginUpdate;
- try
- List.Clear;
- if CompareText(DriverName, szCFGDBSTANDARD) = 0 then
- begin
- List.Add(Format('%s=', [szCFGDBPATH]));
- List.Add(Format('%s=%s', [szCFGDBDEFAULTDRIVER, szPARADOX]));
- List.Add(Format('%s=%s', [szCFGDBENABLEBCD, szCFGFALSE]));
- end
- else
- GetConfigParams('\DRIVERS\%s\DB OPEN', StrToOem(DriverName), List);
- finally
- List.EndUpdate;
- end;
- end;
-
- function TSession.GetHandle: HDBISes;
- begin
- if FHandle <> nil then
- Check(DbiSetCurrSession(FHandle))
- else
- SetActive(True);
- Result := FHandle;
- end;
-
- function TSession.GetNetFileDir: string;
- var
- Length: Word;
- Buffer: DBIPATH;
- begin
- if Active and not (csWriting in ComponentState) then
- begin
- LockSession;
- try
- Check(DbiGetProp(HDBIOBJ(FHandle), sesNETFILE, @Buffer, SizeOf(Buffer),
- Length));
- finally
- UnLockSession;
- end;
- NativeToAnsi(nil, Buffer, Result);
- end else
- Result := FNetFileDir;
- Result := AnsiUpperCaseFileName(Result);
- end;
-
- function TSession.GetPrivateDir: string;
- var
- SessionInfo: SESInfo;
- begin
- if Active and not (csWriting in ComponentState) then
- begin
- LockSession;
- try
- Check(DbiGetSesInfo(SessionInfo));
- finally
- UnlockSession;
- end;
- NativeToAnsi(nil, SessionInfo.szPrivDir, Result);
- end else
- Result := FPrivateDir;
- Result := AnsiUpperCaseFileName(Result);
- end;
-
- function TSession.GetPassword: Boolean;
- begin
- if Assigned(FOnPassword) then
- begin
- Result := False;
- FOnPassword(Self, Result)
- end else
- Result := PasswordDialog(Self);
- end;
-
- procedure TSession.GetTableNames(const DatabaseName, Pattern: string;
- Extensions, SystemTables: Boolean; List: TStrings);
- var
- Database: TDatabase;
- Cursor: HDBICur;
- WildCard: PChar;
- Name: string;
- SPattern: DBITBLNAME;
- Desc: TBLBaseDesc;
- begin
- List.BeginUpdate;
- try
- List.Clear;
- Database := OpenDatabase(DatabaseName);
- try
- WildCard := nil;
- if Pattern <> '' then
- WildCard := AnsiToNative(Database.Locale, Pattern, SPattern,
- SizeOf(SPattern) - 1);
- Check(DbiOpenTableList(Database.Handle, False, SystemTables,
- WildCard, Cursor));
- try
- while DbiGetNextRecord(Cursor, dbiNOLOCK, @Desc, nil) = 0 do
- with Desc do
- begin
- if Extensions and (szExt[0] <> #0) then
- StrCat(StrCat(szName, '.'), szExt);
- NativeToAnsi(Database.Locale, szName, Name);
- List.Add(Name);
- end;
- finally
- DbiCloseCursor(Cursor);
- end;
- finally
- CloseDatabase(Database);
- end;
- finally
- List.EndUpdate;
- end;
- end;
-
- procedure TSession.GetStoredProcNames(const DatabaseName: string; List: TStrings);
- var
- Database: TDatabase;
- Cursor: HDBICur;
- Name: string;
- Desc: SPDesc;
- begin
- List.BeginUpdate;
- try
- List.Clear;
- Database := OpenDatabase(DatabaseName);
- try
- Check(DbiOpenSPList(Database.Handle, False, True, nil, Cursor));
- try
- while DbiGetNextRecord(Cursor, dbiNOLOCK, @Desc, nil) = 0 do
- with Desc do
- begin
- NativeToAnsi(Database.Locale, szName, Name);
- List.Add(Name);
- end;
- finally
- DbiCloseCursor(Cursor);
- end;
- finally
- CloseDatabase(Database);
- end;
- finally
- List.EndUpdate;
- end;
- end;
-
- procedure TSession.InitializeBDE;
- var
- Status: DBIResult;
- Env: DbiEnv;
- ClientHandle: hDBIObj;
- SetCursor: Boolean;
- begin
- SetCursor := (GetCurrentThreadID = MainThreadID) and (Screen.Cursor = crDefault);
- if SetCursor then
- Screen.Cursor := crHourGlass;
- try
- FillChar(Env, SizeOf(Env), 0);
- StrPLCopy(Env.szLang, SIDAPILangID, SizeOf(Env.szLang) - 1);
- Status := DbiInit(@Env);
- if (Status <> DBIERR_NONE) and (Status <> DBIERR_MULTIPLEINIT) then
- Check(Status);
- Check(DbiGetCurrSession(FHandle));
- if DbiGetObjFromName(objCLIENT, nil, ClientHandle) = 0 then
- DbiSetProp(ClientHandle, Integer(clSQLRESTRICT), GDAL);
- if IsLibrary then
- DbiRegisterCallback(nil, cbDETACHNOTIFY, 0, 0, nil, DLLDetachCallBack);
- finally
- if SetCursor and (Screen.Cursor = crHourGlass) then
- Screen.Cursor := crDefault;
- end;
- end;
-
- procedure TSession.InternalAddAlias(const Name, Driver: string; List: TStrings;
- CfgMode: TConfigMode; RestoreMode: Boolean);
- var
- Params: string;
- DrvName: string;
- CfgModeSave: TConfigMode;
- begin
- Params := StringListToParams(List);
- DrvName := List.Values[szCFGDBDEFAULTDRIVER];
- if (DrvName = '') then
- begin
- if (CompareText(Driver, szCFGDBSTANDARD) = 0) then
- DrvName := szPARADOX else
- DrvName := Driver;
- end;
- LockSession;
- try
- CfgModeSave := ConfigMode;
- try
- CheckConfigMode(CfgMode);
- Check(DbiAddAlias(nil, PChar(StrToOem(Name)), PChar(StrToOem(DrvName)), PChar(Params), Bool(-1)));
- finally
- if RestoreMode then ConfigMode := CfgModeSave;
- end;
- finally
- UnlockSession;
- end;
- DBNotification(dbAddAlias, Pointer(Name));
- end;
-
- procedure TSession.InternalDeleteAlias(const Name: string;
- CfgMode: TConfigMode; RestoreMode: Boolean);
- var
- CfgModeSave: TConfigMode;
- begin
- DBNotification(dbDeleteAlias, Pointer(Name));
- LockSession;
- try
- CfgModeSave := ConfigMode;
- try
- CheckConfigMode(CfgMode);
- DeleteConfigPath('\DATABASES\%s', StrToOem(Name));
- finally
- if RestoreMode then ConfigMode := cfgModeSave;
- end;
- finally
- UnlockSession;
- end;
- end;
-
- function TSession.IsAlias(const Name: string): Boolean;
- begin
- LockSession;
- try
- Result := (Name <> '') and
- (DbiCfgPosition(nil, PChar(Format('\DATABASES\%s', [StrToOem(Name)]))) = 0);
- finally
- UnlockSession;
- end;
- end;
-
- procedure TSession.Loaded;
- begin
- inherited Loaded;
- try
- if AutoSessionName then SetSessionNames;
- if FStreamedActive then SetActive(True);
- except
- if csDesigning in ComponentState then
- Application.HandleException(Self)
- else
- raise;
- end;
- end;
-
- procedure TSession.LockSession;
- begin
- if FLockCount = 0 then
- begin
- EnterCriticalSection(FCSect);
- Inc(FLockCount);
- MakeCurrent;
- end
- else
- Inc(FLockCount);
- end;
-
- procedure TSession.UnLockSession;
- begin
- Dec(FLockCount);
- if FLockCount = 0 then
- LeaveCriticalSection(FCSect);
- end;
-
- procedure TSession.MakeCurrent;
- begin
- if FHandle <> nil then
- Check(DbiSetCurrSession(FHandle))
- else
- SetActive(True);
- end;
-
- procedure TSession.ModifyAlias(Name: string; List: TStrings);
- var
- DriverName: string;
- OemName: string;
- CfgModeSave: TConfigMode;
- begin
- LockSession;
- try
- CfgModeSave := ConfigMode;
- try
- CheckConfigMode(ConfigMode);
- DriverName := GetAliasDriverName(Name);
- OemName := StrToOem(Name);
- ModifyConfigParams('\DATABASES\%s\DB INFO', OemName, List);
- if CompareText(DriverName, szCFGDBSTANDARD) <> 0 then
- ModifyConfigParams('\DATABASES\%s\DB OPEN', OemName, List);
- finally
- ConfigMode := CfgModeSave;
- end;
- finally
- UnLockSession;
- end;
- end;
-
- procedure TSession.ModifyDriver(Name: string; List: TStrings);
- var
- CfgModeSave: TConfigMode;
- OemName: string;
- begin
- LockSession;
- try
- CfgModeSave := ConfigMode;
- try
- CheckConfigMode(ConfigMode);
- OemName := StrToOem(Name);
- ModifyConfigParams('\DRIVERS\%s\INIT', OemName, List);
- if IsStandardType(PChar(Name)) then
- ModifyConfigParams('\DRIVERS\%s\TABLE CREATE', OemName, List) else
- ModifyConfigParams('\DRIVERS\%s\DB OPEN', OemName, List);
- finally
- ConfigMode := CfgModeSave;
- end;
- finally
- UnLockSession;
- end;
- end;
-
- procedure TSession.ModifyConfigParams(const Path, Node: string; List: TStrings);
- var
- I, J, C: Integer;
- Params: TStrings;
- begin
- Params := TStringList.Create;
- try
- GetConfigParams(Path, Node, Params);
- C := 0;
- for I := 0 to Params.Count - 1 do
- begin
- J := List.IndexOfName(Params.Names[I]);
- if J >= 0 then
- begin
- Params[I] := List[J];
- Inc(C);
- end;
- end;
- if C > 0 then SetConfigParams(Path, Node, Params);
- finally
- Params.Free;
- end;
- end;
-
- procedure TSession.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- inherited Notification(AComponent, Operation);
- if AutoSessionName and (Operation = opInsert) then
- if AComponent is TDBDataSet then
- TDBDataSet(AComponent).FSessionName := Self.SessionName
- else if AComponent is TDatabase then
- TDatabase(AComponent).FSession := Self;
- end;
-
- procedure TSession.Open;
- begin
- SetActive(True);
- end;
-
- function TSession.DoOpenDatabase(const DatabaseName: string; AOwner: TComponent): TDatabase;
- var
- TempDatabase: TDatabase;
- begin
- Result := nil;
- LockSession;
- try
- TempDatabase := nil;
- try
- Result := DoFindDatabase(DatabaseName, AOwner);
- if Result = nil then
- begin
- TempDatabase := TDatabase.Create(Self);
- TempDatabase.DatabaseName := DatabaseName;
- TempDatabase.KeepConnection := FKeepConnections;
- TempDatabase.Temporary := True;
- Result := TempDatabase;
- end;
- Result.Open;
- Inc(Result.FRefCount);
- except
- TempDatabase.Free;
- raise;
- end;
- finally
- UnLockSession;
- end;
- end;
-
- function TSession.OpenDatabase(const DatabaseName: string): TDatabase;
- begin
- Result := DoOpenDatabase(DatabaseName, nil);
- end;
-
- function TSession.SessionNameStored: Boolean;
- begin
- Result := not FAutoSessionName;
- end;
-
- procedure TSession.LoadSMClient(DesignTime: Boolean);
- var
- FM: THandle;
- ClientName: string;
- FOldCBFunc: pfDBICallBack;
- begin
- try
- if Assigned(FSMClient) or (DbiGetCallBack(nil, cbTrace, nil, nil, nil,
- FOldCBFunc) = DBIERR_NONE) or FSMLoadFailed then Exit;
- if not DesignTime then
- begin
- FM := OpenFileMapping(FILE_MAP_READ, False, 'SMBuffer'); { Do not localize }
- if FM = 0 then Exit;
- CloseHandle(FM);
- end;
- if not Assigned(FSMClient) then
- begin
- if not Assigned(DefaultSession.FSMClient) then
- CoCreateInstance(Class_SMClient, nil, CLSCTX_INPROC_SERVER, ISMClient,
- DefaultSession.FSMClient);
- if not FDefault then
- FSMClient := DefaultSession.FSMClient;
- end;
- if Assigned(FSMClient) then
- begin
- ClientName := Application.Title;
- if ClientName = '' then ClientName := SUntitled;
- if not FDefault then
- ClientName := Format('%s.%s', [ClientName, SessionName]);
- if FSMClient.RegisterClient(Integer(FHandle), PChar(ClientName), Self,
- @TSession.SMClientSignal) then
- begin
- GetMem(FSMBuffer, smTraceBufSize);
- FCallbacks.Add(TBDECallback.Create(Self, nil, cbTRACE,
- FSMBuffer, smTraceBufSize, SqlTraceCallBack, False));
- end else
- FSMClient := nil;
- FSMLoadFailed := FSMClient = nil;;
- end;
- except
- FSMLoadFailed := True;
- end;
- end;
-
- procedure TSession.RegisterCallbacks(Value: Boolean);
- var
- I: Integer;
- begin
- if Value then
- begin
- { Do not register any callbacks if we are not in the MainThread }
- if GetCurrentThreadID <> MainThreadID then Exit;
- if FSQLHourGlass then
- FCallbacks.Add(TBDECallback.Create(Self, nil, cbSERVERCALL,
- @FCBSCType, SizeOf(CBSCType), ServerCallBack, False));
-
- FCallbacks.Add(TBDECallback.Create(Self, nil, cbDBLOGIN,
- @FCBDBLogin, SizeOf(TCBDBLogin), DBLoginCallBack, False));
- end else
- begin
- for I := FCallbacks.Count - 1 downto 0 do
- TBDECallback(FCallbacks[I]).Free;
- FCallbacks.Clear;
- if Assigned(FSMClient) then
- try
- FreeMem(FSMBuffer, smTraceBufSize);
- FSMClient := nil;
- except
- end;
- end;
- end;
-
- procedure TSession.RemoveDatabase(Value: TDatabase);
- begin
- FDatabases.Remove(Value);
- DBNotification(dbRemove, Value);
- end;
-
- procedure TSession.RemoveAllPasswords;
- begin
- LockSession;
- try
- DbiDropPassword(nil);
- finally
- UnlockSession;
- end;
- end;
-
- procedure TSession.RemovePassword(const Password: string);
- var
- Buffer: array[0..255] of Char;
- begin
- LockSession;
- try
- if Password <> '' then
- DbiDropPassword(AnsiToNative(Locale, Password, Buffer, SizeOf(Buffer)-1));
- finally
- UnlockSession;
- end;
- end;
-
- procedure TSession.SaveConfigFile;
- var
- CfgModeSave: TConfigMode;
- begin
- CfgModeSave := ConfigMode;
- try
- ConfigMode := cmPersistent;
- Check(DbiCfgSave(nil, nil, Bool(-1)));
- finally
- ConfigMode := CfgModeSave;
- end;
- end;
-
- function TSession.ServerCallBack(CBInfo: Pointer): CBRType;
- begin
- Result := cbrUSEDEF;
- if (GetCurrentThreadID <> MainThreadID) then Exit;
- if (FCBSCType = cbscSQL) then
- begin
- if TimerID = 0 then
- TimerID := SetTimer(0, 0, SQLDelay, @TimerCallBack);
- if Screen.Cursor <> crSQLWait then
- Screen.Cursor := crSQLWait;
- StartTime := GetTickCount;
- end;
- end;
-
- procedure TSession.SetActive(Value: Boolean);
- begin
- if csReading in ComponentState then
- FStreamedActive := Value
- else
- if Active <> Value then
- StartSession(Value);
- end;
-
- procedure TSession.SetAutoSessionName(Value: Boolean);
- begin
- if Value <> FAutoSessionName then
- begin
- if Value then
- begin
- CheckInActive;
- ValidateAutoSession(Owner, True);
- FSessionNumber := -1;
- EnterCriticalSection(FCSect);
- try
- with Sessions do
- begin
- FSessionNumber := FSessionNumbers.OpenBit;
- FSessionNumbers[FSessionNumber] := True;
- end;
- finally
- LeaveCriticalSection(FCSect);
- end;
- UpdateAutoSessionName;
- end
- else
- begin
- if FSessionNumber > -1 then
- begin
- EnterCriticalSection(FCSect);
- try
- Sessions.FSessionNumbers[FSessionNumber] := False;
- finally
- LeaveCriticalSection(FCSect);
- end;
- end;
- end;
- FAutoSessionName := Value;
- end;
- end;
-
- function TSession.GetConfigMode: TConfigMode;
- begin
- LockSession;
- try
- Result := TConfigMode(Byte(GetIntProp(FHandle, sesCFGMODE2)));
- finally
- UnlockSession;
- end;
- end;
-
- procedure TSession.SetConfigMode(Value: TConfigMode);
- begin
- LockSession;
- try
- Check(DbiSetProp(hDBIObj(FHandle), sesCFGMODE2, Longint(Byte(Value))));
- finally
- UnlockSession;
- end;
- end;
-
- procedure TSession.SetConfigParams(const Path, Node: string; List: TStrings);
- var
- ParamList: TParamList;
- begin
- ParamList := TParamList.Create(List);
- try
- with ParamList do
- Check(DbiCfgModifyRecord(nil, PChar(Format(Path, [Node])), FieldCount,
- PFLDDesc(FieldDescs), Buffer));
- finally
- ParamList.Free;
- end;
- end;
-
- procedure TSession.SetName(const NewName: TComponentName);
- begin
- inherited SetName(NewName);
- if FAutoSessionName then UpdateAutoSessionName;
- end;
-
- procedure TSession.SetNetFileDir(const Value: string);
- var
- Buffer: DBIPATH;
- begin
- if Active then
- begin
- LockSession;
- try
- Check(DbiSetProp(HDBIOBJ(Handle), sesNETFILE, Longint(AnsiToNative(nil,
- Value, Buffer, SizeOf(Buffer) - 1))));
- finally
- UnLockSession;
- end;
- end;
- FNetFileDir := Value;
- end;
-
- procedure TSession.SetPrivateDir(const Value: string);
- var
- Buffer: DBIPATH;
- begin
- if Active then
- begin
- LockSession;
- try
- Check(DbiSetPrivateDir(AnsiToNative(nil, Value, Buffer,
- SizeOf(Buffer) - 1)));
- finally
- UnlockSession;
- end;
- end;
- FPrivateDir := Value;
- end;
-
- procedure TSession.SetSessionName(const Value: string);
- var
- Ses: TSession;
- begin
- if FAutoSessionName and not FUpdatingAutoSessionName then
- DatabaseError(SAutoSessionActive, Self);
- CheckInActive;
- if Value <> '' then
- begin
- Ses := Sessions.FindSession(Value);
- if not ((Ses = nil) or (Ses = Self)) then
- DatabaseErrorFmt(SDuplicateSessionName, [Value], Self);
- end;
- FSessionName := Value
- end;
-
- procedure TSession.SetSessionNames;
- var
- I: Integer;
- Component: TComponent;
- begin
- if Owner <> nil then
- for I := 0 to Owner.ComponentCount - 1 do
- begin
- Component := Owner.Components[I];
- if (Component is TDBDataSet) and
- (AnsiCompareText(TDBDataSet(Component).SessionName, Self.SessionName) <> 0) then
- TDBDataSet(Component).SessionName := Self.SessionName
- else if (Component is TDataBase) and
- (AnsiCompareText(TDatabase(Component).SessionName, Self.SessionName) <> 0) then
- TDataBase(Component).SessionName := Self.SessionName
- end;
- end;
-
- procedure TSession.SetTraceFlags(Value: TTraceFlags);
- var
- I: Integer;
- begin
- FTraceFlags := Value;
- for I := FDatabases.Count - 1 downto 0 do
- with TDatabase(FDatabases[I]) do
- TraceFlags := FTraceFlags;
- end;
-
- procedure TSession.SMClientSignal(Sender: TObject; Data: Integer);
- begin
- SetTraceFlags(TTraceFlags(Word(Data)));
- end;
-
- function TSession.SqlTraceCallBack(CBInfo: Pointer): CBRType;
- var
- Data: Pointer;
- begin
- try
- Data := @PTraceDesc(CBInfo).pszTrace;
- FSMClient.AddStatement(Data, StrLen(Data));
- except
- SetTraceFlags([]);
- end;
- Result := cbrUSEDEF;
- end;
-
- procedure TSession.StartSession(Value: Boolean);
- var
- I: Integer;
- begin
- EnterCriticalSection(FCSect);
- try
- if Value then
- begin
- if Assigned(FOnStartup) then FOnStartup(Self);
- if FSessionName = '' then DatabaseError(SSessionNameMissing, Self);
- if (DefaultSession <> Self) then DefaultSession.Active := True;
- if FDefault then
- InitializeBDE
- else
- Check(DbiStartSession(nil, FHandle, nil));
- try
- RegisterCallbacks(True);
- if FNetFileDir <> '' then SetNetFileDir(FNetFileDir);
- if FPrivateDir <> '' then SetPrivateDir(FPrivateDir);
- ConfigMode := cmAll;
- CallBDEInitProcs;
- except
- StartSession(False);
- raise;
- end;
- end else
- begin
- DbiSetCurrSession(FHandle);
- for I := FDatabases.Count - 1 downto 0 do
- with TDatabase(FDatabases[I]) do
- if Temporary then Free else Close;
- RegisterCallbacks(False);
- if FDefault then
- begin
- if not FDLLDetach then
- begin
- if IsLibrary then
- begin
- DbiRegisterCallback(nil, cbDETACHNOTIFY, 0, 0, @DLLDetachCallBack, nil);
- DbiDLLExit;
- end;
- DbiExit;
- end;
- end
- else
- begin
- Check(DbiCloseSession(FHandle));
- DbiSetCurrSession(DefaultSession.FHandle);
- end;
- FHandle := nil;
- end;
- finally
- LeaveCriticalSection(FCSect);
- end;
- end;
-
- procedure TSession.UpdateAutoSessionName;
- begin
- FUpdatingAutoSessionName := True;
- try
- SessionName := Format('%s_%d', [Name, FSessionNumber + 1]);
- finally
- FUpdatingAutoSessionName := False;
- end;
- SetSessionNames;
- end;
-
- procedure TSession.ValidateAutoSession(AOwner: TComponent; AllSessions: Boolean);
- var
- I: Integer;
- Component: TComponent;
- begin
- if AOwner <> nil then
- for I := 0 to AOwner.ComponentCount - 1 do
- begin
- Component := AOwner.Components[I];
- if (Component <> Self) and (Component is TSession) then
- if AllSessions then DatabaseError(SAutoSessionExclusive, Self)
- else if TSession(Component).AutoSessionName then
- DatabaseErrorFmt(SAutoSessionExists, [Component.Name]);
- end;
- end;
-
- { TParamList }
-
- constructor TParamList.Create(Params: TStrings);
- var
- I, P, FieldNo: Integer;
- BufPtr: PChar;
- S: string;
- begin
- for I := 0 to Params.Count - 1 do
- begin
- S := Params[I];
- P := Pos('=', S);
- if P <> 0 then
- begin
- Inc(FFieldCount);
- Inc(FBufSize, Length(S) - P + 1);
- end;
- end;
- if FFieldCount > 0 then
- begin
- SetLength(FFieldDescs, FFieldCount);
- FBuffer := AllocMem(FBufSize);
- FieldNo := 0;
- BufPtr := FBuffer;
- for I := 0 to Params.Count - 1 do
- begin
- S := Params[I];
- P := Pos('=', S);
- if P <> 0 then
- with FFieldDescs[FieldNo] do
- begin
- Inc(FieldNo);
- iFldNum := FieldNo;
- StrPLCopy(szName, Copy(S, 1, P - 1), SizeOf(szName) - 1);
- iFldType := fldZSTRING;
- iOffset := BufPtr - FBuffer;
- iLen := Length(S) - P + 1;
- StrCopy(BufPtr, PChar(Copy(S, P + 1, 255)));
- CharToOem(BufPtr, BufPtr);
- Inc(BufPtr, iLen);
- end;
- end;
- end;
- end;
-
- destructor TParamList.Destroy;
- begin
- DisposeMem(FBuffer, FBufSize);
- end;
-
- { TDatabase }
-
- constructor TDatabase.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- if FSession = nil then
- if AOwner is TSession then
- FSession := TSession(AOwner) else
- FSession := DefaultSession;
- SessionName := FSession.SessionName;
- FSession.AddDatabase(Self);
- FParams := TStringList.Create;
- TStringList(FParams).OnChanging := ParamsChanging;
- LoginPrompt := True;
- FKeepConnection := True;
- FLocale := FSession.Locale;
- FTransIsolation := tiReadCommitted;
- end;
-
- destructor TDatabase.Destroy;
- begin
- Destroying;
- Close;
- if FSession <> nil then
- FSession.RemoveDatabase(Self);
- inherited Destroy;
- FParams.Free;
- FStmtList.Free;
- end;
-
- procedure TDatabase.ApplyUpdates(const DataSets: array of TDBDataSet);
- var
- I: Integer;
- DS: TDBDataSet;
- begin
- StartTransaction;
- try
- for I := 0 to High(DataSets) do
- begin
- DS := DataSets[I];
- if DS.Database <> Self then
- DatabaseError(Format(SUpdateWrongDB, [DS.Name, Name]));
- DataSets[I].ApplyUpdates;
- end;
- Commit;
- except
- Rollback;
- raise;
- end;
- for I := 0 to High(DataSets) do
- DataSets[I].CommitUpdates;
- end;
-
- type
- PStmtInfo = ^TStmtInfo;
- TStmtInfo = packed record
- HashCode: Integer;
- StmtHandle: HDBIStmt;
- SQLText: string;
- end;
-
- procedure TDatabase.ClearStatements;
- var
- i: Integer;
- begin
- if Assigned(FStmtList) then
- begin
- for i := 0 to FStmtList.Count - 1 do
- begin
- DbiQFree(PStmtInfo(FStmtList[i]).StmtHandle);
- Dispose(PStmtInfo(FStmtList[i]));
- end;
- FStmtList.Clear;
- end;
- end;
-
- function TDatabase.Execute(const SQL: string; Params: TParams = nil;
- Cache: Boolean = False; Cursor: phDBICur = nil): Integer;
-
- function GetStmtInfo(SQL: PChar): PStmtInfo;
-
- function GetHashCode(Str: PChar): Integer;
- var
- Off, Len, Skip, I: Integer;
- begin
- Result := 0;
- Off := 1;
- Len := StrLen(Str);
- if Len < 16 then
- for I := (Len - 1) downto 0 do
- begin
- Result := (Result * 37) + Ord(Str[Off]);
- Inc(Off);
- end
- else
- begin
- { Only sample some characters }
- Skip := Len div 8;
- I := Len - 1;
- while I >= 0 do
- begin
- Result := (Result * 39) + Ord(Str[Off]);
- Dec(I, Skip);
- Inc(Off, Skip);
- end;
- end;
- end;
-
- var
- HashCode, i: Integer;
- Info: PStmtInfo;
- begin
- if not Assigned(FStmtList) then
- FStmtList := TList.Create;
- Result := nil;
- HashCode := GetHashCode(SQL);
- for i := 0 to FStmtList.Count - 1 do
- begin
- Info := PStmtInfo(FStmtList[i]);
- if (Info.HashCode = HashCode) and
- (AnsiStrIComp(PChar(Info.SQLText), SQL) = 0) then
- begin
- Result := Info;
- break;
- end;
- end;
- if not Assigned(Result) then
- begin
- New(Result);
- FStmtList.Add(Result);
- FillChar(Result^, SizeOf(Result^), 0);
- Result.HashCode := HashCode;
- end;
- end;
-
- function GetStatementHandle: HDBIStmt;
- var
- Info: PStmtInfo;
- Status: DBIResult;
- begin
- Info := nil;
- Result := nil;
- if Cache then
- begin
- Info := GetStmtInfo(PChar(SQL));
- Result := Info.StmtHandle;
- end;
- if not Assigned(Result) then
- begin
- Check(DbiQAlloc(Handle, qrylangSQL, Result));
- if Cursor <> nil then
- Check(DbiSetProp(hDbiObj(Result), stmtLIVENESS, Ord(wantCanned)));
- if not IsSQLBased then
- begin
- SetBoolProp(Result, stmtAUXTBLS, False);
- SetBoolProp(Result, stmtCANNEDREADONLY, True);
- end else
- SetBoolProp(Result, stmtUNIDIRECTIONAL, True);
- while True do
- begin
- Status := DbiQPrepare(Result, PChar(SQL));
- case Status of
- DBIERR_NONE: break;
- DBIERR_NOTSUFFTABLERIGHTS:
- if not FSession.GetPassword then DbiError(Status);
- else
- DbiError(Status);
- end;
- end;
- if Assigned(Info) then
- begin
- Info.SQLText := SQL;
- Info.StmtHandle := Result;
- end;
- end;
- end;
-
- var
- StmtHandle: HDBIStmt;
- Len: Word;
- begin
- Open;
- if Assigned(Params) and (Params.Count > 0) then
- begin
- StmtHandle := GetStatementHandle;
- try
- SetQueryParams(Self, StmtHandle, Params);
- Check(DbiQExec(StmtHandle, Cursor));
- finally
- if not Cache then DbiQFree(StmtHandle);
- end;
- end else
- Check(DbiQExecDirect(Handle, qrylangSQL, PChar(SQL), Cursor));
- if (Cursor = nil) and (DbiGetProp(hDBIObj(StmtHandle), stmtROWCOUNT,
- @Result, SizeOf(Result), Len) <> 0) then
- Result := 0;
- end;
-
- procedure TDatabase.CheckActive;
- begin
- if FHandle = nil then DatabaseError(SDatabaseClosed, Self);
- end;
-
- procedure TDatabase.CheckInactive;
- begin
- if FHandle <> nil then
- if csDesigning in ComponentState then
- Close else
- DatabaseError(SDatabaseOpen, Self);
- end;
-
- procedure TDatabase.CheckDatabaseName;
- begin
- if (FDatabaseName = '') and not Temporary then
- DatabaseError(SDatabaseNameMissing, Self);
- end;
-
- procedure TDatabase.CheckSessionName(Required: Boolean);
- var
- NewSession: TSession;
- begin
- if Required then
- NewSession := Sessions.List[FSessionName]
- else
- NewSession := Sessions.FindSession(FSessionName);
- if (NewSession <> nil) and (NewSession <> FSession) then
- begin
- if (FSession <> nil) then FSession.RemoveDatabase(Self);
- FSession := NewSession;
- FSession.FreeNotification(Self);
- FSession.AddDatabase(Self);
- try
- ValidateName(FDatabaseName);
- except
- FDatabaseName := '';
- raise;
- end;
- end;
- if Required then FSession.Active := True;
- end;
-
- procedure TDatabase.DoDisconnect;
- begin
- if FHandle <> nil then
- begin
- ClearStatements;
- Session.DBNotification(dbClose, Self);
- CloseDataSets;
- if FLocaleLoaded then OsLdUnloadObj(FLocale);
- FLocaleLoaded := False;
- FLocale := DefaultSession.Locale;
- if not FAcquiredHandle then
- FSession.CloseDatabaseHandle(Self) else
- FAcquiredHandle := False;
- FSQLBased := False;
- FHandle := nil;
- FRefCount := 0;
- if FSessionAlias then
- begin
- FSession.InternalDeleteAlias(FDatabaseName, cmSession, True);
- FSessionAlias := False;
- end;
- end;
- end;
-
- procedure TDatabase.CloseDataSets;
- begin
- while DataSetCount <> 0 do TDBDataSet(DataSets[DataSetCount-1]).Disconnect;
- end;
-
- procedure TDatabase.Commit;
- begin
- CheckActive;
- EndTransaction(xendCOMMIT);
- end;
-
- procedure TDatabase.EndTransaction(TransEnd: EXEnd);
- begin
- Check(DbiEndTran(FHandle, nil, TransEnd));
- end;
-
- function TDatabase.GetAliasName: string;
- begin
- if FAliased then Result := FDatabaseType else Result := '';
- end;
-
- function TDatabase.GetConnected: Boolean;
- begin
- Result := FHandle <> nil;
- end;
-
- function TDatabase.GetDataSet(Index: Integer): TDBDataSet;
- begin
- Result := inherited GetDataSet(Index) as TDBDataSet;
- end;
-
- function TDatabase.GetDirectory: string;
- var
- SDirectory: DBIPATH;
- begin
- if Handle <> nil then
- begin
- Check(DbiGetDirectory(Handle, False, SDirectory));
- SetLength(Result, StrLen(SDirectory));
- OemToChar(SDirectory, PChar(Result));
- end else
- Result := '';
- end;
-
- function TDatabase.GetDriverName: string;
- begin
- if FAliased then Result := '' else Result := FDatabaseType;
- end;
-
- procedure TDatabase.SetDatabaseFlags;
- var
- Length: Word;
- Buffer: DBINAME;
- SupportsPseudoIndexes: Bool;
- begin
- Check(DbiGetProp(HDBIOBJ(FHandle), dbDATABASETYPE, @Buffer,
- SizeOf(Buffer), Length));
- FSQLBased := StrIComp(Buffer, szCFGDBSTANDARD) <> 0;
- FPseudoIndexes := (DbiGetProp(HDBIOBJ(FHandle), Integer(drvPSEUDOINDEX),
- @SupportsPseudoIndexes, SizeOf(SupportsPseudoIndexes),
- Length) = DBIERR_NONE) and SupportsPseudoIndexes;
- end;
-
- function TDatabase.GetTraceFlags: TTraceFlags;
- begin
- if Connected and IsSQLBased then
- Result := TTraceFlags(Word(GetIntProp(FHandle, dbTraceMode)))
- else
- Result := [];
- end;
-
- function TDatabase.GetObjectContext: IUnknown;
- begin
- if Assigned(GetObjectContextProc) then
- Result := GetObjectContextProc
- else
- Result := nil;
- end;
-
- function TDatabase.GetInTransaction: Boolean;
- var
- X: XInfo;
- begin
- Result := (Handle <> nil) and (DbiGetTranInfo(Handle, nil, @X) = DBIERR_NONE)
- and (X.exState = xsActive);
- end;
-
- procedure TDatabase.Loaded;
- begin
- inherited Loaded;
- if not StreamedConnected then CheckSessionName(False);
- end;
-
- procedure TDatabase.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- inherited Notification(AComponent, Operation);
- if (Operation = opRemove) and (AComponent = FSession) and
- (FSession <> DefaultSession) then
- begin
- Close;
- SessionName := '';
- end;
- end;
-
- procedure TDatabase.LoadLocale;
- var
- LName: DBIName;
- DBLocale: TLocale;
- begin
- if IsSQLBased and (DbiGetLdNameFromDB(FHandle, nil, LName) = 0) and
- (OsLdLoadBySymbName(LName, DBLocale) = 0) then
- begin
- FLocale := DBLocale;
- FLocaleLoaded := True;
- end;
- end;
-
- procedure TDatabase.Login(LoginParams: TStrings);
- var
- UserName, Password: string;
- begin
- if Assigned(FOnLogin) then FOnLogin(Self, LoginParams) else
- begin
- UserName := LoginParams.Values[szUSERNAME];
- if not LoginDialogEx(DatabaseName, UserName, Password, False) then
- DatabaseErrorFmt(SLoginError, [DatabaseName]);
- LoginParams.Values[szUSERNAME] := UserName;
- LoginParams.Values[szPASSWORD] := Password;
- end;
- end;
-
- procedure TDatabase.CheckDatabaseAlias(var Password: string);
- var
- Desc: DBDesc;
- Aliased: Boolean;
- DBName: string;
- DriverType: string;
- AliasParams: TStringList;
- LoginParams: TStringList;
-
- function NeedsDBAlias: Boolean;
- var
- I: Integer;
- PName: String;
- begin
- Result := not Aliased or ((FDatabaseType <> '') and
- (FDatabaseName <> FDatabaseType));
- for I := 0 to FParams.Count - 1 do
- begin
- if AliasParams.IndexOf(FParams[I]) > -1 then continue;
- PName := FParams.Names[I];
- if (CompareText(PName, szPASSWORD) = 0) then continue;
- if AliasParams.IndexOfName(PName) > -1 then
- begin
- Result := True;
- AliasParams.Values[PName] := FParams.Values[PName];
- end;
- end;
- end;
-
- begin
- Password := '';
- FSessionAlias := False;
- AliasParams := TStringList.Create;
- try
- begin
- if FDatabaseType <> '' then
- begin
- DBName := FDatabaseType;
- Aliased := FAliased;
- end else
- begin
- DBName := FDatabaseName;
- Aliased := True;
- end;
- if Aliased then
- begin
- if DbiGetDatabaseDesc(PChar(StrToOem(DBName)), @Desc) <> 0 then Exit;
- if Desc.szDBType[sizeOf(Desc.szDBType) - 1] <> #0 then
- Desc.szDBType[sizeOf(Desc.szDBType) - 1] := #0;
- OemToChar(Desc.szDbType, Desc.szDbType);
- DriverType := Desc.szDbType;
- FSession.GetAliasParams(DBName, AliasParams);
- end else
- begin
- FSession.GetDriverParams(DBName, AliasParams);
- DriverType := FDatabaseType;
- end;
- if AliasParams.IndexOfName(szUSERNAME) <> -1 then
- begin
- if LoginPrompt then
- begin
- LoginParams := TStringList.Create;
- try
- if FParams.Values[szUSERNAME] = '' then
- FParams.Values[szUSERNAME] := AliasParams.Values[szUSERNAME];
- LoginParams.Values[szUSERNAME] := FParams.Values[szUSERNAME];
- Login(LoginParams);
- Password := LoginParams.Values[szPASSWORD];
- FParams.Values[szUSERNAME] := LoginParams.Values[szUSERNAME];
- finally
- LoginParams.Free;
- end;
- end else
- Password := FParams.Values[szPASSWORD];
- end;
- end;
- if NeedsDBAlias then
- begin
- FSession.InternalAddAlias(FDatabaseName, DriverType, AliasParams,
- cmSession, False);
- FSessionAlias := True;
- end;
- finally
- AliasParams.Free;
- end;
- end;
-
- function TDatabase.OpenFromExistingDB: Boolean;
- begin
- Handle := FSession.FindDatabaseHandle(DatabaseName);
- FAcquiredHandle := False;
- Result := (Handle <> nil);
- end;
-
- procedure TDatabase.DoConnect;
- const
- OpenModes: array[Boolean] of DbiOpenMode = (dbiReadWrite, dbiReadOnly);
- ShareModes: array[Boolean] of DbiShareMode = (dbiOpenShared, dbiOpenExcl);
- var
- DBName: string;
- DBPassword: string;
- CfgModeSave: TConfigMode;
- OptParam: Pointer;
- OptFldDesc: pFldDesc;
- OptParamCount: Integer;
- ObjectContextDesc: FldDesc;
- OpenModeFlag: Word;
- begin
- if FHandle = nil then
- begin
- CheckDatabaseName;
- CheckSessionName(True);
- if not (HandleShared and OpenFromExistingDB) then
- begin
- FSession.LockSession;
- try
- CfgModeSave := FSession.ConfigMode;
- try
- CheckDatabaseAlias(DBPassword);
- try
- if (FDatabaseType = '') and IsDirectory(FDatabaseName) then
- DBName := '' else
- DBName := StrToOem(FDatabaseName);
- OptParam := Pointer(GetObjectContext);
- OpenModeFlag := 0;
- if Assigned(OptParam) then
- begin
- OptParamCount := 1;
- ObjectContextDesc.iLen := sizeof(Pointer);
- ObjectContextDesc.iOffset := 0;
- StrCopy(ObjectContextDesc.szName, szMTXCONTEXTOBJ);
- OptFldDesc := @ObjectContextDesc;
- { Set a flag to indicate how bde will handle transactions started
- under MTS. BDE will handle the case of
- (TransIsolation <> tiDirtyRead) and not IsSQLBased. }
- case TransIsolation of
- tiDirtyRead: OpenModeFlag := OPENMODEFLAG_DIRTYREAD;
- tiReadCommitted: OpenModeFlag := OPENMODEFLAG_READCOMMITTED;
- tiRepeatableRead: OpenModeFlag := OPENMODEFLAG_REPEATABLEREAD;
- end
- end
- else
- begin
- OptParamCount := 0;
- OptFldDesc := nil;
- end;
- Check(DbiOpenDatabase(Pointer(DBName), nil,
- DBIOpenMode(Integer(OpenModes[FReadOnly]) or OpenModeFlag),
- ShareModes[FExclusive], Pointer(StrToOem(DBPassword)), OptParamCount, OptFldDesc,
- OptParam, FHandle));
- if DBName = '' then SetDirectory(FDatabaseName);
- SetBoolProp(FHandle, dbUSESCHEMAFILE, True);
- SetBoolProp(FHandle, dbPARAMFMTQMARK, True);
- SetBoolProp(FHandle, dbCOMPRESSARRAYFLDDESC, True);
- SetDatabaseFlags;
- LoadLocale;
- if IsSQLBased then FSession.LoadSMClient(csDesigning in ComponentState);
- TraceFlags := FSession.FTraceFlags;
- Session.DBNotification(dbOpen, Self);
- except
- if FSessionAlias then
- FSession.InternalDeleteAlias(FDatabaseName, cmSession, False);
- raise;
- end;
- finally
- FSession.ConfigMode := CfgModeSave;
- end;
- finally
- FSession.UnlockSession;
- end;
- end;
- end;
- end;
-
- procedure TDatabase.ParamsChanging(Sender: TObject);
- begin
- CheckInactive;
- end;
-
- procedure TDatabase.Rollback;
- begin
- CheckActive;
- EndTransaction(xendABORT);
- end;
-
- procedure TDatabase.SetAliasName(const Value: string);
- begin
- SetDatabaseType(Value, True);
- end;
-
- procedure TDatabase.SetDatabaseName(const Value: string);
- begin
- if csReading in ComponentState then
- FDatabaseName := Value else
- if FDatabaseName <> Value then
- begin
- CheckInactive;
- ValidateName(Value);
- FDatabaseName := Value;
- end;
- end;
-
- procedure TDatabase.SetDatabaseType(const Value: string;
- Aliased: Boolean);
- begin
- CheckInactive;
- FDatabaseType := Value;
- FAliased := Aliased;
- end;
-
- procedure TDatabase.SetDirectory(const Value: string);
- begin
- if Handle <> nil then
- Check(DbiSetDirectory(Handle, Pointer(StrToOem(Value))));
- end;
-
- procedure TDatabase.SetDriverName(const Value: string);
- begin
- SetDatabaseType(Value, False);
- end;
-
- procedure TDatabase.SetHandle(Value: HDBIDB);
- var
- DBSession: HDBISes;
- begin
- if Connected then Close;
- if Value <> nil then
- begin
- Check(DbiGetObjFromObj(HDBIObj(Value), objSESSION, HDBIObj(DBSession)));
- CheckDatabaseName;
- CheckSessionName(True);
- if FSession.Handle <> DBSession then
- DatabaseError(SDatabaseHandleSet, Self);
- FHandle := Value;
- SetDatabaseFlags;
- LoadLocale;
- Session.DBNotification(dbOpen, Self);
- FAcquiredHandle := True;
- end;
- end;
-
- procedure TDatabase.SetKeepConnection(Value: Boolean);
- begin
- if FKeepConnection <> Value then
- begin
- FKeepConnection := Value;
- if not Value and (FRefCount = 0) then Close;
- end;
- end;
-
- procedure TDatabase.SetParams(Value: TStrings);
- begin
- CheckInactive;
- FParams.Assign(Value);
- end;
-
- procedure TDatabase.SetSessionName(const Value: string);
- begin
- if csReading in ComponentState then
- FSessionName := Value
- else
- begin
- CheckInactive;
- if FSessionName <> Value then
- begin
- FSessionName := Value;
- CheckSessionName(False);
- end;
- end;
- end;
-
- procedure TDatabase.SetTraceFlags(Value: TTraceFlags);
- begin
- if Connected and IsSQLBased then
- DbiSetProp(hDBIObj(FHandle), dbTraceMode, Integer(Word(Value)));
- end;
-
- procedure TDatabase.SetExclusive(Value: Boolean);
- begin
- CheckInactive;
- FExclusive := Value;
- end;
-
- procedure TDatabase.SetReadOnly(Value: Boolean);
- begin
- CheckInactive;
- FReadOnly := Value;
- end;
-
- procedure TDatabase.StartTransaction;
- var
- TransHandle: HDBIXAct;
- begin
- CheckActive;
- if not IsSQLBased and (TransIsolation <> tiDirtyRead) then
- DatabaseError(SLocalTransDirty, Self);
- Check(DbiBeginTran(FHandle, EXILType(FTransIsolation), TransHandle));
- end;
-
- procedure TDatabase.ValidateName(const Name: string);
- var
- Database: TDatabase;
- begin
- if (Name <> '') and (FSession <> nil) then
- begin
- Database := FSession.FindDatabase(Name);
- if (Database <> nil) and (Database <> Self) and
- not (Database.HandleShared and HandleShared) then
- begin
- if not Database.Temporary or (Database.FRefCount <> 0) then
- DatabaseErrorFmt(SDuplicateDatabaseName, [Name]);
- Database.Free;
- end;
- end;
- end;
-
- procedure TDatabase.FlushSchemaCache(const TableName: string);
- begin
- if Connected and IsSQLBased then
- Check(DbiSchemaCacheFlush(FHandle, PChar(TableName)));
- end;
-
- { TBDEDataSet }
-
- constructor TBDEDataSet.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- SetLocale(DefaultSession.Locale);
- FCacheBlobs := True;
- NestedDataSetClass := TNestedTable;
- end;
-
- destructor TBDEDataSet.Destroy;
- begin
- inherited Destroy;
- if FBlockReadBuf <> nil then
- begin
- FreeMem(FBlockReadBuf);
- FBlockReadBuf := nil;
- end;
- SetUpdateObject(nil);
- end;
-
- procedure TBDEDataSet.OpenCursor(InfoQuery: Boolean);
- var
- CursorLocale: TLocale;
- begin
- if FHandle = nil then
- FHandle := CreateHandle;
- if FHandle = nil then
- begin
- FreeTimer(True);
- raise ENoResultSet.Create(SHandleError);
- end;
- if DbiGetLdObj(FHandle, CursorLocale) = 0 then SetLocale(CursorLocale);
- inherited OpenCursor(InfoQuery);
- end;
-
- procedure TBDEDataSet.CloseCursor;
- begin
- inherited CloseCursor;
- SetLocale(DefaultSession.Locale);
- if FHandle <> nil then
- begin
- DestroyHandle;
- FHandle := nil;
- end;
- FParentDataSet := nil;
- end;
-
- function TBDEDataSet.CreateHandle: HDBICur;
- begin
- Result := nil;
- end;
-
- procedure TBDEDataSet.DestroyHandle;
- begin
- DbiRelRecordLock(FHandle, False);
- DbiCloseCursor(FHandle);
- end;
-
- procedure TBDEDataSet.InternalInitFieldDefs;
- var
- I, FieldID: Integer;
- FieldDescs: TFieldDescList;
- ValCheckDesc: VCHKDesc;
- RequiredFields: TBits;
- CursorProps: CurProps;
- FldDescCount,
- MaxFieldID,
- HiddenFieldCount: Integer;
- begin
- DbiGetCursorProps(FHandle, CursorProps);
- FldDescCount := CursorProps.iFields;
- HiddenFieldCount := 0;
- if FieldDefs.HiddenFields then
- begin
- if SetBoolProp(Handle, curGETHIDDENCOLUMNS, True) then
- begin
- DbiGetCursorProps(FHandle, CursorProps);
- HiddenFieldCount := CursorProps.iFields - FldDescCount;
- FldDescCount := CursorProps.iFields;
- end;
- end;
- RequiredFields := TBits.Create;
- try
- MaxFieldID := GetIntProp(Handle, curMAXFIELDID);
- if MaxFieldID > 0 then
- RequiredFields.Size := MaxFieldID + 1 else
- RequiredFields.Size := FldDescCount + 1;
- for I := 1 to CursorProps.iValChecks do
- begin
- DbiGetVChkDesc(FHandle, I, @ValCheckDesc);
- if ValCheckDesc.bRequired and not ValCheckDesc.bHasDefVal then
- RequiredFields[ValCheckDesc.iFldNum] := True;
- end;
- SetLength(FieldDescs, FldDescCount);
- DbiGetFieldDescs(FHandle, PFLDDesc(FieldDescs));
- FieldID := FieldNoOfs;
- I := FieldID - 1;
- FieldDefs.Clear;
- while I < FldDescCount do
- AddFieldDesc(FieldDescs, I, FieldID, RequiredFields, FieldDefs);
- if FieldDefs.HiddenFields then
- begin
- SetBoolProp(Handle, curGETHIDDENCOLUMNS, False);
- if HiddenFieldCount > 0 then
- for I := FldDescCount - HiddenFieldCount to FldDescCount - 1 do
- FieldDefs[I].Attributes := FieldDefs[I].Attributes + [faHiddenCol];
- end;
- finally
- RequiredFields.Free;
- end;
- end;
-
- procedure TBDEDataSet.GetObjectTypeNames(Fields: TFields);
- var
- Len: Word;
- I: Integer;
- TypeDesc: ObjTypeDesc;
- ObjectField: TObjectField;
- begin
- for I := 0 to Fields.Count - 1 do
- if Fields[I] is TObjectField then
- begin
- ObjectField := TObjectField(Fields[I]);
- TypeDesc.iFldNum := ObjectField.FieldNo;
- if (DbiGetProp(hDBIObj(Handle), curFIELDTYPENAME, @TypeDesc,
- SizeOf(TypeDesc), Len) = DBIERR_NONE) and (Len > 0) then
- ObjectField.ObjectType := TypeDesc.szTypeName;
- with ObjectField do
- if DataType in [ftADT, ftArray] then
- begin
- if (DataType = ftArray) and SparseArrays and
- (Fields[0].DataType = ftADT) then
- GetObjectTypeNames(TObjectField(Fields[0]).Fields) else
- GetObjectTypeNames(Fields);
- end;
- end
- end;
-
- procedure TBDEDataSet.InternalOpen;
- var
- CursorProps: CurProps;
- begin
- if CachedUpdates then Check(DbiBeginDelayedUpdates(FHandle));
- DbiGetCursorProps(FHandle, CursorProps);
- FRecordSize := CursorProps.iRecBufSize;
- BookmarkSize := CursorProps.iBookmarkSize;
- FCanModify := (CursorProps.eOpenMode = dbiReadWrite)
- and not CursorProps.bTempTable;
- FConstraintLayer := HasConstraints and CanModify;
- if FConstraintLayer then
- Check(DbiBeginConstraintLayer(nil, FHandle, @TBDEDataSet.ConstraintCallBack,
- Integer(Pointer(Self))));
- FRecNoStatus := TRecNoStatus(CursorProps.ISeqNums);
- FieldDefs.Updated := False;
- FieldDefs.Update;
- GetIndexInfo;
- if DefaultFields then CreateFields;
- BindFields(True);
- if ObjectView then GetObjectTypeNames(Fields);
- InitBufferPointers(False);
- if CachedUpdates then
- begin
- AllocCachedUpdateBuffers(True);
- SetupCallBack(UpdateCallBackRequired);
- end;
- AllocKeyBuffers;
- DbiSetToBegin(FHandle);
- PrepareCursor;
- if Filter <> '' then
- FExprFilter := CreateExprFilter(Filter, FilterOptions, 0);
- if Assigned(OnFilterRecord) then
- FFuncFilter := CreateFuncFilter(@TBDEDataSet.RecordFilter, 1);
- if Filtered then ActivateFilters;
- end;
-
- procedure TBDEDataSet.InternalClose;
- begin
- FFuncFilter := nil;
- FExprFilter := nil;
- FreeKeyBuffers;
- if CachedUpdates then
- begin
- SetupCallBack(False);
- AllocCachedUpdateBuffers(False);
- if FConstraintLayer then DbiEndConstraintLayer(FHandle);
- if FHandle <> nil then
- DbiEndDelayedUpdates(FHandle);
- end;
- BindFields(False);
- if DefaultFields then DestroyFields;
- FIndexFieldCount := 0;
- FKeySize := 0;
- FExpIndex := False;
- FCaseInsIndex := False;
- FCanModify := False;
- end;
-
- procedure TBDEDataSet.PrepareCursor;
- begin
- end;
-
- function TBDEDataSet.IsCursorOpen: Boolean;
- begin
- Result := Handle <> nil;
- end;
-
- procedure TBDEDataSet.InternalHandleException;
- begin
- Application.HandleException(Self)
- end;
-
- procedure TBDEDataSet.SetLocale(Value: TLocale);
- begin
- FLocale := Value;
- end;
-
- { Record Functions }
-
- procedure TBDEDataSet.InitBufferPointers(GetProps: Boolean);
- var
- CursorProps: CurProps;
- begin
- if GetProps then
- begin
- Check(DbiGetCursorProps(FHandle, CursorProps));
- BookmarkSize := CursorProps.iBookmarkSize;
- FRecordSize := CursorProps.iRecBufSize;
- end;
- FBlobCacheOfs := FRecordSize + CalcFieldsSize;
- FRecInfoOfs := FBlobCacheOfs + BlobFieldCount * SizeOf(Pointer);
- FBookmarkOfs := FRecInfoOfs + SizeOf(TRecInfo);
- FRecBufSize := FBookmarkOfs + BookmarkSize;
- end;
-
- function TBDEDataSet.AllocRecordBuffer: PChar;
- begin
- Result := AllocMem(FRecBufSize);
- end;
-
- procedure TBDEDataSet.FreeRecordBuffer(var Buffer: PChar);
- begin
- ClearBlobCache(Buffer);
- FreeMem(Buffer);
- end;
-
- procedure TBDEDataSet.InternalInitRecord(Buffer: PChar);
- begin
- DbiInitRecord(FHandle, Buffer);
- end;
-
- procedure TBDEDataSet.ClearBlobCache(Buffer: PChar);
- var
- I: Integer;
- begin
- if FCacheBlobs then
- for I := 0 to BlobFieldCount - 1 do
- TBlobDataArray(Buffer + FBlobCacheOfs)[I] := '';
- end;
-
- procedure TBDEDataSet.ClearCalcFields(Buffer: PChar);
- begin
- FillChar(Buffer[RecordSize], CalcFieldsSize, 0);
- end;
-
- procedure TBDEDataSet.InitRecord(Buffer: PChar);
- begin
- inherited InitRecord(Buffer);
- ClearBlobCache(Buffer);
- with PRecInfo(Buffer + FRecInfoOfs)^ do
- begin
- UpdateStatus := TUpdateStatus(usInserted);
- BookMarkFlag := bfInserted;
- RecordNumber := -1;
- end;
- end;
-
- function TBDEDataSet.GetRecord(Buffer: PChar; GetMode: TGetMode;
- DoCheck: Boolean): TGetResult;
- var
- Status: DBIResult;
- begin
- case GetMode of
- gmCurrent:
- Status := DbiGetRecord(FHandle, dbiNoLock, Buffer, @FRecProps);
- gmNext:
- Status := DbiGetNextRecord(FHandle, dbiNoLock, Buffer, @FRecProps);
- gmPrior:
- Status := DbiGetPriorRecord(FHandle, dbiNoLock, Buffer, @FRecProps);
- else
- Status := DBIERR_NONE;
- end;
- case Status of
- DBIERR_NONE:
- begin
- with PRecInfo(Buffer + FRecInfoOfs)^ do
- begin
- UpdateStatus := TUpdateStatus(FRecProps.iRecStatus);
- BookmarkFlag := bfCurrent;
- case FRecNoStatus of
- rnParadox: RecordNumber := FRecProps.iSeqNum;
- rnDBase: RecordNumber := FRecProps.iPhyRecNum;
- else
- RecordNumber := -1;
- end;
- end;
- ClearBlobCache(Buffer);
- GetCalcFields(Buffer);
- Check(DbiGetBookmark(FHandle, Buffer + FBookmarkOfs));
- Result := grOK;
- end;
- DBIERR_BOF: Result := grBOF;
- DBIERR_EOF: Result := grEOF;
- else
- Result := grError;
- if DoCheck then Check(Status);
- end;
- end;
-
- function TBDEDataSet.GetCurrentRecord(Buffer: PChar): Boolean;
- begin
- if not IsEmpty and (GetBookmarkFlag(ActiveBuffer) = bfCurrent) then
- begin
- UpdateCursorPos;
- Result := (DbiGetRecord(FHandle, dbiNoLock, Buffer, nil) = DBIERR_NONE);
- end else
- Result := False;
- end;
-
- function TBDEDataSet.GetOldRecord: PChar;
- begin
- UpdateCursorPos;
- if SetBoolProp(Handle, curDELAYUPDGETOLDRECORD, True) then
- try
- Check(DbiGetRecord(FHandle, dbiNoLock, FUpdateCBBuf.pOldRecBuf, nil));
- Result := FUpdateCBBuf.pOldRecBuf;
- finally
- SetBoolProp(Handle, curDELAYUPDGETOLDRECORD, False);
- end
- else
- Result := nil;
- end;
-
- procedure TBDEDataSet.FetchAll;
- begin
- if not EOF then
- begin
- CheckBrowseMode;
- Check(DbiSetToEnd(Handle));
- Check(DbiGetPriorRecord(FHandle, dbiNoLock, nil, nil));
- CursorPosChanged;
- end;
- end;
-
- procedure TBDEDataSet.FlushBuffers;
- begin
- CheckBrowseMode;
- Check(DbiSaveChanges(Handle));
- end;
-
- function TBDEDataSet.GetRecordCount: Integer;
- begin
- CheckActive;
- if (DbiGetExactRecordCount(FHandle, Result) <> DBIERR_NONE) and
- (DbiGetRecordCount(FHandle, Result) <> DBIERR_NONE) then
- Result := -1;
- end;
-
- function TBDEDataSet.GetRecNo: Integer;
- var
- BufPtr: PChar;
- begin
- CheckActive;
- if State = dsCalcFields then
- BufPtr := CalcBuffer else
- BufPtr := ActiveBuffer;
- Result := PRecInfo(BufPtr + FRecInfoOfs).RecordNumber;
- end;
-
- procedure TBDEDataSet.SetRecNo(Value: Integer);
- begin
- CheckBrowseMode;
- if (FRecNoStatus = rnParadox) and (Value <> RecNo) then
- begin
- DoBeforeScroll;
- if DbiSetToSeqNo(Handle, Value) = DBIERR_NONE then
- begin
- Resync([rmCenter]);
- DoAfterScroll;
- end;
- end;
- end;
-
- function TBDEDataSet.GetRecordSize: Word;
- begin
- Result := FRecordSize;
- end;
-
- function TBDEDataSet.GetActiveRecBuf(var RecBuf: PChar): Boolean;
- begin
- case State of
- dsBlockRead: RecBuf := FBlockReadBuf + (FBlockBufOfs * FRecordSize);
- dsBrowse: if IsEmpty then RecBuf := nil else RecBuf := ActiveBuffer;
- dsEdit, dsInsert: RecBuf := ActiveBuffer;
- dsSetKey: RecBuf := PChar(FKeyBuffer) + SizeOf(TKeyBuffer);
- dsCalcFields: RecBuf := CalcBuffer;
- dsFilter: RecBuf := FFilterBuffer;
- dsNewValue: if FInUpdateCallback then
- RecBuf := FUpdateCBBuf.pNewRecBuf else
- RecBuf := ActiveBuffer;
- dsOldValue: if FInUpdateCallback then
- RecBuf := FUpdateCBBuf.pOldRecBuf else
- RecBuf := GetOldRecord;
- else
- RecBuf := nil;
- end;
- Result := RecBuf <> nil;
- end;
-
- { Field Related }
-
- procedure TBDEDataSet.AddFieldDesc(FieldDescs: TFieldDescList; var DescNo: Integer;
- var FieldID: Integer; RequiredFields: TBits; FieldDefs: TFieldDefs);
- var
- FType: TFieldType;
- FSize: Word;
- FRequired: Boolean;
- FPrecision, I: Integer;
- FieldName, FName: string;
- FieldDesc: FLDDesc;
- begin
- FieldDesc := FieldDescs[DescNo];
- Inc(DescNo);
- with FieldDesc do
- begin
- NativeToAnsi(Locale, szName, FieldName);
- I := 0;
- FName := FieldName;
- while FieldDefs.IndexOf(FName) >= 0 do
- begin
- Inc(I);
- FName := Format('%s_%d', [FieldName, I]);
- end;
- if iFldType < MAXLOGFLDTYPES then
- FType := DataTypeMap[iFldType] else
- FType := ftUnknown;
- FSize := 0;
- FPrecision := 0;
- if RequiredFields.Size > FieldID then
- FRequired := RequiredFields[FieldID] else
- FRequired := False;
- case iFldType of
- fldZSTRING, fldBYTES, fldVARBYTES, fldADT, fldArray, fldRef:
- begin
- if iUnits1 = 0 then { Ignore MLSLABEL field type on Oracle }
- FType := ftUnknown else
- FSize := iUnits1;
- end;
- fldINT16, fldUINT16:
- if iLen <> 2 then FType := ftUnknown;
- fldINT32:
- if iSubType = fldstAUTOINC then
- begin
- FType := ftAutoInc;
- FRequired := False;
- end;
- fldFLOAT:
- if iSubType = fldstMONEY then FType := ftCurrency;
- fldBCD:
- begin
- FSize := Abs(iUnits2);
- FPrecision := iUnits1;
- end;
- fldBLOB:
- begin
- FSize := iUnits1;
- if (iSubType >= fldstMEMO) and (iSubType <= fldstBFILE) then
- FType := BlobTypeMap[iSubType];
- end;
- end;
- with FieldDefs.AddFieldDef do
- begin
- FieldNo := FieldID;
- Inc(FieldID);
- Name := FName;
- DataType := FType;
- Size := FSize;
- Precision := FPrecision;
- if FRequired then
- Attributes := [faRequired];
- if efldrRights = fldrREADONLY then
- Attributes := Attributes + [faReadonly];
- if iSubType = fldstFIXED then
- Attributes := Attributes + [faFixed];
- InternalCalcField := bCalcField;
- case FType of
- ftADT:
- begin
- if iSubType = fldstADTNestedTable then
- Attributes := Attributes + [faUnNamed];
- for I := 0 to iUnits1 - 1 do
- AddFieldDesc(FieldDescs, DescNo, FieldID, RequiredFields, ChildDefs);
- end;
- ftArray:
- begin
- I := FieldID;
- StrCat(StrCopy(FieldDescs[DescNo].szName, FieldDesc.szName),'[0]');
- AddFieldDesc(FieldDescs, DescNo, I, RequiredFields, ChildDefs);
- Inc(FieldID, iUnits2);
- end;
- end;
- end;
- end;
- end;
-
- function TBDEDataSet.GetBlobFieldData(FieldNo: Integer; var Buffer: TBlobByteData): Integer;
- var
- RecBuf: PChar;
- Status: DBIResult;
- DoCheck: Boolean;
- begin
- Result := 0;
- DoCheck := BlockReadSize = 0;
- if BlockReadSize > 0 then
- RecBuf := FBlockReadBuf + (FBlockBufOfs * FRecordSize) else
- if not GetActiveRecBuf(RecBuf) then Exit;
- Status := DbiOpenBlob(FHandle, RecBuf, FieldNo, dbiReadOnly);
- if Status <> DBIERR_NONE then Exit;
- try
- Status := DbiGetBlobSize(FHandle, RecBuf, FieldNo, Result);
- if (Status <> DBIERR_NONE) or (Result = 0) then Exit;
- if High(Buffer) < Result then
- SetLength(Buffer, Result + Result div 4);
- Status := DbiGetBlob(FHandle, RecBuf, FieldNo, 0, Result, Buffer, Result);
- finally
- if Status <> DBIERR_NONE then Result := 0;
- DbiFreeBlob(FHandle, RecBuf, FieldNo);
- if DoCheck then Check(Status)
- end;
- end;
-
- function TBDEDataSet.GetFieldData(FieldNo: Integer; Buffer: Pointer): Boolean;
- var
- IsBlank: LongBool;
- RecBuf: PChar;
- Status: DBIResult;
- begin
- if BlockReadSize > 0 then
- begin
- { Optimized for speed. If error, just return false }
- Status := DbiGetField(FHandle, FieldNo, FBlockReadBuf +
- (FBlockBufOfs * FRecordSize), Buffer, IsBlank);
- Result := (Status = DBIERR_NONE) and not IsBlank;
- end else
- begin
- Result := GetActiveRecBuf(RecBuf);
- if Result then
- begin
- Check(DbiGetField(FHandle, FieldNo, RecBuf, Buffer, IsBlank));
- Result := not IsBlank;
- end
- end;
- end;
-
- function TBDEDataSet.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
- var
- RecBuf: PChar;
- begin
- if Field.FieldNo > 0 then
- Result := GetFieldData(Field.FieldNo, Buffer)
- else
- begin
- if State = dsBlockRead then
- begin
- RecBuf := TempBuffer;
- Result := True;
- end else
- Result := GetActiveRecBuf(RecBuf);
- if Result and (State in [dsBrowse, dsEdit, dsInsert, dsCalcFields, dsBlockRead]) then
- begin
- Inc(RecBuf, FRecordSize + Field.Offset);
- Result := Boolean(RecBuf[0]);
- if Result and (Buffer <> nil) then
- Move(RecBuf[1], Buffer^, Field.DataSize);
- end;
- end;
- end;
-
- procedure TBDEDataSet.SetFieldData(Field: TField; Buffer: Pointer);
- var
- RecBuf: PChar;
- Blank: LongBool;
- begin
- with Field do
- begin
- if not (State in dsWriteModes) then DatabaseError(SNotEditing, Self);
- if (State = dsSetKey) and ((FieldNo < 0) or (FIndexFieldCount > 0) and
- not IsIndexField) then DatabaseErrorFmt(SNotIndexField, [DisplayName]);
- GetActiveRecBuf(RecBuf);
- if FieldNo > 0 then
- begin
- if State = dsCalcFields then DatabaseError(SNotEditing, Self);
- if ReadOnly and not (State in [dsSetKey, dsFilter]) then
- DatabaseErrorFmt(SFieldReadOnly, [DisplayName]);
- Validate(Buffer);
- if FieldKind <> fkInternalCalc then
- begin
- if FConstraintLayer and Field.HasConstraints and (State in [dsEdit, dsInsert]) then
- Check(DbiVerifyField(FHandle, FieldNo, Buffer, Blank));
- Check(DbiPutField(FHandle, FieldNo, RecBuf, Buffer));
- end;
- end else {fkCalculated, fkLookup}
- begin
- Inc(RecBuf, FRecordSize + Offset);
- Boolean(RecBuf[0]) := LongBool(Buffer);
- if Boolean(RecBuf[0]) then Move(Buffer^, RecBuf[1], DataSize);
- end;
- if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
- DataEvent(deFieldChange, Longint(Field));
- end;
- end;
-
- function TBDEDataSet.GetBlobData(Field: TField; Buffer: PChar): TBlobData;
- begin
- Result := TBlobDataArray(Buffer + FBlobCacheOfs)[Field.Offset];
- end;
-
- procedure TBDEDataSet.SetBlobData(Field: TField; Buffer: PChar; Value: TBlobData);
- begin
- if Buffer = ActiveBuffer then
- TBlobDataArray(Buffer + FBlobCacheOfs)[Field.Offset] := Value;
- end;
-
- function TBDEDataSet.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
- begin
- Result := TBlobStream.Create(Field as TBlobField, Mode);
- end;
-
- procedure TBDEDataSet.CloseBlob(Field: TField);
- begin
- DbiFreeBlob(Handle, ActiveBuffer, Field.FieldNo);
- end;
-
- function TBDEDataSet.GetStateFieldValue(State: TDataSetState; Field: TField): Variant;
- begin
- CheckCachedUpdateMode;
- Result := inherited GetStateFieldValue(State, Field);
- end;
-
- procedure TBDEDataSet.SetStateFieldValue(State: TDataSetState; Field: TField; const Value: Variant);
- begin
- CheckCachedUpdateMode;
- inherited SetStateFieldValue(State, Field, Value);
- end;
-
- function TBDEDataSet.Translate(Src, Dest: PChar; ToOem: Boolean): Integer;
- begin
- Result := StrLen(Src);
- if ToOem then
- AnsiToNativeBuf(Locale, Src, Dest, Result) else
- NativeToAnsiBuf(Locale, Src, Dest, Result);
- if Src <> Dest then Dest[Result] := #0;
- end;
-
- function TBDEDataSet.GetFieldFullName(Field: TField): string;
- var
- Len: Word;
- AttrDesc: ObjAttrDesc;
- Buffer: array[0..1024] of Char;
- begin
- if Field.FieldNo > 0 then
- begin
- AttrDesc.iFldNum := Field.FieldNo;
- AttrDesc.pszAttributeName := Buffer;
- Check(DbiGetProp(HDBIOBJ(Handle), curFIELDFULLNAME, @AttrDesc,
- SizeOf(Buffer), Len));
- NativeToAnsi(Locale, Buffer, Result);
- end else
- Result := inherited GetFieldFullName(Field);
- end;
-
- { Navigation / Editing }
-
- procedure TBDEDataSet.InternalFirst;
- begin
- Check(DbiSetToBegin(FHandle));
- end;
-
- procedure TBDEDataSet.InternalLast;
- begin
- Check(DbiSetToEnd(FHandle));
- end;
-
- procedure TBDEDataSet.InternalEdit;
- begin
- Check(DbiGetRecord(FHandle, dbiWriteLock, ActiveBuffer, nil));
- ClearBlobCache(ActiveBuffer);
- end;
-
- procedure TBDEDataSet.InternalInsert;
- begin
- SetBoolProp(Handle, curMAKECRACK, True);
- CursorPosChanged;
- end;
-
- procedure TBDEDataSet.InternalPost;
- begin
- if State = dsEdit then
- Check(DbiModifyRecord(FHandle, ActiveBuffer, True)) else
- Check(DbiInsertRecord(FHandle, dbiNoLock, ActiveBuffer));
- end;
-
- procedure TBDEDataSet.InternalDelete;
- var
- Result: DBIResult;
- begin
- Result := DbiDeleteRecord(FHandle, nil);
- if (Result <> DBIERR_NONE) and (ErrCat(Result) <> ERRCAT_NOTFOUND) then
- Check(Result);
- end;
-
- function TBDEDataSet.IsSequenced: Boolean;
- begin
- Result := (FRecNoStatus = rnParadox) and (not Filtered);
- end;
-
- function TBDEDataSet.GetCanModify: Boolean;
- begin
- Result := FCanModify or ForceUpdateCallback;
- end;
-
- procedure TBDEDataSet.InternalRefresh;
- begin
- if (DataSetField <> nil) and (DataSetField.DataType = ftReference) then
- Check(DbiForceRecordReread(FHandle, ActiveBuffer)) else
- Check(DbiForceReread(FHandle));
- end;
-
- procedure TBDEDataSet.Post;
- begin
- inherited Post;
- if State = dsSetKey then
- PostKeyBuffer(True);
- end;
-
- procedure TBDEDataSet.Cancel;
- begin
- inherited Cancel;
- if State = dsSetKey then
- PostKeyBuffer(False);
- end;
-
- procedure TBDEDataSet.InternalCancel;
- begin
- if State = dsEdit then
- DbiRelRecordLock(FHandle, False);
- end;
-
- procedure TBDEDataSet.InternalAddRecord(Buffer: Pointer; Append: Boolean);
- begin
- if Append then
- Check(DbiAppendRecord(FHandle, Buffer)) else
- Check(DbiInsertRecord(FHandle, dbiNoLock, Buffer));
- end;
-
- procedure TBDEDataSet.InternalGotoBookmark(Bookmark: TBookmark);
- begin
- Check(DbiSetToBookmark(FHandle, Bookmark));
- end;
-
- procedure TBDEDataSet.InternalSetToRecord(Buffer: PChar);
- begin
- InternalGotoBookmark(Buffer + FBookmarkOfs);
- end;
-
- function TBDEDataSet.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
- begin
- Result := PRecInfo(Buffer + FRecInfoOfs).BookmarkFlag;
- end;
-
- procedure TBDEDataSet.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
- begin
- PRecInfo(Buffer + FRecInfoOfs).BookmarkFlag := Value;
- end;
-
- procedure TBDEDataSet.GetBookmarkData(Buffer: PChar; Data: Pointer);
- begin
- Move(Buffer[FBookmarkOfs], Data^, BookmarkSize);
- end;
-
- procedure TBDEDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
- begin
- Move(Data^, Buffer[FBookmarkOfs], BookmarkSize);
- end;
-
- function TBDEDataSet.CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Integer;
- const
- RetCodes: array[Boolean, Boolean] of ShortInt = ((2,CMPLess),(CMPGtr,CMPEql));
- begin
- { Check for uninitialized bookmarks }
- Result := RetCodes[Bookmark1 = nil, Bookmark2 = nil];
- if Result = 2 then
- begin
- if Handle <> nil then
- DbiCompareBookmarks(Handle, Bookmark1, Bookmark2, Result);
- if Result = CMPKeyEql then Result := CMPEql;
- end;
- end;
-
- function TBDEDataSet.BookmarkValid(Bookmark: TBookmark): Boolean;
- begin
- Result := Handle <> nil;
- if Result then
- begin
- CursorPosChanged;
- Result := (DbiSetToBookmark(FHandle, Bookmark) = DBIERR_NONE) and
- (DbiGetRecord(FHandle, dbiNOLOCK, nil, nil) = DBIERR_NONE)
- end;
- end;
-
- procedure TBDEDataSet.SetBlockReadSize(Value: Integer);
-
- function CanBlockRead: Boolean;
- var
- i: Integer;
- begin
- Result := (BufferCount <= 1) and (DataSetField = nil);
- if Result then
- for i := 0 to FieldCount - 1 do
- if (Fields[i].DataType in [ftDataSet, ftReference]) then
- begin
- Result := False;
- break;
- end;
- end;
-
- procedure FreeBuffer;
- begin
- if FBlockReadBuf <> nil then
- begin
- FreeMem(FBlockReadBuf);
- FBlockReadBuf := nil;
- end;
- end;
-
- const
- DEFBLOCKSIZE = 64 * 1024;
- var
- Size: Integer;
- begin
- if Value <> BlockReadSize then
- begin
- if Value > 0 then
- begin
- if EOF or not CanBlockRead then Exit;
- FreeBuffer;
- UpdateCursorPos;
- DbiSetProp(HDBIObj(FHandle), curMAKECRACK, 0);
- if Value = MaxInt then
- Size := DEFBLOCKSIZE else
- Size := Value * FRecordSize;
- FBlockReadBuf := AllocMem(Size);
- FBlockBufSize := Size div FRecordSize;
- FBlockBufOfs := FBlockBufSize; { Force read of data }
- FBlockBufCount := FBlockBufSize;
- FBlockReadCount := 0;
- inherited;
- BlockReadNext;
- end else
- begin
- inherited;
- // CursorPosChanged;
- // Resync([]);
- FreeBuffer;
- end;
- end;
- end;
-
- procedure TBDEDataSet.BlockReadNext;
- var
- Status: DbiResult;
- begin
- if FBlockBufOfs >= FBlockBufCount - 1 then
- begin
- if FBlockBufCount < FBlockBufSize then Last else
- begin
- Status := DbiReadBlock(FHandle, FBlockBufCount, FBlockReadBuf);
- if (Status <> DBIERR_NONE) and (Status <> DBIERR_EOF) then
- Check(Status);
- if (FBlockBufCount = 0) and (Status = DBIERR_EOF) then Last;
- Inc(FBlockReadCount, FBlockBufCount);
- FBlockBufOfs := 0;
- end
- end else
- Inc(FBlockBufOfs);
- if CalcFieldsSize > 0 then
- GetCalcFields(TempBuffer);
- DataEvent(deDataSetScroll, -1);
- end;
-
- { Index / Ranges }
-
- procedure TBDEDataSet.GetIndexInfo;
- var
- IndexDesc: IDXDesc;
- begin
- if DbiGetIndexDesc(FHandle, 0, IndexDesc) = DBIERR_NONE then
- begin
- FExpIndex := IndexDesc.bExpIdx;
- FCaseInsIndex := IndexDesc.bCaseInsensitive;
- if not ExpIndex then
- begin
- FIndexFieldCount := IndexDesc.iFldsInKey;
- FIndexFieldMap := IndexDesc.aiKeyFld;
- end;
- FKeySize := IndexDesc.iKeyLen;
- end;
- end;
-
- procedure TBDEDataSet.SwitchToIndex(const IndexName, TagName: string);
- var
- Status: DBIResult;
- begin
- ResetCursorRange;
- UpdateCursorPos;
- Status := DbiSwitchToIndex(FHandle, PChar(IndexName),
- PChar(TagName), 0, True);
- if Status = DBIERR_NOCURRREC then
- Status := DbiSwitchToIndex(FHandle, PChar(IndexName),
- PChar(TagName), 0, False);
- Check(Status);
- FKeySize := 0;
- FExpIndex := False;
- FCaseInsIndex := False;
- FIndexFieldCount := 0;
- SetBufListSize(0);
- InitBufferPointers(True);
- try
- SetBufListSize(BufferCount + 1);
- except
- SetState(dsInactive);
- CloseCursor;
- raise;
- end;
- GetIndexInfo;
- end;
-
- function TBDEDataSet.GetIndexField(Index: Integer): TField;
- var
- FieldNo: Integer;
- begin
- if (Index < 0) or (Index >= FIndexFieldCount) then
- DatabaseError(SFieldIndexError, Self);
- FieldNo := FIndexFieldMap[Index];
- Result := FieldByNumber(FieldNo);
- if Result = nil then
- DatabaseErrorFmt(SIndexFieldMissing, [FieldDefs[FieldNo - 1].Name], Self);
- end;
-
- procedure TBDEDataSet.SetIndexField(Index: Integer; Value: TField);
- begin
- GetIndexField(Index).Assign(Value);
- end;
-
- function TBDEDataSet.GetIndexFieldCount: Integer;
- begin
- Result := FIndexFieldCount;
- end;
-
- procedure TBDEDataSet.AllocKeyBuffers;
- var
- KeyIndex: TKeyIndex;
- begin
- try
- for KeyIndex := Low(TKeyIndex) to High(TKeyIndex) do
- FKeyBuffers[KeyIndex] := InitKeyBuffer(
- AllocMem(SizeOf(TKeyBuffer) + FRecordSize));
- except
- FreeKeyBuffers;
- raise;
- end;
- end;
-
- procedure TBDEDataSet.FreeKeyBuffers;
- var
- KeyIndex: TKeyIndex;
- begin
- for KeyIndex := Low(TKeyIndex) to High(TKeyIndex) do
- DisposeMem(FKeyBuffers[KeyIndex], SizeOf(TKeyBuffer) + FRecordSize);
- end;
-
- function TBDEDataSet.InitKeyBuffer(Buffer: PKeyBuffer): PKeyBuffer;
- begin
- FillChar(Buffer^, SizeOf(TKeyBuffer) + FRecordSize, 0);
- DbiInitRecord(FHandle, PChar(Buffer) + SizeOf(TKeyBuffer));
- Result := Buffer;
- end;
-
- procedure TBDEDataSet.CheckSetKeyMode;
- begin
- if State <> dsSetKey then DatabaseError(SNotEditing, Self);
- end;
-
- function TBDEDataSet.SetCursorRange: Boolean;
- var
- RangeStart, RangeEnd: PKeyBuffer;
- StartKey, EndKey: PChar;
- IndexBuffer: PChar;
- UseStartKey, UseEndKey, UseKey: Boolean;
- begin
- Result := False;
- if not (
- BuffersEqual(FKeyBuffers[kiRangeStart], FKeyBuffers[kiCurRangeStart],
- SizeOf(TKeyBuffer) + FRecordSize) and
- BuffersEqual(FKeyBuffers[kiRangeEnd], FKeyBuffers[kiCurRangeEnd],
- SizeOf(TKeyBuffer) + FRecordSize)) then
- begin
- IndexBuffer := AllocMem(KeySize * 2);
- try
- UseStartKey := True;
- UseEndKey := True;
- RangeStart := FKeyBuffers[kiRangeStart];
- if RangeStart.Modified then
- begin
- StartKey := PChar(RangeStart) + SizeOf(TKeyBuffer);
- UseStartKey := DbiExtractKey(Handle, StartKey, IndexBuffer) = 0;
- end
- else StartKey := nil;
- RangeEnd := FKeyBuffers[kiRangeEnd];
- if RangeEnd.Modified then
- begin
- EndKey := PChar(RangeEnd) + SizeOf(TKeyBuffer);
- UseEndKey := DbiExtractKey(Handle, EndKey, IndexBuffer + KeySize) = 0;
- end
- else EndKey := nil;
- UseKey := UseStartKey and UseEndKey;
- if UseKey then
- begin
- if StartKey <> nil then StartKey := IndexBuffer;
- if EndKey <> nil then EndKey := IndexBuffer + KeySize;
- end;
- Check(DbiSetRange(FHandle, UseKey,
- RangeStart.FieldCount, 0, StartKey, not RangeStart.Exclusive,
- RangeEnd.FieldCount, 0, EndKey, not RangeEnd.Exclusive));
- Move(FKeyBuffers[kiRangeStart]^, FKeyBuffers[kiCurRangeStart]^,
- SizeOf(TKeyBuffer) + FRecordSize);
- Move(FKeyBuffers[kiRangeEnd]^, FKeyBuffers[kiCurRangeEnd]^,
- SizeOf(TKeyBuffer) + FRecordSize);
- DestroyLookupCursor;
- Result := True;
- finally
- FreeMem(IndexBuffer, KeySize * 2);
- end;
- end;
- end;
-
- function TBDEDataSet.ResetCursorRange: Boolean;
- begin
- Result := False;
- if FKeyBuffers[kiCurRangeStart].Modified or
- FKeyBuffers[kiCurRangeEnd].Modified then
- begin
- Check(DbiResetRange(FHandle));
- InitKeyBuffer(FKeyBuffers[kiCurRangeStart]);
- InitKeyBuffer(FKeyBuffers[kiCurRangeEnd]);
- DestroyLookupCursor;
- Result := True;
- end;
- end;
-
- procedure TBDEDataSet.SetLinkRanges(MasterFields: TList);
- var
- I: Integer;
- SaveState: TDataSetState;
- begin
- SaveState := SetTempState(dsSetKey);
- try
- FKeyBuffer := InitKeyBuffer(FKeyBuffers[kiRangeStart]);
- FKeyBuffer^.Modified := True;
- for I := 0 to MasterFields.Count - 1 do
- GetIndexField(I).Assign(TField(MasterFields[I]));
- FKeyBuffer^.FieldCount := MasterFields.Count;
- finally
- RestoreState(SaveState);
- end;
- Move(FKeyBuffers[kiRangeStart]^, FKeyBuffers[kiRangeEnd]^,
- SizeOf(TKeyBuffer) + FRecordSize);
- end;
-
- function TBDEDataSet.GetKeyBuffer(KeyIndex: TKeyIndex): PKeyBuffer;
- begin
- Result := FKeyBuffers[KeyIndex];
- end;
-
- procedure TBDEDataSet.SetKeyBuffer(KeyIndex: TKeyIndex; Clear: Boolean);
- begin
- CheckBrowseMode;
- FKeyBuffer := FKeyBuffers[KeyIndex];
- Move(FKeyBuffer^, FKeyBuffers[kiSave]^, SizeOf(TKeyBuffer) + FRecordSize);
- if Clear then InitKeyBuffer(FKeyBuffer);
- SetState(dsSetKey);
- SetModified(FKeyBuffer.Modified);
- DataEvent(deDataSetChange, 0);
- end;
-
- procedure TBDEDataSet.PostKeyBuffer(Commit: Boolean);
- begin
- DataEvent(deCheckBrowseMode, 0);
- if Commit then
- FKeyBuffer.Modified := Modified else
- Move(FKeyBuffers[kiSave]^, FKeyBuffer^, SizeOf(TKeyBuffer) + FRecordSize);
- SetState(dsBrowse);
- DataEvent(deDataSetChange, 0);
- end;
-
- function TBDEDataSet.GetKeyExclusive: Boolean;
- begin
- CheckSetKeyMode;
- Result := FKeyBuffer.Exclusive;
- end;
-
- procedure TBDEDataSet.SetKeyExclusive(Value: Boolean);
- begin
- CheckSetKeyMode;
- FKeyBuffer.Exclusive := Value;
- end;
-
- function TBDEDataSet.GetKeyFieldCount: Integer;
- begin
- CheckSetKeyMode;
- Result := FKeyBuffer.FieldCount;
- end;
-
- procedure TBDEDataSet.SetKeyFieldCount(Value: Integer);
- begin
- CheckSetKeyMode;
- FKeyBuffer.FieldCount := Value;
- end;
-
- procedure TBDEDataSet.SetKeyFields(KeyIndex: TKeyIndex;
- const Values: array of const);
- var
- I: Integer;
- SaveState: TDataSetState;
- begin
- if ExpIndex then DatabaseError(SCompositeIndexError, Self);
- if FIndexFieldCount = 0 then DatabaseError(SNoFieldIndexes, Self);
- SaveState := SetTempState(dsSetKey);
- try
- FKeyBuffer := InitKeyBuffer(FKeyBuffers[KeyIndex]);
- for I := 0 to High(Values) do GetIndexField(I).AssignValue(Values[I]);
- FKeyBuffer^.FieldCount := High(Values) + 1;
- FKeyBuffer^.Modified := Modified;
- finally
- RestoreState(SaveState);
- end;
- end;
-
- function TBDEDataSet.GetIsIndexField(Field: TField): Boolean;
- var
- I: Integer;
- begin
- if (State = dsSetKey) and (FIndexFieldCount = 0) and FExpIndex then
- Result := True else
- begin
- Result := False;
- with Field do
- if FieldNo > 0 then
- for I := 0 to FIndexFieldCount - 1 do
- if FIndexFieldMap[I] = FieldNo then
- begin
- Result := True;
- Exit;
- end;
- end;
- end;
-
- function TBDEDataSet.MapsToIndex(Fields: TList;
- CaseInsensitive: Boolean): Boolean;
- var
- I: Integer;
- HasStr: Boolean;
- begin
- Result := False;
- HasStr := False;
- for I := 0 to Fields.Count - 1 do
- begin
- HasStr := TField(Fields[I]).DataType in [ftString, ftFixedChar, ftWideString];
- if HasStr then break;
- end;
- if (CaseInsensitive <> FCaseInsIndex) and HasStr then Exit;
- if Fields.Count > FIndexFieldCount then Exit;
- for I := 0 to Fields.Count - 1 do
- if TField(Fields[I]).FieldNo <> FIndexFieldMap[I] then Exit;
- Result := True;
- end;
-
- { Filters }
-
- procedure TBDEDataSet.ActivateFilters;
- begin
- if FExprFilter <> nil then
- begin
- if DbiActivateFilter(FHandle, FExprFilter) <> DBIERR_NONE then
- begin
- DbiDropFilter(FHandle, FExprFilter);
- FExprFilter := CreateExprFilter(Filter, FilterOptions, 0);
- Check(DbiActivateFilter(FHandle, FExprFilter));
- end;
- end;
- if FFuncFilter <> nil then
- begin
- if DbiActivateFilter(FHandle, FFuncFilter) <> DBIERR_NONE then
- begin
- DbiDropFilter(FHandle, FFuncFilter);
- FFuncFilter := CreateFuncFilter(@TBDEDataSet.RecordFilter, 1);
- Check(DbiActivateFilter(FHandle, FFuncFilter));
- end;
- end;
- end;
-
- procedure TBDEDataSet.DeactivateFilters;
- begin
- if FFuncFilter <> nil then Check(DbiDeactivateFilter(FHandle, FFuncFilter));
- if FExprFilter <> nil then Check(DbiDeactivateFilter(FHandle, FExprFilter));
- end;
-
- function TBDEDataSet.CreateExprFilter(const Expr: string;
- Options: TFilterOptions; Priority: Integer): HDBIFilter;
- var
- Parser: TExprParser;
- begin
- Parser := TExprParser.Create(Self, Expr, Options, [], '', nil, FldTypeMap);
- try
- Check(DbiAddFilter(FHandle, 0, Priority, False, PCANExpr(Parser.FilterData),
- nil, Result));
- finally
- Parser.Free;
- end;
- end;
-
- function TBDEDataSet.CreateFuncFilter(FilterFunc: Pointer;
- Priority: Integer): HDBIFilter;
- begin
- Check(DbiAddFilter(FHandle, Integer(Self), Priority, False, nil,
- PFGENFilter(FilterFunc), Result));
- end;
-
- {$WARNINGS OFF}
- function TBDEDataSet.CreateLookupFilter(Fields: TList; const Values: Variant;
- Options: TLocateOptions; Priority: Integer): HDBIFilter;
- var
- I: Integer;
- Filter: TFilterExpr;
- Expr, Node: PExprNode;
- FilterOptions: TFilterOptions;
- begin
- if loCaseInsensitive in Options then
- FilterOptions := [foNoPartialCompare, foCaseInsensitive] else
- FilterOptions := [foNoPartialCompare];
- Filter := TFilterExpr.Create(Self, FilterOptions, [], '', nil, FldTypeMap);
- try
- if Fields.Count = 1 then
- begin
- Node := Filter.NewCompareNode(TField(Fields[0]), coEQ, Values);
- Expr := Node;
- end else
- for I := 0 to Fields.Count - 1 do
- begin
- Node := Filter.NewCompareNode(TField(Fields[I]), coEQ, Values[I]);
- if I = 0 then
- Expr := Node else
- Expr := Filter.NewNode(enOperator, coAND, Unassigned, Expr, Node);
- end;
- if loPartialKey in Options then Node^.FPartial := True;
- Check(DbiAddFilter(FHandle, 0, Priority, False,
- PCANExpr(Filter.GetFilterData(Expr)), nil, Result));
- finally
- Filter.Free;
- end;
- end;
- {$WARNINGS ON}
-
- procedure TBDEDataSet.SetFilterHandle(var Filter: HDBIFilter;
- Value: HDBIFilter);
- begin
- if Filtered then
- begin
- CursorPosChanged;
- DestroyLookupCursor;
- DbiSetToBegin(FHandle);
- if Filter <> nil then DbiDropFilter(FHandle, Filter);
- Filter := Value;
- if Filter <> nil then DbiActivateFilter(FHandle, Filter);
- end else
- begin
- if Filter <> nil then DbiDropFilter(FHandle, Filter);
- Filter := Value;
- end;
- end;
-
- procedure TBDEDataSet.SetFilterData(const Text: string; Options: TFilterOptions);
- var
- HFilter: HDBIFilter;
- begin
- if Active then
- begin
- CheckBrowseMode;
- if (Filter <> Text) or (FilterOptions <> Options) then
- begin
- if Text <> '' then
- HFilter := CreateExprFilter(Text, Options, 0) else
- HFilter := nil;
- SetFilterHandle(FExprFilter, HFilter);
- end;
- end;
- inherited SetFilterText(Text);
- inherited SetFilterOptions(Options);
- if Active and Filtered then First;
- end;
-
- procedure TBDEDataSet.SetFilterText(const Value: string);
- begin
- SetFilterData(Value, FilterOptions);
- end;
-
- procedure TBDEDataSet.SetFiltered(Value: Boolean);
- begin
- if Active then
- begin
- CheckBrowseMode;
- if Filtered <> Value then
- begin
- DestroyLookupCursor;
- DbiSetToBegin(FHandle);
- if Value then ActivateFilters else DeactivateFilters;
- inherited SetFiltered(Value);
- end;
- First;
- end else
- inherited SetFiltered(Value);
- end;
-
- procedure TBDEDataSet.SetFilterOptions(Value: TFilterOptions);
- begin
- SetFilterData(Filter, Value);
- end;
-
- procedure TBDEDataSet.SetOnFilterRecord(const Value: TFilterRecordEvent);
- var
- Filter: HDBIFilter;
- begin
- if Active then
- begin
- CheckBrowseMode;
- if Assigned(OnFilterRecord) <> Assigned(Value) then
- begin
- if Assigned(Value) then
- Filter := CreateFuncFilter(@TBDEDataSet.RecordFilter, 1) else
- Filter := nil;
- SetFilterHandle(FFuncFilter, Filter);
- end;
- inherited SetOnFilterRecord(Value);
- if Filtered then First;
- end else
- inherited SetOnFilterRecord(Value);
- end;
-
- function TBDEDataSet.FindRecord(Restart, GoForward: Boolean): Boolean;
- var
- Status: DBIResult;
- begin
- CheckBrowseMode;
- DoBeforeScroll;
- SetFound(False);
- UpdateCursorPos;
- CursorPosChanged;
- if not Filtered then ActivateFilters;
- try
- if GoForward then
- begin
- if Restart then Check(DbiSetToBegin(FHandle));
- Status := DbiGetNextRecord(FHandle, dbiNoLock, nil, nil);
- end else
- begin
- if Restart then Check(DbiSetToEnd(FHandle));
- Status := DbiGetPriorRecord(FHandle, dbiNoLock, nil, nil);
- end;
- finally
- if not Filtered then DeactivateFilters;
- end;
- if Status = DBIERR_NONE then
- begin
- Resync([rmExact, rmCenter]);
- SetFound(True);
- end;
- Result := Found;
- if Result then DoAfterScroll;
- end;
-
- function TBDEDataSet.RecordFilter(RecBuf: Pointer; RecNo: Integer): Smallint;
- var
- Accept: Boolean;
- SaveState: TDataSetState;
- begin
- SaveState := SetTempState(dsFilter);
- FFilterBuffer := RecBuf;
- try
- Accept := True;
- OnFilterRecord(Self, Accept);
- except
- Application.HandleException(Self);
- end;
- RestoreState(SaveState);
- Result := Ord(Accept);
- end;
-
- function TBDEDataSet.LocateRecord(const KeyFields: string;
- const KeyValues: Variant; Options: TLocateOptions;
- SyncCursor: Boolean): Boolean;
- var
- I, FieldCount, PartialLength: Integer;
- Buffer: PChar;
- Fields: TList;
- LookupCursor: HDBICur;
- Filter: HDBIFilter;
- Status: DBIResult;
- CaseInsensitive: Boolean;
- begin
- CheckBrowseMode;
- CursorPosChanged;
- Buffer := TempBuffer;
- Fields := TList.Create;
- try
- GetFieldList(Fields, KeyFields);
- CaseInsensitive := loCaseInsensitive in Options;
- if CachedUpdates then
- LookupCursor := nil
- else
- if MapsToIndex(Fields, CaseInsensitive) then
- LookupCursor := FHandle else
- LookupCursor := GetLookupCursor(KeyFields, CaseInsensitive);
- if (LookupCursor <> nil) then
- begin
- SetTempState(dsFilter);
- FFilterBuffer := Buffer;
- try
- DbiInitRecord(LookupCursor, Buffer);
- FieldCount := Fields.Count;
- if FieldCount = 1 then
- begin
- if VarIsArray(KeyValues) then
- TField(Fields.First).Value := KeyValues[0] else
- TField(Fields.First).Value := KeyValues;
- end else
- for I := 0 to FieldCount - 1 do
- TField(Fields[I]).Value := KeyValues[I];
- PartialLength := 0;
- if (loPartialKey in Options) and
- (TField(Fields.Last).DataType = ftString) then
- begin
- Dec(FieldCount);
- PartialLength := Length(TField(Fields.Last).AsString);
- end;
- Status := DbiGetRecordForKey(LookupCursor, False, FieldCount,
- PartialLength, Buffer, Buffer);
- finally
- RestoreState(dsBrowse);
- end;
- if (Status = DBIERR_NONE) and SyncCursor and
- (LookupCursor <> FHandle) then
- Status := DbiSetToCursor(FHandle, LookupCursor);
- end else
- begin
- Check(DbiSetToBegin(FHandle));
- Filter := CreateLookupFilter(Fields, KeyValues, Options, 2);
- DbiActivateFilter(FHandle, Filter);
- Status := DbiGetNextRecord(FHandle, dbiNoLock, Buffer, nil);
- DbiDropFilter(FHandle, Filter);
- end;
- finally
- Fields.Free;
- end;
- Result := Status = DBIERR_NONE;
- end;
-
- function TBDEDataSet.Lookup(const KeyFields: string; const KeyValues: Variant;
- const ResultFields: string): Variant;
- begin
- Result := Null;
- if LocateRecord(KeyFields, KeyValues, [], False) then
- begin
- SetTempState(dsCalcFields);
- try
- CalculateFields(TempBuffer);
- Result := FieldValues[ResultFields];
- finally
- RestoreState(dsBrowse);
- end;
- end;
- end;
-
- function TBDEDataSet.Locate(const KeyFields: string;
- const KeyValues: Variant; Options: TLocateOptions): Boolean;
- begin
- DoBeforeScroll;
- Result := LocateRecord(KeyFields, KeyValues, Options, True);
- if Result then
- begin
- Resync([rmExact, rmCenter]);
- DoAfterScroll;
- end;
- end;
-
- function TBDEDataSet.GetLookupCursor(const KeyFields: string;
- CaseInsensitive: Boolean): HDBICur;
- begin
- Result := nil;
- end;
-
- procedure TBDEDataSet.DestroyLookupCursor;
- begin
- end;
-
- function TBDEDataSet.HasConstraints: Boolean;
- var
- I: Integer;
- begin
- Result := True;
- if Constraints.Count > 0 then Exit;
- for I := 0 to FieldCount - 1 do
- if Fields[I].HasConstraints then Exit;
- Result := False;
- end;
-
- function TBDEDataSet.ConstraintsDisabled: Boolean;
- begin
- Result := FConstDisableCount > 0;
- end;
-
- procedure TBDEDataSet.DisableConstraints;
- begin
- if FConstDisableCount = 0 then
- SetBoolProp(Handle, curCONSTSTATE, False);
- Inc(FConstDisableCount);
- end;
-
- procedure TBDEDataSet.EnableConstraints;
- begin
- if FConstDisableCount <> 0 then
- begin
- Dec(FConstDisableCount);
- if FConstDisableCount = 0 then
- SetBoolProp(Handle, curCONSTSTATE, True);
- end;
- end;
-
- function TBDEDataSet.ConstraintCallBack(Req: DsInfoReq;
- var ADataSources: DataSources): DBIResult;
-
- function GetPChar(const S: string): PChar;
- begin
- if S <> '' then Result := PChar(Pointer(S)) else Result := '';
- end;
-
- function GetFieldConstraint: Boolean;
- var
- Field: TField;
- begin
- Result := False;
- Field := FindField(ADataSources.szSourceFldName);
- if (Field <> nil) and (Field.Required or (Field.ImportedConstraint <> '') or
- (Field.CustomConstraint <> '')) then
- begin
- StrCopy(ADataSources.szSQLExprImport, GetPChar(Field.ImportedConstraint));
- StrCopy(ADataSources.szSQLExprCustom, GetPChar(Field.CustomConstraint));
- StrCopy(ADataSources.szErrStrCustom, GetPChar(Field.ConstraintErrorMessage));
- StrCopy(ADataSources.szErrStrImport, GetPChar(Field.ConstraintErrorMessage));
- ADataSources.bRequired := Field.Required;
- Result := True;
- end;
- end;
-
- procedure GetTableConstraint;
- begin
- with ADataSources, Constraints[iNumElem - 1] do
- begin
- StrCopy(szSQLExprImport, GetPChar(ImportedConstraint));
- StrCopy(szSQLExprCustom, GetPChar(CustomConstraint));
- StrCopy(szErrStrCustom, GetPChar(ErrorMessage));
- StrCopy(szErrStrImport, GetPChar(ErrorMessage));
- end;
- end;
-
- function GetDefaultExpression: Boolean;
- var
- Field: TField;
- begin
- Result := False;
- Field := FindField(ADataSources.szSourceFldName);
- if (Field <> nil) and (Field.DefaultExpression <> '') then
- begin
- StrCopy(ADataSources.szSQLExprImport, GetPChar(Field.DefaultExpression));
- Result := True;
- end;
- end;
-
- begin
- Result := DBIERR_NA;
- try
- case Req of
- dsFieldSource: if GetFieldSource(Self, ADataSources) then Result := DBIERR_NONE;
- dsFieldDomainExpr: if GetFieldConstraint then Result := DBIERR_NONE;
- dsFieldDefault: if GetDefaultExpression then Result := DBIERR_NONE;
- dsNumTblConstraint:
- begin
- ADataSources.iNumElem := Constraints.Count;
- Result := DBIERR_NONE;
- end;
- dsTblConstraint:
- begin
- GetTableConstraint;
- Result := DBIERR_NONE;
- end;
- end;
- except
- end;
- end;
-
- { Cached Updates }
-
- procedure TBDEDataSet.AllocCachedUpdateBuffers(Allocate: Boolean);
- begin
- if Allocate then
- begin
- FUpdateCBBuf := AllocMem(SizeOf(DELAYUPDCbDesc));
- FUpdateCBBuf.pNewRecBuf := AllocMem(FRecBufSize);
- FUpdateCBBuf.pOldRecBuf := AllocMem(FRecBufSize);
- FUpdateCBBuf.iRecBufSize := FRecordSize;
- end else
- begin
- if Assigned(FUpdateCBBuf) then
- begin
- FreeMem(FUpdateCBBuf.pNewRecBuf);
- FreeMem(FUpdateCBBuf.pOldRecBuf);
- DisposeMem(FUpdateCBBuf, SizeOf(DELAYUPDCbDesc));
- end;
- end;
- end;
-
- procedure TBDEDataSet.CheckCachedUpdateMode;
- begin
- if not CachedUpdates then DatabaseError(SNoCachedUpdates, Self);
- end;
-
- function TBDEDataSet.UpdateCallbackRequired: Boolean;
- begin
- Result := FCachedUpdates and (Assigned(FOnUpdateError) or
- Assigned(FOnUpdateRecord) or Assigned(FUpdateObject));
- end;
-
- function TBDEDataSet.ForceUpdateCallback: Boolean;
- begin
- Result := FCachedUpdates and (Assigned(FOnUpdateRecord) or
- Assigned(FUpdateObject));
- end;
-
- procedure TBDEDataSet.SetCachedUpdates(Value: Boolean);
-
- procedure ReAllocBuffers;
- begin
- FreeFieldBuffers;
- FreeKeyBuffers;
- SetBufListSize(0);
- try
- InitBufferPointers(True);
- SetBufListSize(BufferCount + 1);
- AllocKeyBuffers;
- except
- SetState(dsInactive);
- CloseCursor;
- raise;
- end;
- end;
-
- begin
- if (State = dsInActive) or (csDesigning in ComponentState) then
- FCachedUpdates := Value
- else if FCachedUpdates <> Value then
- begin
- CheckBrowseMode;
- UpdateCursorPos;
- if FConstraintLayer then DbiEndConstraintLayer(FHandle);
- if FCachedUpdates then
- Check(DbiEndDelayedUpdates(FHandle)) else
- Check(DbiBeginDelayedUpdates(FHandle));
- if FConstraintLayer then
- Check(DbiBeginConstraintLayer(nil, FHandle,
- @TBDEDataSet.ConstraintCallBack, Integer(Pointer(Self))));
- FCachedUpdates := Value;
- ReAllocBuffers;
- AllocCachedUpdateBuffers(Value);
- SetupCallBack(UpdateCallBackRequired);
- Resync([]);
- end;
- end;
-
- procedure TBDEDataSet.SetupCallBack(Value: Boolean);
- begin
- if Value then
- begin
- if (csDesigning in ComponentState) then Exit;
- if not Assigned(FUpdateCallback) then
- FUpdateCallback := TBDECallback.Create(Self, Self.Handle, cbDELAYEDUPD,
- FUpdateCBBuf, SizeOf(DELAYUPDCbDesc), CachedUpdateCallBack, True);
- end
- else
- begin
- if Assigned(FUpdateCallback) then
- begin
- FUpdateCallback.Free;
- FUpdateCallback := nil;
- end;
- end;
- end;
-
- function TBDEDataSet.ProcessUpdates(UpdCmd: DBIDelayedUpdCmd): DBIResult;
- begin
- CheckCachedUpdateMode;
- UpdateCursorPos;
- Result := DbiApplyDelayedUpdates(Handle, UpdCmd);
- end;
-
- procedure TBDEDataSet.ApplyUpdates;
- var
- Status: DBIResult;
- begin
- if State <> dsBrowse then Post;
- Status := ProcessUpdates(dbiDelayedUpdPrepare);
- if Status <> DBIERR_NONE then
- if Status = DBIERR_UPDATEABORT then SysUtils.Abort
- else DbiError(Status);
- end;
-
- procedure TBDEDataSet.CommitUpdates;
- begin
- Check(ProcessUpdates(dbiDelayedUpdCommit));
- Resync([]);
- end;
-
- procedure TBDEDataSet.CancelUpdates;
- begin
- Cancel;
- ProcessUpdates(dbiDelayedUpdCancel);
- Resync([]);
- end;
-
- procedure TBDEDataSet.RevertRecord;
- var
- Status: DBIResult;
- begin
- if State in dsEditModes then Cancel;
- Status := ProcessUpdates(dbiDelayedUpdCancelCurrent);
- if not ((Status = DBIERR_NONE) or (Status = DBIERR_NOTSUPPORTED)) then
- Check(Status);
- Resync([]);
- end;
-
- function TBDEDataSet.UpdateStatus: TUpdateStatus;
- var
- BufPtr: PChar;
- begin
- if CachedUpdates then
- begin
- if State = dsCalcFields then
- BufPtr := CalcBuffer else
- BufPtr := ActiveBuffer;
- Result := PRecInfo(BufPtr + FRecInfoOfs).UpdateStatus;
- end else
- Result := usUnModified;
- end;
-
- function TBDEDataSet.CachedUpdateCallBack(CBInfo: Pointer): CBRType;
- const
- CBRetCode: array[TUpdateAction] of CBRType = (cbrAbort, cbrAbort,
- cbrSkip, cbrRetry, cbrPartialAssist);
- var
- UpdateAction: TUpdateAction;
- UpdateKind: TUpdateKind;
- begin
- FInUpdateCallBack := True;
- UpdateAction := uaFail;
- UpdateKind := TUpdateKind(ord(FUpdateCBBuf.eDelayUpdOpType)-1);
- try
- if Assigned(FOnUpdateRecord) then
- FOnUpdateRecord(Self, UpdateKind, UpdateAction)
- else
- if Assigned(FUpdateObject) then
- begin
- FUpdateObject.Apply(UpdateKind);
- UpdateAction := uaApplied;
- end
- else
- DbiError(FUpdateCBBuf.iErrCode);
- except
- on E: Exception do
- begin
- if E is EDBEngineError then
- FUpdateCBBuf.iErrCode := EDBEngineError(E).Errors[0].ErrorCode;
- if (E is EDatabaseError) and Assigned(FOnUpdateError) then
- FOnUpdateError(Self, EDatabaseError(E), UpdateKind, UpdateAction)
- else
- begin
- Application.HandleException(Self);
- UpdateAction := uaAbort;
- end;
- end;
- end;
- Result := CBRetCode[UpdateAction];
- if UpdateAction = uaAbort then FUpdateCBBuf.iErrCode := DBIERR_UPDATEABORT;
- FInUpdateCallBack := False;
- end;
-
- function TBDEDataSet.GetUpdateRecordSet: TUpdateRecordTypes;
- begin
- if Active then
- begin
- CheckCachedUpdateMode;
- Result := TUpdateRecordTypes(Byte(GetIntProp(FHandle, curDELAYUPDDISPLAYOPT)));
- end
- else
- Result := [];
- end;
-
- procedure TBDEDataSet.SetUpdateRecordSet(RecordTypes: TUpdateRecordTypes);
- begin
- CheckCachedUpdateMode;
- CheckBrowseMode;
- UpdateCursorPos;
- Check(DbiSetProp(hDbiObj(Handle), curDELAYUPDDISPLAYOPT, Longint(Byte(RecordTypes))));
- Resync([]);
- end;
-
- procedure TBDEDataSet.SetUpdateObject(Value: TDataSetUpdateObject);
- begin
- if Value <> FUpdateObject then
- begin
- if Assigned(FUpdateObject) and (FUpdateObject.DataSet = Self) then
- FUpdateObject.DataSet := nil;
- FUpdateObject := Value;
- if Assigned(FUpdateObject) then
- begin
- { If another dataset already references this updateobject, then
- remove the reference }
- if Assigned(FUpdateObject.DataSet) and
- (FUpdateObject.DataSet <> Self) then
- FUpdateObject.DataSet.UpdateObject := nil;
- FUpdateObject.DataSet := Self;
- end;
- end;
- end;
-
- procedure TBDEDataSet.SetOnUpdateError(UpdateEvent: TUpdateErrorEvent);
- begin
- if Active then SetupCallback(UpdateCallBackRequired);
- FOnUpdateError := UpdateEvent;
- end;
-
- function TBDEDataSet.GetUpdatesPending: Boolean;
- begin
- Result := GetIntProp(FHandle, curDELAYUPDNUMUPDATES) > 0;
- end;
-
- procedure TBDEDataSet.DataEvent(Event: TDataEvent; Info: Integer);
-
- procedure CheckIfParentScrolled;
- var
- ParentPosition, I: Integer;
- begin
- ParentPosition := 0;
- with FParentDataSet do
- if not IsEmpty then
- for I := 0 to BookmarkSize - 1 do
- ParentPosition := ParentPosition + Byte(ActiveBuffer[FBookmarkOfs+I]);
- if (FLastParentPos = 0) or (ParentPosition <> FLastParentPos) then
- begin
- First;
- FLastParentPos := ParentPosition;
- end else
- begin
- UpdateCursorPos;
- Resync([]);
- end;
- end;
-
- begin
- if Event = deParentScroll then CheckIfParentScrolled;
- inherited DataEvent(Event, Info);
- end;
-
- { TBDEDataSet.IProviderSupport}
-
- function TBDEDataSet.PSGetUpdateException(E: Exception; Prev: EUpdateError): EUpdateError;
- var
- PrevErr: Integer;
- begin
- if E is EDBEngineError then
- begin
- if Prev <> nil then
- PrevErr := Prev.ErrorCode else
- PrevErr := 0;
- with EDBEngineError(E).Errors[0] do
- Result := EUpdateError.Create(E.Message, '', ErrorCode, PrevErr, E);
- end else
- Result := inherited PSGetUpdateException(E, Prev);
- end;
-
- function TBDEDataSet.PSIsSQLSupported: Boolean;
- begin
- Result := True;
- end;
-
- procedure TBDEDataSet.PSReset;
- begin
- inherited PSReset;
- if Handle <> nil then
- DbiForceReread(Handle);
- end;
-
- function TBDEDataSet.PSUpdateRecord(UpdateKind: TUpdateKind; Delta: TDataSet): Boolean;
- var
- UpdateAction: TUpdateAction;
- begin
- Result := False;
- if Assigned(OnUpdateRecord) then
- begin
- UpdateAction := uaFail;
- if Assigned(FOnUpdateRecord) then
- begin
- FOnUpdateRecord(Delta, UpdateKind, UpdateAction);
- Result := UpdateAction = uaApplied;
- end;
- end;
- end;
-
- { TNestedTable }
-
- constructor TNestedTable.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- ObjectView := True;
- end;
-
- function TNestedTable.CreateHandle: HDBICur;
- var
- PHandle: HDBICur;
- begin
- if not Assigned(DataSetField) then DatabaseError(SNoDataSetField, Self);
- FParentDataSet := (DataSetField.DataSet as TBDEDataSet);
- OpenParentDataSet(FParentDataSet);
- PHandle := FParentDataSet.Handle;
- with DataSetField do
- if DataType = ftDataSet then
- Check(DbiOpenNestedTable(PHandle, FieldNo, ReadOnly, False, Result)) else
- Check(DbiOpenRef(PHandle, FieldNo, ReadOnly, False, Result));
- FieldDefs.HiddenFields := FParentDataSet.FieldDefs.HiddenFields;
- if DataSetField.IncludeObjectField then
- FieldNoOfs := 1 else
- FieldNoOfs := 2;
- end;
-
- procedure TNestedTable.DoAfterPost;
- var
- DataPtr: Pointer;
- RefData: Variant;
- RefSize: Word;
- RefBuffer: array[0..255] of Byte;
- begin
- { Assign the reference ID to the DataSetField }
- if DataSetField.DataType = ftReference then
- begin
- Check(DbiGetProp(hDBIObj(FHandle), curGETREF, @RefBuffer, SizeOf(RefBuffer), RefSize));
- if RefSize <= DataSetField.DataSize then
- begin
- RefData := VarArrayCreate([0, DataSetField.DataSize - 1], varByte);
- DataPtr := VarArrayLock(RefData);
- try
- Move(RefBuffer, DataPtr^, RefSize);
- finally
- VarArrayUnlock(RefData);
- end;
- DataSetField.AsVariant := RefData;
- end;
- end;
- inherited;
- end;
-
- procedure TNestedTable.DoBeforeInsert;
- begin
- inherited DoBeforeInsert;
- if (DataSetField.DataType = ftDataSet) and (FParentDataSet.State = dsInsert) then
- FParentDataSet.Post;
- end;
-
- procedure TNestedTable.InternalPost;
- begin
- if (DataSetField.DataType = ftReference) and (State = dsInsert) then
- begin
- if TReferenceField(DataSetField).ReferenceTableName = '' then
- DatabaseErrorFmt(SNoReferenceTableName, [DataSetField.DisplayName]);
- Check(DbiSetProp(hDBIObj(FHandle), curREFINSERTTABLENAME,
- Integer(PChar(TReferenceField(DataSetField).ReferenceTableName))));
- end;
- inherited;
- end;
-
- { TDBDataSet }
-
- constructor TDBDataSet.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- if AOwner is TDatabase then
- begin
- DatabaseName := TDatabase(AOwner).DatabaseName;
- SessionName := TDatabase(AOwner).SessionName;
- end;
- FAutoRefresh := False;
- end;
-
- procedure TDBDataSet.SetHandle(Value: HDBICur);
- begin
- Close;
- FHandle := Value;
- if Assigned(Value) then
- try
- Open;
- except
- FHandle := nil;
- raise;
- end;
- end;
-
- procedure TDBDataSet.OpenCursor(InfoQuery: Boolean);
- begin
- SetDBFlag(dbfOpened, True);
- inherited OpenCursor(InfoQuery);
- SetUpdateMode(FUpdateMode);
- if Database.IsSQLBased then
- SetupAutoRefresh
- end;
-
- procedure TDBDataSet.CloseCursor;
- begin
- inherited CloseCursor;
- SetDBFlag(dbfOpened, False);
- end;
-
- procedure TDBDataSet.CheckDBSessionName;
- var
- S: TSession;
- Database: TDatabase;
- begin
- if (SessionName <> '') and (DatabaseName <> '') then
- begin
- S := Sessions.FindSession(SessionName);
- if Assigned(S) and not Assigned(S.DoFindDatabase(DatabaseName, Self)) then
- begin
- Database := DefaultSession.DoFindDatabase(DatabaseName, Self);
- if Assigned(Database) then Database.CheckSessionName(True);
- end;
- end;
- end;
-
- function TDBDataSet.CheckOpen(Status: DBIResult): Boolean;
- begin
- case Status of
- DBIERR_NONE:
- Result := True;
- DBIERR_NOTSUFFTABLERIGHTS:
- begin
- if not DBSession.GetPassword then DbiError(Status);
- Result := False;
- end;
- else
- DbiError(Status);
- Result := False;
- end;
- end;
-
- function TDBDataSet.ConstraintsStored: Boolean;
- begin
- Result := Constraints.Count > 0;
- end;
-
- procedure TDBDataSet.Disconnect;
- begin
- Close;
- end;
-
- function TDBDataSet.GetDBHandle: HDBIDB;
- begin
- if FDatabase <> nil then
- Result := FDatabase.Handle else
- Result := nil;
- end;
-
- function TDBDataSet.GetDBLocale: TLocale;
- begin
- if Database <> nil then
- Result := Database.Locale else
- Result := nil;
- end;
-
- function TDBDataSet.GetDBSession: TSession;
- begin
- if (FDatabase <> nil) then
- Result := FDatabase.Session else
- Result := Sessions.FindSession(SessionName);
- if Result = nil then Result := DefaultSession;
- end;
-
- function TDBDataSet.OpenDatabase: TDatabase;
- begin
- with Sessions.List[FSessionName] do
- Result := DoOpenDatabase(FDatabasename, Self.Owner);
- end;
-
- procedure TDBDataSet.CloseDatabase(Database: TDatabase);
- begin
- if Assigned(Database) then
- Database.Session.CloseDatabase(Database);
- end;
-
- procedure TDBDataSet.SetDatabaseName(const Value: string);
- begin
- if csReading in ComponentState then
- FDatabaseName := Value
- else if FDatabaseName <> Value then
- begin
- CheckInactive;
- if FDatabase <> nil then DatabaseError(SDatabaseOpen, Self);
- FDatabaseName := Value;
- DataEvent(dePropertyChange, 0);
- end;
- end;
-
- function TDBDataSet.SetDBFlag(Flag: Integer; Value: Boolean): Boolean;
- begin
- Result := Flag in DBFlags;
- if Value then
- begin
- if not Result then
- begin
- if FDBFlags = [] then
- begin
- CheckDBSessionName;
- FDatabase := OpenDatabase;
- FDatabase.RegisterClient(Self);
- SetLocale(FDatabase.Locale);
- if FDatabase.Temporary and (csDesigning in ComponentState) then
- FDatabase.Session.LoadSMClient(True);
- end;
- Include(FDBFlags, Flag);
- end;
- end else
- begin
- if Result then
- begin
- Exclude(FDBFlags, Flag);
- if FDBFlags = [] then
- begin
- SetLocale(DBLocale);
- FDatabase.UnregisterClient(Self);
- FDatabase.Session.CloseDatabase(FDatabase);
- FDatabase := nil;
- end;
- end;
- end;
- end;
-
- procedure TDBDataSet.SetSessionName(const Value: string);
- begin
- CheckInactive;
- FSessionName := Value;
- DataEvent(dePropertyChange, 0);
- end;
-
- procedure TDBDataSet.SetUpdateMode(const Value: TUpdateMode);
- begin
- if (FHandle <> nil) and Database.IsSQLBased and CanModify then
- Check(DbiSetProp(hDbiObj(FHandle), curUPDLOCKMODE, Longint(Value)));
- FUpdateMode := Value;
- end;
-
- { AutoRefresh }
- procedure TDBDataSet.SetAutoRefresh(const Value: Boolean);
- begin
- CheckInactive;
- FAutoRefresh := Value;
- end;
-
- procedure TDBDataSet.SetupAutoRefresh;
- const
- PropFlags: array[TAutoRefreshFlag] of LongInt = (0, curFIELDISAUTOINCR, curFIELDISDEFAULT);
- var
- I: Integer;
- ColDesc: ServerColDesc;
- begin
- if AutoRefresh then
- Check(DbiSetProp(hDbiObj(FHandle), curAUTOREFETCH, Longint(True)));
-
- for I := 0 to Fields.Count - 1 do
- with Fields[I] do
- if AutoGenerateValue <> arNone then
- begin
- ColDesc.iFldNum := I + 1;
- ColDesc.bServerCol := True;
- Check(DbiSetProp(hDbiObj(FHandle), PropFlags[AutoGenerateValue], LongInt(@ColDesc)));
- end;
- end;
-
- { TDBDataSet.IProviderSupport }
-
- procedure TDBDataSet.PSGetAttributes(List: TList);
- var
- Attr: PPacketAttribute;
- begin
- inherited PSGetAttributes(List);
- if Locale <> nil then
- begin
- New(Attr);
- List.Add(Attr);
- with Attr^ do
- begin
- Name := 'LCID';
- Value := Integer(TOSBLObj(Locale^).LdLCID);
- IncludeInDelta := False;
- end;
- end;
- end;
-
- function TDBDataSet.PSIsSQLBased: Boolean;
- var
- InProvider: Boolean;
- begin
- InProvider := SetDBFlag(dbfProvider, True);
- try
- Result := Database.IsSQLBased;
- finally
- SetDBFlag(dbfProvider, InProvider);
- end;
- end;
-
- function TDBDataSet.PSGetQuoteChar: string;
- var
- Q: Char;
- Len: Word;
- InProvider: Boolean;
- begin
- InProvider := SetDBFlag(dbfProvider, True);
- try
- Result := '';
- if PSIsSQLBased then
- begin
- Q := #0;
- DbiGetProp(HDBIObj(Database.Handle), dbQUOTECHAR, @Q, SizeOf(Q), Len);
- if Q <> #0 then
- Result := Q;
- end else
- Result := '"';
- finally
- SetDBFlag(dbfProvider, InProvider);
- end;
- end;
-
- function TDBDataSet.PSInTransaction: Boolean;
- var
- InProvider: Boolean;
- begin
- if not Assigned(Database) or not Database.Connected then
- Result := False
- else
- begin
- InProvider := SetDBFlag(dbfProvider, True);
- try
- Result := Database.InTransaction;
- finally
- SetDBFlag(dbfProvider, InProvider);
- end;
- end;
- end;
-
- procedure TDBDataSet.PSStartTransaction;
- begin
- SetDBFlag(dbfProvider, True);
- try
- if not PSIsSQLBased then
- Database.TransIsolation := tiDirtyRead;
- Database.StartTransaction;
- except
- SetDBFlag(dbfProvider, False);
- raise;
- end;
- end;
-
- procedure TDBDataSet.PSEndTransaction(Commit: Boolean);
- const
- EndType: array[Boolean] of eXEnd = (xendABORT, xendCOMMIT);
- begin
- try
- Database.ClearStatements;
- Database.EndTransaction(EndType[Commit]);
- finally
- SetDBFlag(dbfProvider, False);
- end;
- end;
-
- function TDBDataSet.PSExecuteStatement(const ASQL: string; AParams: TParams;
- ResultSet: Pointer = nil): Integer;
- var
- InProvider: Boolean;
- Cursor: hDBICur;
- begin
- InProvider := SetDBFlag(dbfProvider, True);
- try
- if Assigned(ResultSet) then
- begin
- Result := Database.Execute(ASQL, AParams, True, @Cursor);
- TDataSet(ResultSet^) := TDBDataSet.Create(nil);
- TDBDataSet(ResultSet^).SetHandle(Cursor);
- end else
- Result := Database.Execute(ASQL, AParams, True, nil);
- finally
- SetDBFlag(dbfProvider, InProvider);
- end;
- end;
-
- function TDBDataSet.PSUpdateRecord(UpdateKind: TUpdateKind; Delta: TDataSet): Boolean;
-
- procedure AssignParams(DataSet: TDataSet; Params: TParams);
- var
- I: Integer;
- Old: Boolean;
- Param: TParam;
- PName: string;
- Field: TField;
- Value: Variant;
- begin
- 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 := DataSet.FindField(PName);
- if not Assigned(Field) then Continue;
- if Old then Param.AssignFieldValue(Field, Field.OldValue) else
- begin
- Value := Field.NewValue;
- if VarIsEmpty(Value) then Value := Field.OldValue;
- Param.AssignFieldValue(Field, Value);
- end;
- end;
- end;
-
- var
- SQL: string;
- Params: TParams;
- begin
- Result := inherited PSUpdateRecord(UpdateKind, Delta);
- if not Result and Assigned(FUpdateObject) and (FUpdateObject is TSQLUpdateObject) then
- begin
- SQL := TSQLUpdateObject(FUpdateObject).GetSQL(UpdateKind).Text;
- if SQL <> '' then
- begin
- Params := TParams.Create;
- try
- Params.ParseSQL(SQL, True);
- AssignParams(Delta, Params);
- if PSExecuteStatement(SQL, Params) = 0 then
- DatabaseError(SRecordChanged);
- Result := True;
- finally
- Params.Free;
- end;
- end;
- end;
- 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(nil, Name, Buffer, DBIMAXTBLNAMELEN) else
- Result := nil;
- end;
-
- procedure TBatchMove.Execute;
- type
- TFieldMap = array of Word;
- var
- SourceActive, DestinationActive: Boolean;
- BatchMode: TBatchMode;
- I: Integer;
- FieldCount: Word;
- FieldMap: TFieldMap;
- 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
- DatabaseError(SInvalidBatchMove, Self);
- 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;
- SetLength(FieldMap, FieldCount);
- for I := 0 to FMappings.Count - 1 do
- begin
- GetMappingNames;
- FieldMap[Destination.FieldDefs.Find(DestName).FieldNo-1] :=
- 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 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.SetMappings(Value: TStrings);
- begin
- FMappings.Assign(Value);
- end;
-
- procedure TBatchMove.SetSource(Value: TBDEDataSet);
- begin
- FSource := Value;
- if Value <> nil then Value.FreeNotification(Self);
- end;
-
- { TIndexFiles }
-
- constructor TIndexFiles.Create(AOwner: TTable);
- begin
- inherited Create;
- FOwner := AOwner;
- end;
-
- function TIndexFiles.Add(const S: string): Integer;
- begin
- with FOwner do
- begin
- if Active then OpenIndexFile(S);
- IndexDefs.Updated := False;
- end;
- Result := inherited Add(S);
- 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);
- IndexDefs.Updated := False;
- end;
- end;
-
- procedure TIndexFiles.Delete(Index: Integer);
- begin
- with FOwner do
- begin
- if Active then CloseIndexFile(Strings[Index]);
- IndexDefs.Updated := False;
- end;
- inherited Delete(Index);
- end;
-
- { TTable }
-
- constructor TTable.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FIndexDefs := TIndexDefs.Create(Self);
- FMasterLink := TMasterDataLink.Create(Self);
- FMasterLink.OnMasterChange := MasterChanged;
- FMasterLink.OnMasterDisable := MasterDisabled;
- FIndexFiles := TIndexFiles.Create(Self);
- FDefaultIndex := True;
- end;
-
- destructor TTable.Destroy;
- begin
- inherited Destroy;
- FIndexFiles.Free;
- FMasterLink.Free;
- FIndexDefs.Free;
- 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
- SIndexName: DBITBLNAME;
- OpenMode: DbiOpenMode;
- RetCode: DbiResult;
- IndexID: Word;
- I: Integer;
- begin
- Result := nil;
- OpenMode := OpenModes[FReadOnly or ForceUpdateCallback];
- if DefaultIndex then
- IndexID := 0 else
- IndexID := NODEFAULTINDEX;
- while True do
- begin
- RetCode := DbiOpenTable(DBHandle, NativeTableName, GetTableTypeName,
- PChar(IndexName), PChar(IndexTag), IndexID, OpenMode, ShareModes[FExclusive],
- xltField, False, nil, Result);
- if RetCode = DBIERR_TABLEREADONLY then
- OpenMode := dbiReadOnly
- else if CheckOpen(RetCode) then Break;
- end;
- if IsXBaseTable 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
- CursorLocale: TLocale;
- IndexName, IndexTag: string;
- begin
- if FTableName = '' then DatabaseError(SNoTableName, Self);
- IndexDefs.Updated := False;
- if Database.IsSQLBased then
- begin
- GetIndexParams(FIndexName, FFieldsIndex, IndexName, IndexTag);
- Result := GetHandle(IndexName, IndexTag);
- end else
- begin
- { For local tables, open the table first then switch the index }
- Result := GetHandle('', '');
- { Set the FHandle & Locale before calling GetIndexParams }
- FHandle := Result;
- if DbiGetLdObj(Result, CursorLocale) = 0 then SetLocale(CursorLocale);
- GetIndexParams(FIndexName, FFieldsIndex, IndexName, IndexTag);
- if (IndexName <> '') and IsProductionIndex(IndexName) then
- Check(DbiSwitchToIndex(Result, PChar(IndexName), PChar(IndexTag), 0, False));
- end;
- end;
-
- function TTable.GetLanguageDriverName: string;
- var
- TblName: DBITBLNAME;
- LdName: DBINAME;
- DriverName: PChar;
- S: string;
- FDb: Boolean;
- begin
- TblName[0] := #0;
- FDb := SetDBFlag(dbfDatabase, True);
- try
- if Database.IsSQLBased then
- begin
- DriverName := PChar(DBSession.GetAliasDriverName(DatabaseName));
- FmtStr(S, ':%s:%s', [DatabaseName, TableName]);
- AnsiToNative(DBLocale, S, TblName, SizeOf(TblName) - 1);
- end
- else begin
- DbiFormFullName(Database.Handle, NativeTableName, nil, TblName);
- DriverName := GetTableTypeName;
- end;
- { If the table does not exist, get the language driver for the driver }
- if DbiGetLdName(DriverName, @TblName, @LdName) <> 0 then
- DbiGetLdName(DriverName, nil, @LdName);
- finally
- SetDBFlag(dbfDatabase, FDb);
- end;
- Result := LdName;
- end;
-
- function TTable.SetTempLocale(ActiveCheck: Boolean): TLocale;
- var
- LName: string;
- TempLocale: TLocale;
- begin
- if not ActiveCheck or (FHandle = nil) then
- begin
- Result := Locale;
- LName := GetLanguageDriverName;
- if (LName <> '') and (OsLdLoadBySymbName(PChar(LName), TempLocale) = 0) then
- if TempLocale <> Locale then
- SetLocale(TempLocale) else
- OsLdUnloadObj(TempLocale);
- end else
- begin
- if DbiGetLdObj(FHandle, TempLocale) = 0 then SetLocale(TempLocale);
- Result := TempLocale;
- end;
- end;
-
- procedure TTable.RestoreLocale(LocaleSave: TLocale);
- begin
- if (LocaleSave <> Locale) and (Locale <> nil) then
- begin
- OsLdUnloadObj(FLocale);
- SetLocale(LocaleSave);
- end;
- end;
-
- procedure TTable.PrepareCursor;
- var
- IndexName, IndexTag: string;
- begin
- if IsXBaseTable then
- begin
- GetIndexParams(FIndexName, FFieldsIndex, IndexName, IndexTag);
- if not IsProductionIndex(IndexName) then SwitchToIndex(IndexName, IndexTag);
- end;
- CheckMasterRange;
- end;
-
- procedure TTable.DefChanged(Sender: TObject);
- begin
- StoreDefs := True;
- end;
-
- procedure TTable.InitFieldDefs;
- var
- I, FieldID, FldDescCount: Integer;
- FieldDescs: TFieldDescList;
- FCursor, VCursor: HDBICur;
- RequiredFields: TBits;
- ValCheckDesc: VCHKDesc;
- LocaleSave: TLocale;
- begin
- if (FHandle <> nil) then InternalInitFieldDefs else
- begin
- SetDBFlag(dbfFieldList, True);
- try
- if FTableName = '' then DatabaseError(SNoTableName, Self);
- LocaleSave := SetTempLocale(True);
- try
- while not CheckOpen(DbiOpenFieldList(DBHandle, NativeTableName,
- GetTableTypeName, False, FCursor)) do {Retry};
- try
- Check(DbiGetRecordCount(FCursor, FldDescCount));
- SetLength(FieldDescs, FldDescCount);
- { Create an array of field descriptors }
- for I := 0 to FldDescCount - 1 do
- Check(DbiGetNextRecord(FCursor, dbiNoLock, @FieldDescs[I], nil));
- { Initialize list of required fields }
- RequiredFields := TBits.Create;
- try
- if FieldDescs[FldDescCount-1].iFldNum > FldDescCount then
- RequiredFields.Size := FieldDescs[FldDescCount-1].iFldNum + 1 else
- RequiredFields.Size := FldDescCount + 1;
- if DbiOpenVChkList(DBHandle, NativeTableName, GetTableTypeName,
- VCursor) = 0 then
- try
- while DbiGetNextRecord(VCursor, dbiNoLock, @ValCheckDesc, nil) = 0 do
- if ValCheckDesc.bRequired and not ValCheckDesc.bHasDefVal then
- begin
- { Grow the RequiredFields bits if needed for array fields }
- if ValCheckDesc.iFldNum > (RequiredFields.Size - 1) then
- RequiredFields.Size := RequiredFields.Size + 100;
- RequiredFields[ValCheckDesc.iFldNum] := True;
- end;
- finally
- DbiCloseCursor(VCursor);
- end;
- { Initialize the FieldDefs }
- FieldDefs.BeginUpdate;
- try
- FieldDefs.Clear;
- I := 0;
- FieldID := 1;
- while I < FldDescCount do
- AddFieldDesc(FieldDescs, I, FieldID, RequiredFields, FieldDefs);
- finally
- FieldDefs.EndUpdate;
- end;
- finally
- RequiredFields.Free;
- end;
- finally
- DbiCloseCursor(FCursor);
- end;
- finally
- RestoreLocale(LocaleSave);
- end;
- finally
- SetDBFlag(dbfFieldList, False);
- end;
- end;
- end;
-
- procedure TTable.DestroyHandle;
- begin
- DestroyLookupCursor;
- inherited DestroyHandle;
- end;
-
- { Index / Ranges / Keys }
-
- procedure TTable.DecodeIndexDesc(const IndexDesc: IDXDesc;
- var Source, Name, FieldExpression, DescFields: string;
- var Options: TIndexOptions);
-
- procedure ConcatField(var FieldList: string; const FieldName: string);
- begin
- if FieldList = '' then
- FieldList := FieldName else
- FieldList := Format('%s;%s', [FieldList, FieldName]);
- end;
-
-
- var
- IndexOptions: TIndexOptions;
- I: Integer;
- SSource, SName: PChar;
- FieldName: string;
- 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 not bMaintained then Include(IndexOptions, ixNonMaintained);
- if bExpIdx then
- begin
- NativeToAnsi(Locale, szKeyExp, FieldExpression);
- Include(IndexOptions, ixExpression);
- end else
- begin
- FieldExpression := '';
- DescFields := '';
- for I := 0 to iFldsInKey - 1 do
- begin
- FieldName := FieldDefList[aiKeyFld[I] - 1].Name;
- ConcatField(FieldExpression, FieldName);
- if abDescending[I] then
- ConcatField(DescFields, FieldName);
- end;
- if bDescending and (DescFields = FieldExpression) then
- DescFields := '';
- end;
- Options := IndexOptions;
- end;
- end;
-
- procedure TTable.EncodeIndexDesc(var IndexDesc: IDXDesc;
- const Name, FieldExpression: string; Options: TIndexOptions;
- const DescFields: string);
-
- function IndexFieldOfs(const FieldName: string): Integer;
- var
- FieldNo: Integer;
- begin
- FieldNo := FieldDefs.Find(FieldName).FieldNo;
- for Result := 0 to IndexDesc.iFldsInKey - 1 do
- if IndexDesc.aiKeyFld[Result] = FieldNo then Exit;
- DatabaseErrorFmt(SIndexFieldMissing, [FieldName], Self);
- Result := -1;
- end;
-
- var
- Pos: Integer;
- begin
- FillChar(IndexDesc, SizeOf(IndexDesc), 0);
- with IndexDesc do
- begin
- bPrimary := ixPrimary in Options;
- bUnique := ixUnique in Options;
- bDescending := (ixDescending in Options) and (DescFields = '');
- bMaintained := not (ixNonMaintained in Options);
- { -1 for True is ignored in the Paradox driver }
- Word(bCaseInsensitive) := Word(ixCaseInsensitive in Options);
- if IsXBaseTable then
- begin
- if bMaintained then
- AnsiToNative(Locale, Name, szTagName, SizeOf(szTagName) - 1) else
- AnsiToNative(Locale, Name, szName, SizeOf(szName) - 1);
- end else
- AnsiToNative(Locale, Name, szName, SizeOf(szName) - 1);
- if ixExpression in Options then
- begin
- bExpIdx := True;
- AnsiToNative(Locale, FieldExpression, szKeyExp, SizeOf(szKeyExp) - 1);
- end else
- begin
- Pos := 1;
- while (Pos <= Length(FieldExpression)) and (iFldsInKey < DBIMAXFLDSINKEY) do
- begin
- aiKeyFld[iFldsInKey] :=
- FieldDefs.Find(ExtractFieldName(FieldExpression, Pos)).FieldNo;
- abDescending[iFldsInKey] := bDescending;
- Inc(iFldsInKey);
- end;
- if (DescFields <> '') then
- begin
- bDescending := True;
- Pos := 1;
- while Pos <= Length(DescFields) do
- abDescending[IndexFieldOfs(ExtractFieldName(DescFields, Pos))] := True;
- end;
- end;
- end;
- end;
-
- procedure TTable.AddIndex(const Name, Fields: string; Options: TIndexOptions;
- const DescFields: string);
- var
- IndexDesc: IDXDesc;
- LocaleSave: TLocale;
- begin
- FieldDefs.Update;
- if Active then
- begin
- EncodeIndexDesc(IndexDesc, Name, Fields, Options, DescFields);
- CheckBrowseMode;
- CursorPosChanged;
- Check(DbiAddIndex(DBHandle, Handle, nil, nil, IndexDesc, nil));
- end else
- begin
- LocaleSave := SetTempLocale(False);
- try
- EncodeIndexDesc(IndexDesc, Name, Fields, Options, DescFields);
- finally
- RestoreLocale(LocaleSave);
- end;
- SetDBFlag(dbfTable, True);
- try
- Check(DbiAddIndex(DBHandle, nil, NativeTableName, GetTableTypeName,
- IndexDesc, nil));
- finally
- SetDBFlag(dbfTable, False);
- end;
- end;
- IndexDefs.Updated := False;
- end;
-
- procedure TTable.DeleteIndex(const Name: string);
- var
- IndexName, IndexTag: 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
- GetIndexParams(Name, False, IndexName, IndexTag);
- SetDBFlag(dbfTable, True);
- try
- Check(DbiDeleteIndex(DBHandle, nil, NativeTableName, GetTableTypeName,
- PChar(IndexName), PChar(IndexTag), 0));
- finally
- SetDBFlag(dbfTable, False);
- end;
- end;
- IndexDefs.Updated := False;
- 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);
- begin
- IndexDefs.Update;
- IndexDefs.GetItemNames(List);
- end;
-
- procedure TTable.GetIndexParams(const IndexName: string;
- FieldsIndex: Boolean; var IndexedName, IndexTag: string);
- var
- I: Integer;
- IndexStr: TIndexName;
- SIndexName: DBIMSG;
- SIndexTag: DBINAME;
- LocaleSave: TLocale;
- begin
- SIndexName[0] := #0;
- SIndexTag[0] := #0;
- if IndexName <> '' then
- begin
- IndexDefs.Update;
- IndexStr := IndexName;
- LocaleSave := SetTempLocale(True);
- try
- if FieldsIndex then
- if Database.FPseudoIndexes 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 IsXBaseTable and (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
- DatabaseErrorFmt(SIndexDoesNotExist, [IndexName], Self);
- AnsiToNative(nil, IndexStr, SIndexName, SizeOf(SIndexName) - 1);
- end;
- end else
- AnsiToNative(Locale, IndexStr, SIndexName, SizeOf(SIndexName) - 1);
- finally
- RestoreLocale(LocaleSave);
- end;
- end;
- IndexedName := SIndexName;
- IndexTag := SIndexTag;
- end;
-
- procedure TTable.SetIndexDefs(Value: TIndexDefs);
- begin
- IndexDefs.Assign(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);
- CheckMasterRange;
- 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.OpenIndexFile(const IndexName: string);
- var
- Buffer: DBINAME;
- begin
- CheckIndexOpen(DbiOpenIndex(Handle,
- AnsiToNative(Locale, IndexName, Buffer, SizeOf(Buffer) - 1), 0));
- end;
-
- procedure TTable.CloseIndexFile(const IndexFileName: string);
- var
- IndexName, IndexTag: string;
- Buffer: DBINAME;
- begin
- GetIndexParams(FIndexName, FFieldsIndex, IndexName, IndexTag);
- if AnsiUpperCaseFileName(IndexName) = AnsiUpperCaseFileName(IndexFileName) then
- Self.IndexName := '';
- Check(DbiCloseIndex(Handle,
- AnsiToNative(Locale, IndexFileName, Buffer, SizeOf(Buffer) - 1), 0));
- end;
-
- procedure TTable.UpdateIndexDefs;
- var
- Opts: TIndexOptions;
- IdxName, Src, Flds, DescFlds: string;
-
- procedure UpdateFromCursor;
- var
- I: Integer;
- Cursor: HDBICur;
- CursorProps: CurProps;
- IndexDescs: TIndexDescList;
- OldLocale, CursorLocale: TLocale;
- begin
- OldLocale := Locale;
- if Handle = nil then
- begin
- Cursor := GetHandle('', '');
- { For Local tables (i.e. Paradox & dBase) we need to get the locale
- from the actual Table }
- if DbiGetLdObj(Cursor, CursorLocale) = 0 then SetLocale(CursorLocale);
- end else
- Cursor := Handle;
- try
- DbiGetCursorProps(Cursor, CursorProps);
- if CursorProps.iIndexes > 0 then
- begin
- SetLength(IndexDescs, CursorProps.iIndexes);
- DbiGetIndexDescs(Cursor, PIDXDesc(IndexDescs));
- for I := 0 to CursorProps.iIndexes - 1 do
- begin
- DecodeIndexDesc(IndexDescs[I], Src, IdxName, Flds, DescFlds, Opts);
- with IndexDefs.AddIndexDef do
- begin
- Name := IdxName;
- Fields := Flds;
- DescFields := DescFlds;
- Options := Opts;
- if Src <> '' then
- Source := Src;
- end;
- end;
- end;
- finally
- if (Cursor <> nil) and (Cursor <> Handle) then DbiCloseCursor(Cursor);
- if Locale <> OldLocale then SetLocale(OldLocale);
- end;
- end;
-
- procedure UpdateFromIndexList;
- var
- FCursor: HDBICur;
- IndexDesc: IDXDesc;
- begin
- while not CheckOpen(DbiOpenIndexList(DBHandle, NativeTableName,
- GetTableTypeName, FCursor)) do {Retry};
- try
- while DbiGetNextRecord(FCursor, dbiNoLock, @IndexDesc, nil) = 0 do
- if IndexDesc.bMaintained then
- begin
- DecodeIndexDesc(IndexDesc, Src, IdxName, Flds, DescFlds, Opts);
- with IndexDefs.AddIndexDef do
- begin
- Name := IdxName;
- Fields := Flds;
- DescFields := DescFlds;
- Options := Opts;
- end;
- end;
- finally
- DbiCloseCursor(FCursor);
- end;
- end;
-
- begin
- SetDBFlag(dbfIndexList, True);
- try
- FieldDefs.Update;
- IndexDefs.Clear;
- if IsCursorOpen or not Database.IsSQLBased then
- UpdateFromCursor else
- UpdateFromIndexList;
- finally
- SetDBFlag(dbfIndexList, False);
- end;
- end;
-
- function TTable.IsProductionIndex(const IndexName: string): Boolean;
- begin
- Result := True;
- if IsXBaseTable and (IndexName <> '') then
- if AnsiUpperCase(ExtractFileExt(IndexName)) = '.NDX' then
- Result := False
- else Result := AnsiUpperCaseFileName(ChangeFileExt(NativeTableName, '')) =
- AnsiUpperCaseFileName(ChangeFileExt(IndexName, ''));
- end;
-
- function TTable.GetExists: Boolean;
- var
- H: HDBICur;
- E: DBIResult;
- begin
- Result := Active;
- if Result or (TableName = '') then Exit;
- SetDBFlag(dbfTable, True);
- try
- if Database.IsSQLBased then
- begin
- { Assume (get fields) faster than (get tables & find this table) }
- E := DbiOpenFieldList(DBHandle, NativeTableName, nil, False, H);
- Result := E = DBIERR_NONE;
- if Result then DbiCloseCursor(H)
- else if (E <> DBIERR_NOSUCHTABLE) and (E <> DBIERR_OBJNOTFOUND) then DbiError(E);
- end else Result := FileExists(GetFileName);
- finally
- SetDBFlag(dbfTable, False);
- 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.GotoKey: Boolean;
- var
- KeyBuffer: PKeyBuffer;
- IndexBuffer, RecBuffer: PChar;
- UseKey: Boolean;
- begin
- CheckBrowseMode;
- DoBeforeScroll;
- 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]);
- if Result then DoAfterScroll;
- 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.SetKey;
- begin
- SetKeyBuffer(kiLookup, True);
- end;
-
- procedure TTable.EditKey;
- begin
- SetKeyBuffer(kiLookup, False);
- end;
-
- procedure TTable.ApplyRange;
- begin
- CheckBrowseMode;
- if SetCursorRange then First;
- end;
-
- procedure TTable.CancelRange;
- begin
- CheckBrowseMode;
- UpdateCursorPos;
- if ResetCursorRange then Resync([]);
- 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.EditRangeEnd;
- begin
- SetKeyBuffer(kiRangeEnd, False);
- end;
-
- procedure TTable.EditRangeStart;
- begin
- SetKeyBuffer(kiRangeStart, False);
- end;
-
- procedure TTable.UpdateRange;
- begin
- SetLinkRanges(FMasterLink.Fields);
- end;
-
- function TTable.GetLookupCursor(const KeyFields: string;
- CaseInsensitive: Boolean): HDBICur;
- var
- IndexFound, FieldsIndex: Boolean;
- KeyIndexName, IndexName, IndexTag: string;
- KeyIndex: TIndexDef;
- begin
- if (KeyFields <> FLookupKeyFields) or
- (CaseInsensitive <> FLookupCaseIns) then
- begin
- DestroyLookupCursor;
- IndexFound := False;
- FieldsIndex := False;
- { If a range is active, don't use a lookup cursor }
- if not FKeyBuffers[kiCurRangeStart].Modified and
- not FKeyBuffers[kiCurRangeEnd].Modified then
- begin
- if Database.FPseudoIndexes 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) and
- (CaseInsensitive = (ixCaseInsensitive in KeyIndex.Options)) then
- begin
- KeyIndexName := KeyIndex.Name;
- FieldsIndex := False;
- IndexFound := True;
- end;
- end;
- if IndexFound and (Length(KeyFields) < DBIMAXMSGLEN) then
- begin
- Check(DbiCloneCursor(Handle, True, False, FLookupHandle));
- GetIndexParams(KeyIndexName, FieldsIndex, IndexName, IndexTag);
- Check(DbiSwitchToIndex(FLookupHandle, PChar(IndexName),
- PChar(IndexTag), 0, False));
- end;
- FLookupKeyFields := KeyFields;
- FLookupCaseIns := CaseInsensitive;
- end;
- end;
- Result := FLookupHandle;
- end;
-
- procedure TTable.DestroyLookupCursor;
- begin
- if FLookupHandle <> nil then
- begin
- DbiCloseCursor(FLookupHandle);
- FLookupHandle := nil;
- FLookupKeyFields := '';
- end;
- end;
-
- procedure TTable.GotoCurrent(Table: TTable);
- begin
- CheckBrowseMode;
- Table.CheckBrowseMode;
- if (AnsiCompareText(DatabaseName, Table.DatabaseName) <> 0) or
- (AnsiCompareText(TableName, Table.TableName) <> 0) then
- DatabaseError(STableMismatch, Self);
- Table.UpdateCursorPos;
- Check(DbiSetToCursor(Handle, Table.Handle));
- DoBeforeScroll;
- Resync([rmExact, rmCenter]);
- DoAfterScroll;
- end;
-
- procedure TTable.GetDetailLinkFields(MasterFields, DetailFields: TList);
- var
- i: Integer;
- Idx: TIndexDef;
- begin
- MasterFields.Clear;
- DetailFields.Clear;
- if (MasterSource <> nil) and (MasterSource.DataSet <> nil) and
- (Self.MasterFields <> '') then
- begin
- Idx := nil;
- MasterSource.DataSet.GetFieldList(MasterFields, Self.MasterFields);
- UpdateIndexDefs;
- if IndexName <> '' then
- Idx := IndexDefs.Find(IndexName)
- else if IndexFieldNames <> '' then
- Idx := IndexDefs.GetIndexForFields(IndexFieldNames, False)
- else
- for i := 0 to IndexDefs.Count - 1 do
- if ixPrimary in IndexDefs[i].Options then
- begin
- Idx := IndexDefs[i];
- break;
- end;
- if Idx <> nil then
- GetFieldList(DetailFields, Idx.Fields);
- end;
- end;
-
- { Master / Detail }
-
- procedure TTable.CheckMasterRange;
- begin
- if FMasterLink.Active and (FMasterLink.Fields.Count > 0) then
- begin
- SetLinkRanges(FMasterLink.Fields);
- SetCursorRange;
- end;
- end;
-
- procedure TTable.MasterChanged(Sender: TObject);
- begin
- CheckBrowseMode;
- UpdateRange;
- ApplyRange;
- end;
-
- procedure TTable.MasterDisabled(Sender: TObject);
- begin
- CancelRange;
- end;
-
- function TTable.GetDataSource: TDataSource;
- begin
- Result := FMasterLink.DataSource;
- end;
-
- procedure TTable.SetDataSource(Value: TDataSource);
- begin
- if IsLinkedTo(Value) then DatabaseError(SCircularDataLink, Self);
- FMasterLink.DataSource := Value;
- end;
-
- function TTable.GetMasterFields: string;
- begin
- Result := FMasterLink.FieldNames;
- end;
-
- procedure TTable.SetMasterFields(const Value: string);
- begin
- FMasterLink.FieldNames := Value;
- end;
-
- procedure TTable.DoOnNewRecord;
- var
- I: Integer;
- begin
- if FMasterLink.Active and (FMasterLink.Fields.Count > 0) then
- for I := 0 to FMasterLink.Fields.Count - 1 do
- IndexFields[I] := TField(FMasterLink.Fields[I]);
- inherited DoOnNewRecord;
- end;
-
- { Table Manipulation }
-
- function TTable.BatchMove(ASource: TBDEDataSet; 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.CreateTable;
- var
- LocaleSave: TLocale;
- IndexDescs: TIndexDescList;
- TableDesc: CRTblDesc;
- FieldDescs: TFieldDescList;
- ValChecks: TValCheckList;
- DriverTypeName: DBINAME;
- SQLLName: DBINAME;
- PSQLLName: PChar;
- LvlFldDesc: FLDDesc;
- Level: DBINAME;
-
- procedure InitTableSettings;
- var
- PTblType: PChar;
- begin
- FillChar(TableDesc, SizeOf(TableDesc), 0);
- with TableDesc do
- begin
- AnsiToNative(Locale, TableName, szTblName, SizeOf(szTblName) - 1);
- PTblType := GetTableTypeName;
- if Assigned(PTblType) then StrCopy(szTblType, PTblType);
- if FTableLevel > 0 then
- begin
- iOptParams := 1;
- StrCopy(@Level, PChar(IntToStr(FTableLevel)));
- pOptData := @Level;
- StrCopy(LvlFldDesc.szName, szCFGDRVLEVEL);
- LvlFldDesc.iLen := StrLen(Level) + 1;
- LvlFldDesc.iOffset := 0;
- pfldOptParams := @LvlFldDesc;
- end;
- end;
- end;
-
- procedure InitFieldDescriptors;
- var
- I: Integer;
- TempFieldDescs: TFieldDescList;
- begin
- with TableDesc do
- begin
- InitFieldDefsFromFields;
- iFldCount := FieldDefs.Count;
- SetLength(TempFieldDescs, iFldCount);
- for I := 0 to FieldDefs.Count - 1 do
- with FieldDefs[I] do
- begin
- EncodeFieldDesc(TempFieldDescs[I], Name, DataType, Size, Precision);
- if Required then Inc(iValChkCount);
- end;
- SetLength(FieldDescs, iFldCount);
- pFldDesc := BDE.PFLDDesc(FieldDescs);
- PSQLLName := nil;
- if Database.IsSQLBased then
- if DbiGetLdNameFromDB(DBHandle, nil, SQLLName) = 0 then
- PSQLLName := SQLLName;
- Check(DbiTranslateRecordStructure(nil, iFldCount, BDE.PFLDDesc(TempFieldDescs),
- GetDriverTypeName(DriverTypeName), PSQLLName, pFLDDesc, False));
- end;
- end;
-
- procedure InitIndexDescriptors;
- var
- I: Integer;
- begin
- TableDesc.iIdxCount := IndexDefs.Count;
- SetLength(IndexDescs, TableDesc.iIdxCount);
- TableDesc.pIdxDesc := PIDXDesc(IndexDescs);
- for I := 0 to IndexDefs.Count - 1 do
- with IndexDefs[I] do
- EncodeIndexDesc(IndexDescs[I], Name, FieldExpression, Options, DescFields);
- end;
-
- procedure InitValChecks;
- var
- I, ValCheckNo: Integer;
- begin
- with TableDesc do
- if iValChkCount > 0 then
- begin
- SetLength(ValChecks, iValChkCount);
- ValCheckNo := 0;
- for I := 0 to FieldDefs.Count - 1 do
- if FieldDefs[I].Required then
- begin
- ValChecks[ValCheckNo].iFldNum := I + 1;
- ValChecks[ValCheckNo].bRequired := True;
- Inc(ValCheckNo);
- end;
- pvchkDesc := BDE.pVCHKDesc(ValChecks);
- end;
- end;
-
- begin
- CheckInactive;
- SetDBFlag(dbfTable, True);
- try
- InitTableSettings;
- LocaleSave := SetTempLocale(False);
- try
- InitFieldDescriptors;
- InitIndexDescriptors;
- InitValChecks;
- Check(DbiCreateTable(DBHandle, True, TableDesc));
- finally
- RestoreLocale(LocaleSave);
- end;
- finally
- SetDBFlag(dbfTable, False);
- end;
- end;
-
- procedure TTable.DeleteTable;
- begin
- CheckInactive;
- SetDBFlag(dbfTable, True);
- try
- Check(DbiDeleteTable(DBHandle, NativeTableName, GetTableTypeName));
- finally
- SetDBFlag(dbfTable, False);
- end;
- end;
-
- procedure TTable.EmptyTable;
- 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, NativeTableName, GetTableTypeName));
- finally
- SetDBFlag(dbfTable, False);
- end;
- end;
- end;
-
- procedure TTable.LockTable(LockType: TLockType);
- begin
- SetTableLock(LockType, True);
- end;
-
- procedure TTable.SetTableLock(LockType: TLockType; Lock: Boolean);
- var
- L: DBILockType;
- begin
- CheckActive;
- 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.UnlockTable(LockType: TLockType);
- begin
- SetTableLock(LockType, False);
- end;
-
- procedure TTable.RenameTable(const NewTableName: string);
- var
- SNewTableName: DBITBLNAME;
- begin
- CheckInactive;
- SetDBFlag(dbfTable, True);
- try
- Check(DbiRenameTable(DBHandle, NativeTableName, GetTableTypeName,
- AnsiToNative(DBLocale, NewTableName, SNewTableName,
- SizeOf(SNewTableName) - 1)));
- finally
- SetDBFlag(dbfTable, False);
- end;
- TableName := NewTableName;
- end;
-
- procedure TTable.EncodeFieldDesc(var FieldDesc: FLDDesc;
- const Name: string; DataType: TFieldType; Size, Precision: Integer);
- begin
- with FieldDesc do
- begin
- AnsiToNative(Locale, Name, szName, SizeOf(szName) - 1);
- iFldType := FldTypeMap[DataType];
- iSubType := FldSubTypeMap[DataType];
- case DataType of
- ftString, ftFixedChar, ftBytes, ftVarBytes, ftBlob..ftTypedBinary:
- iUnits1 := Size;
- ftBCD:
- begin
- { Default precision is 32, Size = Scale }
- if (Precision > 0) and (Precision <= 32) then
- iUnits1 := Precision else
- iUnits1 := 32;
- iUnits2 := Size; {Scale}
- end;
- end;
- end;
- end;
-
- procedure TTable.DataEvent(Event: TDataEvent; Info: Longint);
- begin
- if Event = dePropertyChange then IndexDefs.Updated := False;
- inherited DataEvent(Event, Info);
- end;
-
- { Informational & Property }
-
- function TTable.GetCanModify: Boolean;
- begin
- Result := inherited GetCanModify and not ReadOnly;
- 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, szCFGDBSTANDARD) = 0 then
- begin
- Result := GetTableTypeName;
- if Result <> nil then Result := StrCopy(Buffer, Result);
- end;
- end;
-
- function TTable.GetTableTypeName: PChar;
- begin
- if Database.IsSQLBased then Result := nil
- else Result := TableTypeDriverNames[GetTableType];
- end;
-
- function TTable.GetTableLevel: Integer;
- begin
- if Handle <> nil then
- Result := GetIntProp(Handle, curTABLELEVEL) else
- Result := FTableLevel;
- end;
-
- function TTable.FieldDefsStored: Boolean;
- begin
- Result := StoreDefs and (FieldDefs.Count > 0);
- end;
-
- function TTable.IndexDefsStored: Boolean;
- begin
- Result := StoreDefs and (IndexDefs.Count > 0);
- end;
-
- function TTable.IsXBaseTable: Boolean;
- begin
- Result := (TableType in [ttDBase, ttFoxPro]) or
- (CompareText(ExtractFileExt(TableName), '.DBF') = 0);
- end;
-
- function TTable.GetFileName: string;
- const
- Exts: array [TTableType] of string = ('.DB', '.DB', '.DBF', '.DBF', '.TXT');
- var
- FDb: Boolean;
- begin
- FDb := SetDBFlag(dbfDatabase, True);
- try
- Result := Database.Directory;
- if (Result <> '') and (not IsPathDelimiter(Result, Length(Result))) then
- Result := Result + '\';
- if ExtractFileExt(TableName) = '' then
- Result := Result + ChangeFileExt(TableName, Exts[TableType]) else
- Result := Result + TableName;
- finally
- SetDBFlag(dbfDatabase, FDb);
- end;
- end;
-
- function TTable.GetTableType: TTableType;
- var
- Name, Extension: string;
- FDb: Boolean;
- begin
- Result := ttDefault;
- FDb := SetDBFlag(dbfDatabase, True);
- try
- if not Database.IsSQLBased then
- if TableType = ttDefault then
- begin
- Extension := ExtractFileExt(TableName);
- if CompareText(Extension, '.DB') = 0 then Result := ttParadox
- else if CompareText(Extension, '.DBF') = 0 then
- begin
- Name := GetFileName;
- if FileExists(ChangeFileExt(Name, '.FPT')) or
- FileExists(ChangeFileExt(Name, '.CDX')) then
- Result := ttFoxPro else
- Result := ttDBase;
- end
- else if CompareText(Extension, '.TXT') = 0 then Result := ttASCII
- end else Result := TableType;
- finally
- if not FDb then SetDBFlag(dbfDatabase, False);
- end;
- end;
-
- function TTable.NativeTableName: PChar;
- begin
- if FNativeTableName[0] = #0 then
- AnsiToNative(DBLocale, FTableName, FNativeTableName, SizeOf(FNativeTableName) - 1);
- Result := FNativeTableName;
- end;
-
- procedure TTable.SetExclusive(Value: Boolean);
- begin
- CheckInactive;
- FExclusive := Value;
- end;
-
- procedure TTable.SetReadOnly(Value: Boolean);
- begin
- CheckInactive;
- FReadOnly := Value;
- end;
-
- procedure TTable.SetTableName(const Value: TFileName);
- begin
- if csReading in ComponentState then
- FTableName := Value
- else if (FTableName <> Value) then
- begin
- CheckInactive;
- IndexFiles.Clear;
- FTableName := Value;
- FNativeTableName[0] := #0;
- DataEvent(dePropertyChange, 0);
- end;
- end;
-
- procedure TTable.SetTableType(Value: TTableType);
- begin
- CheckInactive;
- FTableType := Value;
- end;
-
- { TTable.IProviderSupport }
-
- function TTable.PSGetDefaultOrder: TIndexDef;
-
- function GetIdx(IdxType: TIndexOption): TIndexDef;
- var
- i: Integer;
- begin
- Result := nil;
- for i := 0 to IndexDefs.Count - 1 do
- if IdxType in IndexDefs[i].Options then
- try
- Result := IndexDefs[i];
- GetFieldList(nil, Result.Fields);
- break;
- except
- Result := nil;
- end;
- end;
-
- var
- DefIdx: TIndexDef;
- begin
- DefIdx := nil;
- IndexDefs.Update;
- try
- if IndexName <> '' then
- DefIdx := IndexDefs.Find(IndexName)
- else if IndexFieldNames <> '' then
- DefIdx := IndexDefs.FindIndexForFields(IndexFieldNames);
- if Assigned(DefIdx) then
- GetFieldList(nil, DefIdx.Fields);
- except
- DefIdx := nil;
- end;
- if not Assigned(DefIdx) then
- DefIdx := GetIdx(ixPrimary);
- if not Assigned(DefIdx) then
- DefIdx := GetIdx(ixUnique);
- if Assigned(DefIdx) then
- begin
- Result := TIndexDef.Create(nil);
- Result.Assign(DefIdx);
- end else
- Result := nil;
- end;
-
- function TTable.PSGetIndexDefs(IndexTypes: TIndexOptions): TIndexDefs;
- begin
- Result := GetIndexDefs(IndexDefs, IndexTypes);
- end;
-
- function TTable.PSGetTableName: string;
- begin
- Result := TableName;
- end;
-
- procedure TTable.PSSetParams(AParams: TParams);
-
- procedure AssignFields;
- var
- I: Integer;
- begin
- for I := 0 to AParams.Count - 1 do
- if AParams[I].Name <> '' then
- FieldByName(AParams[I].Name).Value := AParams[I].Value else
- IndexFields[I].Value := AParams[I].Value;
- end;
-
- begin
- if AParams.Count > 0 then
- begin
- Open;
- SetRangeStart;
- AssignFields;
- SetRangeEnd;
- AssignFields;
- ApplyRange;
- end else
- if Active then CancelRange;
- PSReset;
- end;
-
- procedure TTable.PSSetCommandText(const CommandText: string);
- begin
- if CommandText <> '' then
- TableName := CommandText;
- end;
-
- function TTable.PSGetKeyFields: string;
- var
- i, Pos: Integer;
- IndexFound: Boolean;
- begin
- Result := inherited PSGetKeyFields;
- if Result = '' then
- begin
- if not Exists then Exit;
- IndexFound := False;
- IndexDefs.Update;
- for i := 0 to IndexDefs.Count - 1 do
- if ixUnique in IndexDefs[I].Options then
- begin
- Result := IndexDefs[I].Fields;
- IndexFound := (FieldCount = 0);
- if not IndexFound then
- begin
- Pos := 1;
- while Pos <= Length(Result) do
- begin
- IndexFound := FindField(ExtractFieldName(Result, Pos)) <> nil;
- if not IndexFound then Break;
- end;
- end;
- if IndexFound then Break;
- end;
- if not IndexFound then
- Result := '';
- end;
- end;
-
- { TQueryDataLink }
-
- constructor TQueryDataLink.Create(AQuery: TQuery);
- begin
- inherited Create;
- FQuery := AQuery;
- end;
-
- procedure TQueryDataLink.ActiveChanged;
- begin
- if FQuery.Active then FQuery.RefreshParams;
- end;
-
- function TQueryDataLink.GetDetailDataSet: TDataSet;
- begin
- Result := FQuery;
- 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(Self);
- end;
-
- destructor TStoredProc.Destroy;
- begin
- Destroying;
- Disconnect;
- FParams.Free;
- inherited Destroy;
- end;
-
- procedure TStoredProc.DefineProperties(Filer: TFiler);
-
- function WriteData: Boolean;
- begin
- if Filer.Ancestor <> nil then
- Result := not FParams.IsEqual(TStoredProc(Filer.Ancestor).FParams) else
- Result := FParams.Count > 0;
- end;
-
- begin
- inherited DefineProperties(Filer);
- Filer.DefineProperty('ParamData', ReadParamData, WriteParamData, WriteData);
- end;
-
- procedure TStoredProc.WriteParamData(Writer: TWriter);
- begin
- Writer.WriteCollection(Params);
- end;
-
- procedure TStoredProc.ReadParamData(Reader: TReader);
- begin
- Reader.ReadValue;
- Reader.ReadCollection(Params);
- 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;
- var
- Desc: SPParamDesc;
- Cursor: HDBICur;
- Buffer: DBISPNAME;
- ParamName: string;
- ParamDataType: TFieldType;
- begin
- AnsiToNative(DBLocale, StoredProcName, Buffer, SizeOf(Buffer)-1);
- 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, ParamName);
- if (TParamType(eParamType) = ptResult) and (ParamName = '') then
- ParamName := SResultName;
- if uFldType < MAXLOGFLDTYPES then ParamDataType := DataTypeMap[uFldType]
- else ParamDataType := ftUnknown;
- case uFldtype of
- fldFloat:
- if uSubType = fldstMONEY then ParamDataType := ftCurrency;
- fldBlob:
- if (uSubType >= fldstMEMO) and (uSubType <= fldstBFILE) then
- ParamDataType := BlobTypeMap[uSubType];
- end;
- with TParam(FParams.Add) do
- begin
- ParamType := TParamType(eParamType);
- DataType := ParamDataType;
- Name := ParamName;
- end;
- end;
- SetServerParams;
- finally
- DbiCloseCursor(Cursor);
- end;
- end;
-
- procedure TStoredProc.SetServerParams;
- var
- I: Integer;
- begin
- SetLength(FServerDescs, Params.Count);
- for I := 0 to Params.Count - 1 do
- with TParam(Params[I]), FServerDescs[I] do
- begin
- ParamName := Name;
- BindType := DataType;
- end;
- end;
-
- function TStoredProc.CheckServerParams: Boolean;
- var
- Low, I, J: Integer;
- begin
- if FServerDescs = nil then
- begin
- SetServerParams;
- Result := False;
- end else
- begin
- Low := 0;
- for I := 0 to High(FServerDescs) do
- begin
- for J := Low to Params.Count - 1 do
- with TParam(Params[J]), FServerDescs[I] do
- if Name = ParamName then
- if (DataType <> BindType) then
- begin
- Result := False;
- Exit;
- end else
- begin
- if J = Low then inc(Low);
- Break;
- end;
- end;
- Result := True;
- end;
- end;
-
- function TStoredProc.DescriptionsAvailable: Boolean;
- var
- Cursor: HDBICur;
- Buffer: DBISPNAME;
- begin
- SetDBFlag(dbfProcDesc, True);
- try
- AnsiToNative(DBLocale, StoredProcName, Buffer, SizeOf(Buffer)-1);
- Result := DbiOpenSPParamList(DBHandle, Buffer, False, OverLoad, Cursor) = 0;
- if Result then DbiCloseCursor(Cursor);
- finally
- SetDBFlag(dbfProcDesc, False);
- end;
- end;
-
- procedure TStoredProc.PrepareProc;
- var
- I: Integer;
- NumBytes, Offset: Word;
- Buffer: DBISPNAME;
- begin
- SetLength(FParamDescs, FParams.Count);
- NumBytes := 0;
- for I := 0 to FParams.Count - 1 do
- with Params[I] do
- if DataType in [ftString, ftFixedChar] then Inc(NumBytes, 255 + 2)
- else Inc(NumBytes, GetParamDataSize(Params[I]) + 2);
- SetLength(FRecordBuffer, NumBytes);
- Offset := 0;
- for I := 0 to FParams.Count - 1 do
- begin
- with Params[I], FParamDescs[I] do
- begin
- if DataType = ftUnknown then
- DatabaseErrorFmt(SNoParameterValue, [Name], Self);
- if ParamType = ptUnknown then
- DatabaseErrorFmt(SNoParameterType, [Name], Self);
- if FBindMode = pbByName then
- AnsiToNative(Locale, Name, szName, SizeOf(szName) - 1)
- else uParamNum := I + 1;
- eParamType := STMTParamType(ParamType);
- uFldType := FldTypeMap[DataType];
- uSubType := FldSubTypeMap[DataType];
- if uFldType = fldZString then
- begin
- uLen := 255;
- iUnits1 := 255;
- end else
- uLen := GetParamDataSize(Params[I]);
- uOffset := Offset;
- Inc(Offset, uLen);
- uNullOffset := NumBytes - 2 * (I + 1);
- if ParamType in [ptInput, ptInputOutput] then
- PSmallint(@FRecordBuffer[NumBytes - 2 * (I + 1)])^ := IndNull;
- end;
- end;
- AnsiToNative(Locale, StoredProcName, Buffer, SizeOf(Buffer)-1);
- Check(DbiQPrepareProc(DBHandle, Buffer, High(FParamDescs)+1,
- PSPParamDesc(FParamDescs), nil, FStmtHandle));
- end;
-
- procedure TStoredProc.GetResults;
- var
- I: Integer;
- CurPtr: PChar;
- IntPtr: ^SmallInt;
- NumBytes: Word;
- begin
- if FRecordBuffer <> nil then
- begin
- CurPtr := PChar(FRecordBuffer);
- NumBytes := High(FRecordBuffer) + 1;
- for I := 0 to FParams.Count - 1 do
- with Params[I] do
- begin
- if ParamType in [ptOutput, ptInputOutput, ptResult] then
- begin
- if DataType in [ftString, ftFixedChar] then
- NativeToAnsiBuf(Locale, CurPtr, CurPtr, StrLen(CurPtr));
- IntPtr := @FRecordBuffer[NumBytes - 2 * (I + 1)];
- if IntPtr^ = IndNull then Value := NULL
- else if IntPtr^ = IndTrunc then DatabaseErrorFmt(STruncationError, [Name])
- else SetData(CurPtr);
- end;
- if DataType in [ftString, ftFixedChar] then Inc(CurPtr, 255)
- else Inc(CurPtr, GetParamDataSize(Params[I]));
- end;
- end;
- end;
-
- procedure TStoredProc.BindParams;
- var
- I: Integer;
- CurPtr: PChar;
- NumBytes: Word;
- IntPtr: ^SmallInt;
- DrvLocale: TLocale;
- begin
- if FRecordBuffer = nil then Exit;
- if not CheckServerParams then
- begin
- SetPrepared(False);
- SetPrepared(True);
- end;
- NumBytes := High(FRecordBuffer) + 1;
- CurPtr := PChar(FRecordBuffer);
- DrvLocale := GetStatementLocale(StmtHandle);
- try
- for I := 0 to FParams.Count - 1 do
- begin
- with Params[I] do
- begin
- if ParamType in [ptInput, ptInputOutput] then
- begin
- GetParamData(Params[i], CurPtr, DrvLocale);
- IntPtr := @FRecordBuffer[NumBytes - 2 * (I + 1)];
- if IsNull then IntPtr^ := IndNull
- else IntPtr^ := 0;
- end;
- if DataType in [ftString, ftFixedChar] then
- begin
- Inc(CurPtr, 255);
- { Adjust param descriptor for string pseudo blobs }
- if ParamType = ptInput then
- with FParamDescs[I] do
- begin
- uLen := GetParamDataSize(Params[I]);
- if uFldType = fldZString then
- iUnits1 := GetDataSize - 1 {Do not include null terminator} else
- iUnits1 := GetDataSize;
- end
- end
- else
- Inc(CurPtr, GetParamDataSize(Params[I]));
- end;
- end;
- Check(DbiQSetProcParams(StmtHandle, High(FParamDescs)+1,
- PSPParamDesc(FParamDescs), FRecordBuffer));
- finally
- FreeStatementLocale(DrvLocale);
- end;
- end;
-
- procedure TStoredProc.SetPrepared(Value: Boolean);
- begin
- if Handle <> nil then DatabaseError(SDataSetOpen, Self);
- 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);
- FParamDescs := nil;
- FServerDescs := nil;
- FRecordBuffer := nil;
- FPrepared := False;
- end;
-
- procedure TStoredProc.SetPrepare(Value: Boolean);
- begin
- if Value then Prepare
- else UnPrepare;
- end;
-
- function TStoredProc.SetDBFlag(Flag: Integer; Value: Boolean): Boolean;
- begin
- if not Value and (DBFlags - [Flag] = []) then SetPrepared(False);
- Result := 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;
-
- { TStoredProc.IProviderSupport }
-
- function TStoredProc.PSGetParams: TParams;
- begin
- Result := Params;
- end;
-
- procedure TStoredProc.PSSetParams(AParams: TParams);
- begin
- if AParams.Count > 0 then
- Params.Assign(AParams);
- Close;
- end;
-
- function TStoredProc.PSGetTableName: string;
- begin
- Result := inherited PSGetTableName;
- end;
-
- procedure TStoredProc.PSExecute;
- begin
- ExecProc;
- end;
-
- procedure TStoredProc.PSSetCommandText(const CommandText: string);
- begin
- if CommandText <> '' then
- StoredProcName := CommandText;
- end;
-
- { TQuery }
-
- constructor TQuery.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FSQL := TStringList.Create;
- TStringList(SQL).OnChange := QueryChanged;
- FParams := TParams.Create(Self);
- 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 DatabaseError(SCircularDataLink, Self);
- 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
- if not (csReading in ComponentState) then
- begin
- Disconnect;
- StrDispose(SQLBinary);
- SQLBinary := nil;
- if ParamCheck or (csDesigning in ComponentState) then
- begin
- List := TParams.Create(Self);
- try
- FText := List.ParseSQL(SQL.Text, True);
- List.AssignValues(FParams);
- FParams.Clear;
- FParams.Assign(List);
- finally
- List.Free;
- end;
- end else
- FText := SQL.Text;
- DataEvent(dePropertyChange, 0);
- end else
- FText := FParams.ParseSQL(SQL.Text, False);
- 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);
-
- function WriteData: Boolean;
- begin
- if Filer.Ancestor <> nil then
- Result := not FParams.IsEqual(TQuery(Filer.Ancestor).FParams) else
- Result := FParams.Count > 0;
- end;
-
- begin
- inherited DefineProperties(Filer);
- Filer.DefineBinaryProperty('Data', ReadBinaryData, WriteBinaryData, SQLBinary <> nil);
- Filer.DefineProperty('ParamData', ReadParamData, WriteParamData, WriteData);
- end;
-
- procedure TQuery.ReadParamData(Reader: TReader);
- begin
- Reader.ReadValue;
- Reader.ReadCollection(FParams);
- end;
-
- procedure TQuery.WriteParamData(Writer: TWriter);
- begin
- Writer.WriteCollection(Params);
- 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 DatabaseError(SDataSetOpen, Self);
- if Value <> Prepared then
- begin
- if Value then
- begin
- FRowsAffected := -1;
- FCheckRowsAffected := True;
- if Length(Text) > 1 then PrepareSQL(PChar(Text))
- else DatabaseError(SEmptySQLStatement, Self);
- end
- else
- begin
- if FCheckRowsAffected then
- FRowsAffected := RowsAffected;
- FreeStatement;
- end;
- FPrepared := Value;
- end;
- end;
-
- procedure TQuery.FreeStatement;
- var
- Result: DbiResult;
- begin
- if StmtHandle <> nil then
- begin
- Result := DbiQFree(FStmtHandle);
- if not (csDestroying in ComponentState) then
- Check(Result);
- end;
- 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;
-
- function TQuery.CreateCursor(GenHandle: Boolean): HDBICur;
- begin
- if SQL.Count > 0 then
- begin
- FExecSQL := not GenHandle;
- try
- SetPrepared(True);
- finally
- FExecSQL := False;
- end;
- if FDataLink.DataSource <> nil then SetParamsFromCursor;
- Result := GetQueryCursor(GenHandle);
- end else
- begin
- DatabaseError(SEmptySQLStatement, Self);
- Result := nil;
- end;
- FCheckRowsAffected := (Result = nil);
- 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 SetQueryParams(Self, StmtHandle, Params);
- Check(DbiQExec(StmtHandle, PCursor));
- end;
-
- function TQuery.SetDBFlag(Flag: Integer; Value: Boolean): Boolean;
- var
- NewConnection: Boolean;
- begin
- if Value then
- begin
- NewConnection := DBFlags = [];
- Result := 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);
- Result := inherited SetDBFlag(Flag, Value);
- end;
- end;
-
- procedure TQuery.PrepareSQL(Value: PChar);
- begin
- GetStatementHandle(Value);
- if not Local then
- SetBoolProp(StmtHandle, stmtUNIDIRECTIONAL, FUniDirectional);
- end;
-
- procedure TQuery.GetStatementHandle(SQLText: PChar);
- const
- DataType: array[Boolean] of LongInt = (Ord(wantCanned), Ord(wantLive));
- begin
- Check(DbiQAlloc(DBHandle, qrylangSQL, FStmtHandle));
- try
- if not FExecSQL then
- Check(DBiSetProp(hDbiObj(StmtHandle), stmtLIVENESS,
- DataType[RequestLive and not ForceUpdateCallback]));
- if Local then
- begin
- SetBoolProp(StmtHandle, stmtAUXTBLS, False);
- if RequestLive and Constrained then
- SetBoolProp(StmtHandle, stmtCONSTRAINED, True);
- SetBoolProp(StmtHandle, stmtCANNEDREADONLY, True);
- end;
- while not CheckOpen(DbiQPrepare(FStmtHandle, SQLText)) do
- {Retry};
- except
- DbiQFree(FStmtHandle);
- FStmtHandle := nil;
- 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;
-
- procedure TQuery.GetDetailLinkFields(MasterFields, DetailFields: TList);
-
- function AddFieldToList(const FieldName: string; DataSet: TDataSet;
- List: TList): Boolean;
- var
- Field: TField;
- begin
- Field := DataSet.FindField(FieldName);
- if (Field <> nil) then
- List.Add(Field);
- Result := Field <> nil;
- end;
-
- var
- i: Integer;
- begin
- MasterFields.Clear;
- DetailFields.Clear;
- if (DataSource <> nil) and (DataSource.DataSet <> nil) then
- for i := 0 to Params.Count - 1 do
- if AddFieldToList(Params[i].Name, DataSource.DataSet, MasterFields) then
- AddFieldToList(Params[i].Name, Self, DetailFields);
- end;
-
- { TQuery.IProviderSupport }
-
- function TQuery.PSGetDefaultOrder: TIndexDef;
- begin
- Result := inherited PSGetDefaultOrder;
- if not Assigned(Result) then
- Result := GetIndexForOrderBy(SQL.Text, Self);
- end;
-
- function TQuery.PSGetParams: TParams;
- begin
- Result := Params;
- end;
-
- procedure TQuery.PSSetParams(AParams: TParams);
- begin
- if AParams.Count <> 0 then
- Params.Assign(AParams);
- Close;
- end;
-
- function TQuery.PSGetTableName: string;
- begin
- Result := GetTableNameFromSQL(SQL.Text);
- end;
-
- procedure TQuery.PSExecute;
- begin
- ExecSQL;
- end;
-
- procedure TQuery.PSSetCommandText(const CommandText: string);
- begin
- if CommandText <> '' then
- SQL.Text := CommandText;
- end;
-
- { TUpdateSQL }
-
- constructor TUpdateSQL.Create(AOwner: TComponent);
- var
- UpdateKind: TUpdateKind;
- begin
- inherited Create(AOwner);
- for UpdateKind := Low(TUpdateKind) to High(TUpdateKind) do
- begin
- FSQLText[UpdateKind] := TStringList.Create;
- TStringList(FSQLText[UpdateKind]).OnChange := SQLChanged;
- end;
- 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 DatabaseError(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: TBDEDataSet;
- begin
- Result := FDataSet;
- end;
-
- procedure TUpdateSQL.SetDataSet(ADataSet: TBDEDataSet);
- begin
- FDataSet := ADataSet;
- end;
-
- procedure TUpdateSQL.SetSQL(UpdateKind: TUpdateKind; Value: TStrings);
- begin
- FSQLText[UpdateKind].Assign(Value);
- end;
-
- procedure TUpdateSQL.SetSQLIndex(Index: Integer; Value: TStrings);
- begin
- SetSQL(TUpdateKind(Index), Value);
- end;
-
- procedure TUpdateSQL.SQLChanged(Sender: TObject);
- var
- UpdateKind: TUpdateKind;
- begin
- for UpdateKind := Low(TUpdateKind) to High(TUpdateKind) do
- if Sender = FSQLText[UpdateKind] then
- begin
- if Assigned(FQueries[UpdateKind]) then
- begin
- FQueries[UpdateKind].Params.Clear;
- FQueries[UpdateKind].SQL.Assign(FSQLText[UpdateKind]);
- end;
- Break;
- end;
- end;
-
- procedure TUpdateSQL.SetParams(UpdateKind: TUpdateKind);
- var
- I: Integer;
- Old: Boolean;
- Param: TParam;
- PName: string;
- Field: TField;
- Value: Variant;
- begin
- if not Assigned(FDataSet) then Exit;
- with Query[UpdateKind] do
- begin
- 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
- begin
- Value := Field.NewValue;
- if VarIsEmpty(Value) then Value := Field.OldValue;
- Param.AssignFieldValue(Field, Value);
- end;
- end;
- end;
- end;
-
- procedure TUpdateSQL.Apply(UpdateKind: TUpdateKind);
- begin
- SetParams(UpdateKind);
- ExecSQL(UpdateKind);
- end;
-
- { TBlobStream }
-
- constructor TBlobStream.Create(Field: TBlobField; Mode: TBlobStreamMode);
- var
- OpenMode: DbiOpenMode;
- begin
- FMode := Mode;
- FField := Field;
- FDataSet := FField.DataSet as TBDEDataSet;
- FFieldNo := FField.FieldNo;
- if not FDataSet.GetActiveRecBuf(FBuffer) then Exit;
- if FDataSet.State = dsFilter then
- DatabaseErrorFmt(SNoFieldAccess, [FField.DisplayName], FDataSet);
- if not FField.Modified then
- begin
- if Mode = bmRead then
- begin
- FCached := FDataSet.FCacheBlobs and (FBuffer = FDataSet.ActiveBuffer) and
- (FField.IsNull or (FDataSet.GetBlobData(FField, FBuffer) <> ''));
- OpenMode := dbiReadOnly;
- end else
- begin
- FDataSet.SetBlobData(FField, FBuffer, '');
- if FField.ReadOnly then DatabaseErrorFmt(SFieldReadOnly,
- [FField.DisplayName], FDataSet);
- if not (FDataSet.State in [dsEdit, dsInsert]) then
- DatabaseError(SNotEditing, FDataSet);
- OpenMode := dbiReadWrite;
- end;
- if not FCached then
- begin
- if FDataSet.State = dsBrowse then
- FDataSet.GetCurrentRecord(FDataSet.ActiveBuffer);
- Check(DbiOpenBlob(FDataSet.Handle, FBuffer, FFieldNo, OpenMode));
- end;
- end;
- FOpened := True;
- if Mode = bmWrite then Truncate;
- end;
-
- destructor TBlobStream.Destroy;
- begin
- if FOpened then
- begin
- if FModified then FField.Modified := True;
- if not FField.Modified and not FCached then
- DbiFreeBlob(FDataSet.Handle, FBuffer, FFieldNo);
- end;
- if FModified then
- try
- FDataSet.DataEvent(deFieldChange, Longint(FField));
- except
- Application.HandleException(Self);
- end;
- end;
-
- function TBlobStream.Read(var Buffer; Count: Longint): Longint;
- var
- Status: DBIResult;
- begin
- Result := 0;
- if FOpened then
- begin
- if FCached then
- begin
- if Count > Size - FPosition then
- Result := Size - FPosition else
- Result := Count;
- if Result > 0 then
- begin
- Move(PChar(FDataSet.GetBlobData(FField, FBuffer))[FPosition], Buffer, Result);
- Inc(FPosition, Result);
- end;
- end else
- begin
- Status := DbiGetBlob(FDataSet.Handle, FBuffer, FFieldNo, FPosition,
- Count, @Buffer, Result);
- case Status of
- DBIERR_NONE, DBIERR_ENDOFBLOB:
- begin
- if FField.Transliterate then
- NativeToAnsiBuf(FDataSet.Locale, @Buffer, @Buffer, Result);
- if FDataset.FCacheBlobs and (FBuffer = FDataSet.ActiveBuffer) and
- (FMode = bmRead) and not FField.Modified and (FPosition = FCacheSize) then
- begin
- FCacheSize := FPosition + Result;
- SetLength(FBlobData, FCacheSize);
- Move(Buffer, PChar(FBlobData)[FPosition], Result);
- if FCacheSize = Size then
- begin
- FDataSet.SetBlobData(FField, FBuffer, FBlobData);
- FBlobData := '';
- FCached := True;
- DbiFreeBlob(FDataSet.Handle, FBuffer, FFieldNo);
- end;
- end;
- Inc(FPosition, Result);
- end;
- DBIERR_INVALIDBLOBOFFSET:
- {Nothing};
- else
- DbiError(Status);
- end;
- end;
- end;
- end;
-
- function TBlobStream.Write(const Buffer; Count: Longint): Longint;
- var
- Temp: Pointer;
- begin
- Result := 0;
- if FOpened then
- begin
- if FField.Transliterate then
- begin
- GetMem(Temp, Count);
- try
- AnsiToNativeBuf(FDataSet.Locale, @Buffer, Temp, Count);
- Check(DbiPutBlob(FDataSet.Handle, FBuffer, FFieldNo, FPosition,
- Count, Temp));
- finally
- FreeMem(Temp, Count);
- end;
- end else
- Check(DbiPutBlob(FDataSet.Handle, FBuffer, FFieldNo, FPosition,
- Count, @Buffer));
- Inc(FPosition, Count);
- Result := Count;
- FModified := True;
- FDataSet.SetBlobData(FField, FBuffer, '');
- 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, FBuffer, FFieldNo, FPosition));
- FModified := True;
- FDataSet.SetBlobData(FField, FBuffer, '');
- end;
- end;
-
- function TBlobStream.GetBlobSize: Longint;
- begin
- Result := 0;
- if FOpened then
- if FCached then
- Result := Length(FDataSet.GetBlobData(FField, FBuffer)) else
- Check(DbiGetBlobSize(FDataSet.Handle, FBuffer, FFieldNo, Result));
- end;
-
- var
- SaveInitProc: Pointer;
- NeedToUninitialize: Boolean;
-
- procedure InitDBTables;
- begin
- if SaveInitProc <> nil then TProcedure(SaveInitProc);
- NeedToUninitialize := Succeeded(CoInitialize(nil));
- end;
-
- initialization
- if not IsLibrary then
- begin
- SaveInitProc := InitProc;
- InitProc := @InitDBTables;
- end;
- Sessions := TSessionList.Create;
- Session := TSession.Create(nil);
- Session.SessionName := 'Default'; { Do not localize }
- finalization
- Sessions.Free;
- Sessions := nil;
- FreeAndNil(BDEInitProcs);
- FreeTimer(True);
- if NeedToUninitialize then CoUninitialize;
- end.
-