unit KOLEdb;
{* This unit is created for KOL to allow to communicate with DB using OLE DB.
|
========================================================================
|
Copyright (C) 2001 by Vladimir Kladov.
|
This unit conains three objects TDataSource, TSession and TQuery to implement
the most important things: to connect to database, to control transactions,
to perform commands (queries) and obtain results or update tables.
|
}
interface
uses Windows, mComObj, KOL;
type
INT64 = I64;
PInt64 = PI64;
tagVariant = packed Record
vt: WORD;
reserved1,
reserved2,
reserved3: WORD;
case Integer of
0: ( bVal : Byte );
1: ( iVal : ShortInt );
2: ( lVal : Integer );
3: ( fltVal : Extended );
4: ( dblVal : Double );
5: ( boolVal : Bool );
//6: ( scode : SCODE );
//7: ( cyVal : CY );
//8: ( date : Date );
9: ( bstrVal : Pointer ); // BSTR => [ Len: Integer; array[ 1..Len ] of WideChar ]
//10:( pdecVal : ^Decimal );
end;
(*
typedef struct tagVARIANT {
VARTYPE vt;
unsigned short wReserved1;
unsigned short wReserved2;
unsigned short wReserved3;
union {
Byte bVal; // VT_UI1.
Short iVal; // VT_I2.
long lVal; // VT_I4.
float fltVal; // VT_R4.
double dblVal; // VT_R8.
VARIANT_BOOL boolVal; // VT_BOOL.
SCODE scode; // VT_ERROR.
CY cyVal; // VT_CY.
DATE date; // VT_DATE.
BSTR bstrVal; // VT_BSTR.
DECIMAL FAR* pdecVal // VT_BYREF|VT_DECIMAL.
IUnknown FAR* punkVal; // VT_UNKNOWN.
IDispatch FAR* pdispVal; // VT_DISPATCH.
SAFEARRAY FAR* parray; // VT_ARRAY|*.
Byte FAR* pbVal; // VT_BYREF|VT_UI1.
short FAR* piVal; // VT_BYREF|VT_I2.
long FAR* plVal; // VT_BYREF|VT_I4.
float FAR* pfltVal; // VT_BYREF|VT_R4.
double FAR* pdblVal; // VT_BYREF|VT_R8.
VARIANT_BOOL FAR* pboolVal; // VT_BYREF|VT_BOOL.
SCODE FAR* pscode; // VT_BYREF|VT_ERROR.
CY FAR* pcyVal; // VT_BYREF|VT_CY.
DATE FAR* pdate; // VT_BYREF|VT_DATE.
BSTR FAR* pbstrVal; // VT_BYREF|VT_BSTR.
IUnknown FAR* FAR* ppunkVal; // VT_BYREF|VT_UNKNOWN.
IDispatch FAR* FAR* ppdispVal; // VT_BYREF|VT_DISPATCH.
SAFEARRAY FAR* FAR* pparray; // VT_ARRAY|*.
VARIANT FAR* pvarVal; // VT_BYREF|VT_VARIANT.
void FAR* byref; // Generic ByRef.
char cVal; // VT_I1.
unsigned short uiVal; // VT_UI2.
unsigned long ulVal; // VT_UI4.
int intVal; // VT_INT.
unsigned int uintVal; // VT_UINT.
char FAR * pcVal; // VT_BYREF|VT_I1.
unsigned short FAR * puiVal; // VT_BYREF|VT_UI2.
unsigned long FAR * pulVal; // VT_BYREF|VT_UI4.
int FAR * pintVal; // VT_BYREF|VT_INT.
unsigned int FAR * puintVal; //VT_BYREF|VT_UINT.
};
};
*)
{============= This part of code is grabbed from OLEDB.pas ================}
const
MAXBOUND = 65535; { High bound for arrays }
DBSTATUS_S_ISNULL = $00000003;
type
PIUnknown = ^IUnknown;
PUintArray = ^TUintArray;
TUintArray = array[0..MAXBOUND] of UINT;
HROW = UINT;
PHROW = ^HROW;
PPHROW = ^PHROW;
HACCESSOR = UINT;
HCHAPTER = UINT;
DBCOLUMNFLAGS = UINT;
DBTYPE = Word;
DBKIND = UINT;
DBPART = UINT;
DBMEMOWNER = UINT;
DBPARAMIO = UINT;
DBBINDSTATUS = UINT;
const
IID_NULL : TGUID = '{00000000-0000-0000-0000-000000000000}';
IID_IDataInitialize : TGUID = '{2206CCB1-19C1-11D1-89E0-00C04FD7A829}';
CLSID_MSDAINITIALIZE: TGUID = '{2206CDB0-19C1-11D1-89E0-00C04FD7A829}';
IID_IDBInitialize : TGUID = '{0C733A8B-2A1C-11CE-ADE5-00AA0044773D}';
//IID_IDBProperties : TGUID = '{0C733A8A-2A1C-11CE-ADE5-00AA0044773D}';
IID_IDBCreateSession: TGUID = '{0C733A5D-2A1C-11CE-ADE5-00AA0044773D}';
IID_IDBCreateCommand: TGUID = '{0C733A1D-2A1C-11CE-ADE5-00AA0044773D}';
IID_ICommand : TGUID = '{0C733A63-2A1C-11CE-ADE5-00AA0044773D}';
IID_ICommandText : TGUID = '{0C733A27-2A1C-11CE-ADE5-00AA0044773D}';
IID_ICommandProperties: TGUID = '{0C733A79-2A1C-11CE-ADE5-00AA0044773D}';
IID_IRowset : TGUID = '{0C733A7C-2A1C-11CE-ADE5-00AA0044773D}';
IID_IRowsetChange : TGUID = '{0C733A05-2A1C-11CE-ADE5-00AA0044773D}';
IID_IRowsetUpdate : TGUID = '{0C733A6D-2A1C-11CE-ADE5-00AA0044773D}';
IID_IColumnsInfo : TGUID = '{0C733A11-2A1C-11CE-ADE5-00AA0044773D}';
IID_IAccessor : TGUID = '{0C733A8C-2A1C-11CE-ADE5-00AA0044773D}';
// Added By ECM !!! ==================================================
IID_ITransaction : TGUID = '{0FB15084-AF41-11CE-BD2B-204C4F4F5020}';
IID_ITransactionLocal: TGUID = '{0C733A5F-2A1C-11CE-ADE5-00AA0044773D}';
IID_ITransactionOptions: TGUID = '{3A6AD9E0-23B9-11CF-AD60-00AA00A74CCD}';
// ===================================================================
// for version 1.5 of OLE DB:
//DBGUID_DBSQL : TGUID = '{c8b522df-5cf3-11ce-ade5-00aa0044773d}';
// otherwise:
DBGUID_DBSQL : TGUID = '{C8B521FB-5CF3-11CE-ADE5-00AA0044773D}';
DBGUID_DEFAULT : TGUID = '{C8B521FB-5CF3-11CE-ADE5-00AA0044773D}';
DBGUID_SQL : TGUID = '{C8B522D7-5CF3-11CE-ADE5-00AA0044773D}';
DBPROPSET_ROWSET : TGUID = '{C8B522BE-5CF3-11CE-ADE5-00AA0044773D}';
DB_S_ENDOFROWSET = $00040EC6;
type
// *********************************************************************//
// Interface: IDBInitialize
// GUID: {0C733A8B-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
IDBInitialize = interface(IUnknown)
['{0C733A8B-2A1C-11CE-ADE5-00AA0044773D}']
function Initialize: HResult; stdcall;
function Uninitialize: HResult; stdcall;
end;
// *********************************************************************//
// Interface: IDBCreateCommand
// GUID: {0C733A1D-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
IDBCreateCommand = interface(IUnknown)
['{0C733A1D-2A1C-11CE-ADE5-00AA0044773D}']
function CreateCommand(const punkOuter: IUnknown; const riid: TGUID;
out ppCommand: IUnknown): HResult; stdcall;
end;
(*---
{ Safecall Version }
IDBCreateCommandSC = interface(IUnknown)
['{0C733A1D-2A1C-11CE-ADE5-00AA0044773D}']
procedure CreateCommand(const punkOuter: IUnknown; const riid: TGUID;
out ppCommand: IUnknown); safecall;
end;
---*)
// *********************************************************************//
// Interface: IDBCreateSession
// GUID: {0C733A5D-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
IDBCreateSession = interface(IUnknown)
['{0C733A5D-2A1C-11CE-ADE5-00AA0044773D}']
function CreateSession(const punkOuter: IUnknown; const riid: TGUID;
out ppDBSession: IUnknown): HResult; stdcall;
end;
(*---
{ Safecall Version }
IDBCreateSessionSC = interface(IUnknown)
['{0C733A5D-2A1C-11CE-ADE5-00AA0044773D}']
procedure CreateSession(const punkOuter: IUnknown; const riid: TGUID;
out ppDBSession: IUnknown); safecall;
end;
---*)
// *********************************************************************//
// Interface: IDataInitialize
// GUID: {2206CCB1-19C1-11D1-89E0-00C04FD7A829}
// *********************************************************************//
IDataInitialize = interface(IUnknown)
['{2206CCB1-19C1-11D1-89E0-00C04FD7A829}']
function GetDataSource(const pUnkOuter: IUnknown; dwClsCtx: DWORD;
pwszInitializationString: POleStr; const riid: TIID;
var DataSource: IUnknown): HResult; stdcall;
function GetInitializationString(const DataSource: IUnknown;
fIncludePassword: Boolean; out pwszInitString: POleStr): HResult; stdcall;
function CreateDBInstance(const clsidProvider: TGUID;
const pUnkOuter: IUnknown; dwClsCtx: DWORD; pwszReserved: POleStr;
riid: TIID; var DataSource: IUnknown): HResult; stdcall;
function CreateDBInstanceEx(const clsidProvider: TGUID;
const pUnkOuter: IUnknown; dwClsCtx: DWORD; pwszReserved: POleStr;
pServerInfo: PCoServerInfo; cmq: ULONG; rgmqResults: Pointer): HResult; stdcall;
function LoadStringFromStorage(pwszFileName: POleStr;
out pwszInitializationString: POleStr): HResult; stdcall;
function WriteStringToStorage(pwszFileName, pwszInitializationString: POleStr;
dwCreationDisposition: DWORD): HResult; stdcall;
end;
(*---
{ Safecall Version }
IDataInitializeSC = interface(IUnknown)
['{2206CCB1-19C1-11D1-89E0-00C04FD7A829}']
procedure GetDataSource(const pUnkOuter: IUnknown; dwClsCtx: DWORD;
pwszInitializationString: POleStr; const riid: TIID;
var DataSource: IUnknown); safecall;
procedure GetInitializationString(const DataSource: IUnknown;
fIncludePassword: Boolean; out pwszInitString: POleStr); safecall;
procedure CreateDBInstance(const clsidProvider: TGUID;
const pUnkOuter: IUnknown; dwClsCtx: DWORD; pwszReserved: POleStr;
riid: TIID; var DataSource: IUnknown); safecall;
procedure CreateDBInstanceEx(const clsidProvider: TGUID;
const pUnkOuter: IUnknown; dwClsCtx: DWORD; pwszReserved: POleStr;
pServerInfo: PCoServerInfo; cmq: ULONG; rgmqResults: PMultiQI); safecall;
procedure LoadStringFromStorage(pwszFileName: POleStr;
out pwszInitializationString: POleStr); safecall;
procedure WriteStringToStorage(pwszFileName, pwszInitializationString: POleStr;
dwCreationDisposition: DWORD); safecall;
end;
---*)
// *********************************************************************//
// Interface: ICommand
// GUID: {0C733A63-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
ICommand = interface(IUnknown)
['{0C733A63-2A1C-11CE-ADE5-00AA0044773D}']
function Cancel: HResult; stdcall;
function Execute(const punkOuter: IUnknown; const riid: TGUID;
pParams: Pointer; // var pParams: DBPARAMS;
pcRowsAffected: PInteger; ppRowset: PIUnknown): HResult; stdcall;
function GetDBSession(const riid: TGUID; out ppSession: IUnknown): HResult; stdcall;
end;
(*
{ Safecall Version }
ICommandSC = interface(IUnknown)
['{0C733A63-2A1C-11CE-ADE5-00AA0044773D}']
procedure Cancel; safecall;
procedure Execute(const punkOuter: IUnknown; const riid: TGUID; var pParams: DBPARAMS;
pcRowsAffected: PInteger; ppRowset: PIUnknown); safecall;
procedure GetDBSession(const riid: TGUID; out ppSession: IUnknown); safecall;
end;
*)
// *********************************************************************//
// Interface: ICommandText
// GUID: {0C733A27-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
ICommandText = interface(ICommand)
['{0C733A27-2A1C-11CE-ADE5-00AA0044773D}']
function GetCommandText(var pguidDialect: TGUID;
out ppwszCommand: PWideChar): HResult; stdcall;
function SetCommandText(rguidDialect: PGUID;
pwszCommand: PWideChar): HResult; stdcall;
end;
(*
{ Safecall Version }
ICommandTextSC = interface(ICommand)
['{0C733A27-2A1C-11CE-ADE5-00AA0044773D}']
procedure GetCommandText(var pguidDialect: TGUID;
out ppwszCommand: PWideChar); safecall;
procedure SetCommandText(rguidDialect: PGUID;
pwszCommand: PWideChar); safecall;
end;
*)
// *********************************************************************//
// Interface: IRowset
// GUID: {0C733A7C-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
IRowset = interface(IUnknown)
['{0C733A7C-2A1C-11CE-ADE5-00AA0044773D}']
function AddRefRows(cRows: UINT; rghRows: PUintArray; rgRefCounts: PUintArray;
rgRowStatus: PUintArray): HResult; stdcall;
function GetData(HROW: HROW; HACCESSOR: HACCESSOR; pData: Pointer): HResult; stdcall;
function GetNextRows(hReserved: HCHAPTER; lRowsOffset: Integer; cRows: Integer;
out pcRowsObtained: UINT; {var prghRows: PUintArray} prghRows: Pointer ): HResult; stdcall;
function ReleaseRows(cRows: UINT; rghRows: PUintArray; rgRowOptions,
rgRefCounts, rgRowStatus: PUintArray): HResult; stdcall;
function RestartPosition(hReserved: HCHAPTER): HResult; stdcall;
end;
(*
{ Safecall Version }
IRowsetSC = interface(IUnknown)
['{0C733A7C-2A1C-11CE-ADE5-00AA0044773D}']
procedure AddRefRows(cRows: UINT; rghRows: PUintArray; rgRefCounts: PUintArray;
rgRowStatus: PUintArray); safecall;
procedure GetData(HROW: HROW; HACCESSOR: HACCESSOR; pData: Pointer); safecall;
procedure GetNextRows(hReserved: HCHAPTER; lRowsOffset: Integer; cRows: Integer;
out pcRowsObtained: UINT; var prghRows: PUintArray); safecall;
procedure ReleaseRows(cRows: UINT; rghRows: PUintArray; rgRowOptions,
rgRefCounts, rgRowStatus: PUintArray); safecall;
procedure RestartPosition(hReserved: HCHAPTER); safecall;
end;
*)
// *********************************************************************//
// Interface: IRowsetChange
// GUID: {0C733A05-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
IRowsetChange = interface(IUnknown)
['{0C733A05-2A1C-11CE-ADE5-00AA0044773D}']
function DeleteRows(hReserved: HCHAPTER; cRows: UINT; rghRows: PUintArray;
rgRowStatus: PUintArray): HResult; stdcall;
function SetData(HROW: HROW; HACCESSOR: HACCESSOR; pData: Pointer): HResult; stdcall;
function InsertRow(hReserved: HCHAPTER; HACCESSOR: HACCESSOR; pData: Pointer;
phRow: PHROW): HResult; stdcall;
end;
(*
{ Safecall Version }
IRowsetChangeSC = interface(IUnknown)
['{0C733A05-2A1C-11CE-ADE5-00AA0044773D}']
procedure DeleteRows(hReserved: HCHAPTER; cRows: UINT; rghRows: PUintArray;
rgRowStatus: PUintArray); safecall;
procedure SetData(HROW: HROW; HACCESSOR: HACCESSOR; pData: Pointer); safecall;
procedure InsertRow(hReserved: HCHAPTER; HACCESSOR: HACCESSOR; pData: Pointer;
phRow: PHROW); safecall;
end;
*)
// *********************************************************************//
// Interface: IRowsetUpdate
// GUID: {0C733A6D-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
DBPENDINGSTATUS = DWORD;
PDBPENDINGSTATUS = ^DBPENDINGSTATUS;
PPDBPENDINGSTATUS = ^PDBPENDINGSTATUS;
DBROWSTATUS = UINT;
PDBROWSTATUS = ^DBROWSTATUS;
PPDBROWSTATUS = ^PDBROWSTATUS;
IRowsetUpdate = interface(IRowsetChange)
['{0C733A6D-2A1C-11CE-ADE5-00AA0044773D}']
function GetOriginalData(HROW: HROW; HACCESSOR: HACCESSOR; pData: Pointer): HResult; stdcall;
function GetPendingRows(hReserved: HCHAPTER; dwRowStatus: DBPENDINGSTATUS; pcPendingRows: PUINT;
prgPendingRows: PPHROW; prgPendingStatus: PPDBPENDINGSTATUS): HResult; stdcall;
function GetRowStatus(hReserved: HCHAPTER; cRows: UINT; rghRows: PUintArray;
rgPendingStatus: PUintArray): HResult; stdcall;
function Undo(hReserved: HCHAPTER; cRows: UINT; rghRows: PUintArray; pcRowsUndone: PUINT;
prgRowsUndone: PPHROW; prgRowStatus: PPDBROWSTATUS): HResult; stdcall;
function Update(hReserved: HCHAPTER; cRows: UINT; rghRows: PUintArray; pcRows: PUINT;
prgRows: PPHROW; prgRowStatus: PPDBROWSTATUS): HResult; stdcall;
end;
(*
{ Safecall Version }
IRowsetUpdateSC = interface(IRowsetChange)
['{0C733A6D-2A1C-11CE-ADE5-00AA0044773D}']
procedure GetOriginalData(HROW: HROW; HACCESSOR: HACCESSOR; pData: Pointer); safecall;
procedure GetPendingRows(hReserved: HCHAPTER; dwRowStatus: DBPENDINGSTATUS; pcPendingRows: PUINT;
prgPendingRows: PPHROW; prgPendingStatus: PPDBPENDINGSTATUS); safecall;
procedure GetRowStatus(hReserved: HCHAPTER; cRows: UINT; rghRows: PUintArray;
rgPendingStatus: PUintArray); safecall;
procedure Undo(hReserved: HCHAPTER; cRows: UINT; rghRows: PUintArray; pcRowsUndone: PUINT;
prgRowsUndone: PPHROW; prgRowStatus: PPDBROWSTATUS); safecall;
procedure Update(hReserved: HCHAPTER; cRows: UINT; rghRows: PUintArray; pcRows: PUINT;
prgRows: PPHROW; prgRowStatus: PPDBROWSTATUS); safecall;
end;
*)
// *********************************************************************//
// Interface: ICommandProperties
// GUID: {0C733A79-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
DBPROPID = UINT;
PDBPROPID = ^DBPROPID;
PDBPropIDArray = ^TDBPropIDArray;
TDBPropIDArray = array[0..MAXBOUND] of DBPROPID;
PDBIDGuid = ^TDBIDGuid;
DBIDGUID = record
case Integer of
0: (guid: TGUID);
1: (pguid: ^TGUID);
end;
TDBIDGuid = DBIDGUID;
PDBIDName = ^TDBIDName;
DBIDNAME = record
case Integer of
0: (pwszName: PWideChar);
1: (ulPropid: UINT);
end;
TDBIDName = DBIDNAME;
DBPROPOPTIONS = UINT;
DBPROPSTATUS = UINT;
PPDBID = ^PDBID;
PDBID = ^DBID;
DBID = packed record
uGuid: DBIDGUID;
eKind: DBKIND;
uName: DBIDNAME;
end;
TDBID = DBID;
PDBProp = ^TDBProp;
DBPROP = packed record
dwPropertyID: DBPROPID;
dwOptions: DBPROPOPTIONS;
dwStatus: DBPROPSTATUS;
colid: DBID;
vValue: tagVariant; // OleVariant;
end;
TDBProp = DBPROP;
PDBPropArray = ^TDBPropArray;
TDBPropArray = array[0..MAXBOUND] of TDBProp;
PPDBPropSet = ^PDBPropSet;
PDBPropSet = ^TDBPropSet;
DBPROPSET = packed record
rgProperties: PDBPropArray;
cProperties: UINT;
guidPropertySet: TGUID;
end;
TDBPropSet = DBPROPSET;
PDBPropIDSet = ^TDBPropIDSet;
DBPROPIDSET = packed record
rgPropertyIDs: PDBPropIDArray;
cPropertyIDs: UINT;
guidPropertySet: TGUID;
end;
TDBPropIDSet = DBPROPIDSET;
PDBPropIDSetArray = ^TDBPropIDSetArray;
TDBPropIDSetArray = array[0..MAXBOUND] of TDBPropIDSet;
PDBPropSetArray = ^TDBPropSetArray;
TDBPropSetArray = array[0..MAXBOUND] of TDBPropSet;
ICommandProperties = interface(IUnknown)
['{0C733A79-2A1C-11CE-ADE5-00AA0044773D}']
function GetProperties(cPropertyIDSets: UINT; rgPropertyIDSets: PDBPropIDSetArray;
var pcPropertySets: UINT; out prgPropertySets: PDBPropSet): HResult; stdcall;
function SetProperties(cPropertySets: UINT; rgPropertySets: PDBPropSetArray): HResult; stdcall;
end;
(*
{ Safecall Version }
ICommandPropertiesSC = interface(IUnknown)
['{0C733A79-2A1C-11CE-ADE5-00AA0044773D}']
procedure GetProperties(cPropertyIDSets: UINT; rgPropertyIDSets: PDBPropIDSetArray;
var pcPropertySets: UINT; out prgPropertySets: PDBPropSet); safecall;
procedure SetProperties(cPropertySets: UINT; rgPropertySets: PDBPropSetArray); safecall;
end;
*)
PDBIDArray = ^TDBIDArray;
TDBIDArray = array[0..MAXBOUND] of TDBID;
PDBColumnInfo = ^TDBColumnInfo;
DBCOLUMNINFO = packed record
pwszName: PWideChar;
pTypeInfo: Pointer;
iOrdinal: UINT;
dwFlags: DBCOLUMNFLAGS;
ulColumnSize: UINT;
wType: DBTYPE;
bPrecision: Byte;
bScale: Byte;
columnid: DBID;
end;
TDBColumnInfo = DBCOLUMNINFO;
PColumnInfo = ^TColumnInfoArray;
TColumnInfoArray = array[ 0..MAXBOUND ] of TDBColumnInfo;
// *********************************************************************//
// Interface: IColumnsInfo
// GUID: {0C733A11-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
IColumnsInfo = interface(IUnknown)
['{0C733A11-2A1C-11CE-ADE5-00AA0044773D}']
function GetColumnInfo(var pcColumns: UINT; out prgInfo: PDBColumnInfo;
out ppStringsBuffer: PWideChar): HResult; stdcall;
function MapColumnIDs(cColumnIDs: UINT; rgColumnIDs: PDBIDArray;
rgColumns: PUintArray): HResult; stdcall;
end;
(*
{ Safecall Version }
IColumnsInfoSC = interface(IUnknown)
['{0C733A11-2A1C-11CE-ADE5-00AA0044773D}']
procedure GetColumnInfo(var pcColumns: UINT; out prgInfo: PDBColumnInfo;
out ppStringsBuffer: PWideChar); safecall;
procedure MapColumnIDs(cColumnIDs: UINT; rgColumnIDs: PDBIDArray;
rgColumns: PUINTArray); safecall;
end;
*)
PDBBindExt = ^TDBBindExt;
DBBINDEXT = packed record
pExtension: PByte;
ulExtension: UINT;
end;
TDBBindExt = DBBINDEXT;
PDBObject = ^TDBObject;
DBOBJECT = packed record
dwFlags: UINT;
iid: TGUID;
end;
TDBObject = DBOBJECT;
PDBBinding = ^TDBBinding;
DBBINDING = packed record
iOrdinal: UINT;
obValue: UINT;
obLength: UINT;
obStatus: UINT;
pTypeInfo: Pointer; //ITypeInfo; (reserved, should be nil)
pObject: PDBObject;
pBindExt: PDBBindExt;
dwPart: DBPART;
dwMemOwner: DBMEMOWNER;
eParamIO: DBPARAMIO;
cbMaxLen: UINT;
dwFlags: UINT;
wType: DBTYPE;
bPrecision: Byte;
bScale: Byte;
end;
TDBBinding = DBBINDING;
PDBBindingArray = ^TDBBindingArray;
TDBBindingArray = array[0..MAXBOUND] of TDBBinding;
const
DBTYPE_EMPTY = $00000000;
DBTYPE_NULL = $00000001;
DBTYPE_I2 = $00000002;
DBTYPE_I4 = $00000003;
DBTYPE_R4 = $00000004;
DBTYPE_R8 = $00000005;
DBTYPE_CY = $00000006;
DBTYPE_DATE = $00000007;
DBTYPE_BSTR = $00000008;
DBTYPE_IDISPATCH = $00000009;
DBTYPE_ERROR = $0000000A;
DBTYPE_BOOL = $0000000B;
DBTYPE_VARIANT = $0000000C;
DBTYPE_IUNKNOWN = $0000000D;
DBTYPE_DECIMAL = $0000000E;
DBTYPE_UI1 = $00000011;
DBTYPE_ARRAY = $00002000;
DBTYPE_BYREF = $00004000;
DBTYPE_I1 = $00000010;
DBTYPE_UI2 = $00000012;
DBTYPE_UI4 = $00000013;
DBTYPE_I8 = $00000014;
DBTYPE_UI8 = $00000015;
DBTYPE_FILETIME = $00000040;
DBTYPE_GUID = $00000048;
DBTYPE_VECTOR = $00001000;
DBTYPE_RESERVED = $00008000;
DBTYPE_BYTES = $00000080;
DBTYPE_STR = $00000081;
DBTYPE_WSTR = $00000082;
DBTYPE_NUMERIC = $00000083;
DBTYPE_UDT = $00000084;
DBTYPE_DBDATE = $00000085;
DBTYPE_DBTIME = $00000086;
DBTYPE_DBTIMESTAMP = $00000087;
DBTYPE_DBFILETIME = $00000089;
DBTYPE_PROPVARIANT = $0000008A;
DBTYPE_VARNUMERIC = $0000008B;
type
// *********************************************************************//
// Interface: IAccessor
// GUID: {0C733A8C-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
IAccessor = interface(IUnknown)
['{0C733A8C-2A1C-11CE-ADE5-00AA0044773D}']
function AddRefAccessor(HACCESSOR: HACCESSOR; pcRefCount: PUINT): HResult; stdcall;
function CreateAccessor(dwAccessorFlags: UINT; cBindings: UINT; rgBindings: PDBBindingArray;
cbRowSize: UINT; var phAccessor: HACCESSOR; rgStatus: PUintArray): HResult; stdcall;
function GetBindings(HACCESSOR: HACCESSOR; pdwAccessorFlags: PUINT; var pcBindings: UINT;
out prgBindings: PDBBinding): HResult; stdcall;
function ReleaseAccessor(HACCESSOR: HACCESSOR; pcRefCount: PUINT): HResult; stdcall;
end;
(*
{ Safecall Version }
IAccessorSC = interface(IUnknown)
['{0C733A8C-2A1C-11CE-ADE5-00AA0044773D}']
procedure AddRefAccessor(HACCESSOR: HACCESSOR; pcRefCount: PUINT); safecall;
procedure CreateAccessor(dwAccessorFlags: UINT; cBindings: UINT; rgBindings: PDBBindingArray;
cbRowSize: UINT; var phAccessor: HACCESSOR; rgStatus: PUintArray); safecall;
procedure GetBindings(HACCESSOR: HACCESSOR; pdwAccessorFlags: PUINT; var pcBindings: UINT;
out prgBindings: PDBBinding); safecall;
procedure ReleaseAccessor(HACCESSOR: HACCESSOR; pcRefCount: PUINT); safecall;
end;
*)
// Begin Added By ECM !!! =======================================================
PBoid = ^TBoid;
BOID = packed record
rgb_: array[0..15] of Byte;
end;
TBoid = BOID;
PXactTransInfo = ^TXactTransInfo;
XACTTRANSINFO = packed record
uow: BOID;
isoLevel: Integer;
isoFlags: UINT;
grfTCSupported: UINT;
grfRMSupported: UINT;
grfTCSupportedRetaining: UINT;
grfRMSupportedRetaining: UINT;
end;
TXactTransInfo = XACTTRANSINFO;
PXactOpt = ^TXactOpt;
XACTOPT = packed record
ulTimeout: UINT;
szDescription: array[0..39] of Shortint;
end;
TXActOpt = XACTOPT;
// *********************************************************************//
// Interface: ITransactionOptions
// GUID: {3A6AD9E0-23B9-11CF-AD60-00AA00A74CCD}
// *********************************************************************//
ITransactionOptions = interface(IUnknown)
['{3A6AD9E0-23B9-11CF-AD60-00AA00A74CCD}']
function SetOptions(var pOptions: XACTOPT): HResult; stdcall;
function GetOptions(var pOptions: XACTOPT): HResult; stdcall;
end;
// *********************************************************************//
// Interface: ITransaction
// GUID: {0FB15084-AF41-11CE-BD2B-204C4F4F5020}
// *********************************************************************//
ITransaction = interface(IUnknown)
['{0FB15084-AF41-11CE-BD2B-204C4F4F5020}']
function Commit(fRetaining: BOOL; grfTC: UINT; grfRM: UINT): HResult; stdcall;
function Abort(pboidReason: PBOID; fRetaining: BOOL; fAsync: BOOL): HResult; stdcall;
function GetTransactionInfo(out pinfo: XACTTRANSINFO): HResult; stdcall;
end;
// *********************************************************************//
// Interface: ITransactionLocal
// GUID: {0C733A5F-2A1C-11CE-ADE5-00AA0044773D}
// *********************************************************************//
ITransactionLocal = interface(ITransaction)
['{0C733A5F-2A1C-11CE-ADE5-00AA0044773D}']
function GetOptionsObject(out ppOptions: ITransactionOptions): HResult; stdcall;
function StartTransaction(isoLevel: Integer; isoFlags: UINT;
const pOtherOptions: ITransactionOptions; pulTransactionLevel: PUINT): HResult; stdcall;
end;
const
XACTTC_SYNC_PHASEONE = $00000001;
XACTTC_SYNC_PHASETWO = $00000002;
XACTTC_SYNC = $00000002;
XACTTC_ASYNC_PHASEONE = $00000004;
XACTTC_ASYNC = $00000004;
// End Added By ECM !!! =========================================================
// Begin Added By azsd !!! ======================================================
(*
type
PDbNumeric = ^tagDB_NUMERIC;
tagDB_NUMERIC = packed record
precision: Byte;
scale: Byte;
sign: Byte;
val: array[0..15] of Byte;
end;
*)
// End Added By azsd !!! ========================================================
{============= This part of code is designed by me ================}
type
PDBBINDSTATUSARRAY = ^TDBBINDSTATUSARRAY;
TDBBINDSTATUSARRAY = array[ 0..MAXBOUND ] of DBBINDSTATUS;
//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
// TDataSource - a connection to data base
//,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
type
PDataSource = ^TDataSource;
TDataSource = object( TObj )
{* This object provides a connection with data base. You create it using
NewDataSource function and passing a connection string to it. The object
is initializing immediately after creating. You can get know if the
connection established successfully reading Intitialized property. }
private
fSessions: PList;
fIDBInitialize: IDBInitialize;
FInitialized: Boolean;
protected
function Initialize( const Params: String ): Boolean;
public
constructor Create;
{* Do not call this constructor. Use function NewDataSource instead. }
destructor Destroy; virtual;
{* Do not call this destructor. Use Free method instead. When TDataSource
object is destroyed, all its sessions (and consequensly, all queries)
are freed automatically. }
property Initialized: Boolean read FInitialized;
{* Returns True, if the connection with database is established. Mainly,
it is not necessary to analizy this flag. If any error occure during
initialization, CheckOle halts further execution. (But You can use
another error handler, which does not stop the application). }
end;
function NewDataSource( const Params: String ): PDataSource;
{* Creates data source objects and initializes it. Pass a connection
string as a parameter, which determines used provider, database
location, user identification and other parameters. See demo provided
or/and read spicifications from database software vendors, which
parameters to pass. }
//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
// TSession - transaction session in a connection
//,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
type
PSession = ^TSession;
TSession = object( TObj )
{* This object is intended to provide session transactions. It always
must be created as a "child" of TDataSource object, and it owns by
query objects (of type TQuery). For each TDataSource object, it is
possible to create several TSession objects, and for each session,
several TQuery objects can exist. }
private
fQueryList: PList;
fDataSource: PDataSource;
fCreateCommand: IDBCreateCommand;
// Added By ECM !!! ==================
fTransaction: ITransaction;
fTransactionLocal: ITransactionLocal;
// ===================================
protected
public
constructor Create;
{* }
destructor Destroy; virtual;
{* Do not call directly, call Free method instead. When TSession object is
destroyed, all it child queries are freed automatically. }
// Added By ECM !!! ====================================
function StartTransaction(isoLevel: Integer): HRESULT;
function Commit(Retaining: BOOL): HRESULT;
function Rollback(Retaining: BOOL): HRESULT;
function Active: Boolean;
// =====================================================
property DataSource: PDataSource read fDataSource;
{* Returns a pointer to owner TDataSource object. }
end;
function NewSession( ADataSource: PDataSource ): PSession;
{* Creates session object owned by ADataSource (this last must exist). }
//''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
// TQuery - a command and resulting rowset(s)
//,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
type
TRowsetMode = ( rmUpdateImmediate, rmUpdateDelayed, rmReadOnly );
TFieldType = ( ftInteger, ftReal, ftString, ftDate, ftLargeInt, ftOther );
PQuery = ^TQuery;
TQuery = object( TObj )
{* This is the most important object to work with database. It is always
must be created as a "child" of TSession object, and allows to perform
commands, open rowsets, scroll it, update and so on. }
private
fSession: PSession;
fText: String;
fCommand: ICommandText;
fCommandProps: ICommandProperties;
fRowsAffected: Integer;
fRowSet: IRowset;
fRowSetChg: IRowsetChange;
fRowSetUpd: IRowsetUpdate;
fColCount: UINT;
fColInfo: PColumnInfo;
fColNames: PWideChar;
fBindings: PDBBindingArray;
fBindStatus: PDBBINDSTATUSARRAY;
fRowSize: Integer;
fAccessor: HACCESSOR;
fRowHandle: THandle;
fRowBuffers: PList;
fEOF: Boolean;
fCurIndex: Integer;
fChanged: Boolean;
fMode: TRowsetMode;
procedure SetText(const Value: String);
function GetRowCount: Integer;
function GetColNames(Idx: Integer): String;
procedure SetCurIndex(const Value: Integer);
function GetRowsKnown: Integer;
function GetStrField(Idx: Integer): String;
procedure SetStrField(Idx: Integer; const Value: String);
function GetIntField(Idx: Integer): Integer;
procedure SetIntField(Idx: Integer; const Value: Integer);
function GetFltField(Idx: Integer): Double;
procedure SetFltField(Idx: Integer; const Value: Double);
function GetDField(Idx: Integer): TDateTime;
procedure SetDField(Idx: Integer; const Value: TDateTime);
function FieldPtr( Idx: Integer ): Pointer;
function Changed( Idx: Integer ): Pointer;
function GetColByName(Name: String): Integer;
function GetSFieldByName(const Name: String): String;
procedure SetSFieldByName(const Name: String; const Value: String);
function GetIFieldByName(const Name: String): Integer;
procedure SetIFieldByName(const Name: String; Value: Integer);
function GetRFieldByName(const Name: String): Double;
procedure SetRFieldByName(const Name: String; const Value: Double);
function GetDFlfByName(const Name: String): TDateTime;
procedure SetDFldByName(const Name: String; const Value: TDateTime);
function GetColType(Idx: Integer): TFieldType;
function GetColTypeByName(const Name: String): TFieldType;
function GetIsNull(Idx: Integer): Boolean;
procedure SetIsNull(Idx: Integer; const Value: Boolean);
function GetIsNullByName(const Name: String): Boolean;
procedure SetIsNullByName(const Name: String; const Value: Boolean);
function GetFByNameAsStr(const Name: String): String;
function GetFieldAsStr(Idx: Integer): String;
procedure SetFByNameFromStr(const Name, Value: String);
procedure SetFieldFromStr(Idx: Integer; const Value: String);
function GetI64Field(Idx: Integer): Int64;
function GetI64FldByName(const Name: String): Int64;
procedure SetI64Field(Idx: Integer; const Value: Int64);
procedure SetI64FldByName(const Name: String; const Value: Int64);
function GetFixupNumeric(Idx: Integer): Int64; //add by azsd
function GetRawType(Idx: Integer): DWORD;
function GetRawTypeByName(const Name: String): DWORD;
function GetFieldAsHex(Idx: Integer): Pointer;
function GetFieldByNameAsHex(const Name: String): Pointer;
protected
fDelList: PList;
procedure ClearRowset;
procedure ReleaseHandle;
procedure FetchData;
procedure NextWOFetch( Skip: Integer );
public
destructor Destroy; virtual;
{* Do not call the destructor directly, call method Free instead. When
"parent" TSession object is destroyed, all queries owned by the session
are destroyed automatically. }
property Session: PSession read fSession;
{* Returns owner session object. }
property Text: String read FText write SetText;
{* Query command text. When You change it, currently opened rowset (if any)
is closed, so there are no needs to call Close method before preparing
for new command. Current version does not support passing "parameters",
so include all values into Text as a part of string. }
procedure Close;
{* Closes opened rowset if any. It is not necessary to call close after
Execute. Also, rowset is closed automatically when another value is
assigned to Text property. }
procedure Execute;
{* Call this method to execute command (stored in Text), which does not
open a rowset (thus is, "insert", "delete", and "update" SQL statements
do so). }
procedure Open;
{* Call this method for executing command, which opens a rowset (table of
data). This can be "select" SQL statement, or call to stored procedure,
which returns result in a table. }
property RowCount: Integer read GetRowCount;
{* For commands, such as "insert", "delete" or "update" SQL statements,
this property returns number of rows affected by a command. For "select"
statement performed using Open method, this property should return
a number of rows selected. By for (the most) providers, this value is
unknown for first time (-1 is returned). To get know how much rows are
in returned rowset, method Last should be called first. But for large
data returned this is not efficient way, because actually a loop
"while not EOF do Next" is performed to do so.
|
Tip: to get count of rows, You can call another query, which executes
"select count(*) where..." SQL statement with the same conditions. }
property RowsKnown: Integer read GetRowsKnown;
{* Returns actual number or selected rows, if this is "known" value, or number
of rows already fetched. }
property ColCount: UINT read fColCount;
{* Returns number of columns in opened rowset. }
property ColNames[ Idx: Integer ]: String read GetColNames;
{* Return names of columns. }
property ColByName[ Name: String ]: Integer read GetColByName;
{* Returns column index by name. Comparing of names is ANSI and case insensitive. }
property ColType[ Idx: Integer ]: TFieldType read GetColType;
{* }
property ColTypeByName[ const Name: String ]: TFieldType read GetColTypeByName;
{* }
function FirstColumn: Integer;
{* by Alexander Shakhaylo. To return an index of the first column,
containing actual data. (for .mdb, the first can contain special
control information, but not for .dbf) }
property RawType[ Idx: Integer ]: DWORD read GetRawType;
{*}
property RawTypeByName[ const Name: String ]: DWORD read GetRawTypeByName;
{*}
property EOF: Boolean read fEOF;
{* Returns True, if end of data is achived (usually after calling Next
or Prev method, or immediately after Open, if there are no rows in opened
rowset). }
procedure First;
{* Resets a position to the start of rowset. This method is called
automatically when Open is called successfully. }
procedure Next;
{* Moves position to the next row if possible. If EOF achived, a position
is not changed. }
procedure Prev;
{* Moves position to a previous row (but if CurIndex > 0). }
procedure Last;
{* Moves position to the last row. This method can be unefficient for
large datasets, because implemented as a loop where method Next is
called repeteadly, while EOF is not achieved. }
property Mode: TRowsetMode read fMode write fMode;
{* }
procedure Post;
{* Applyes changes made in a record, writing changed row to database table. }
procedure Delete;
{* Deletes a row. In rmUpdateDelayed Mode, rows are only added to a list
for later deleting it when Update called. }
procedure Update;
{* Allows to apply all updates far later, not when Post method is called.
To use TQuery in this manner, its Mode should be set to rmUpdateDelayed. }
property CurIndex: Integer read fCurIndex write SetCurIndex;
{* Index of current row. It is possible to change it directly even if
specified row is not yet fetched. But check at least what new value is
stored in CurIndex after such assignment. }
property SField[ Idx: Integer ]: String read GetStrField write SetStrField;
{* Access to a string field by index. You should be sure, that a field
has string type. }
property SFieldByName[ const Name: String ]: String read GetSFieldByName write SetSFieldByName;
{* }
property IField[ Idx: Integer ]: Integer read GetIntField write SetIntField;
{* Access to a integer field by index. You should be sure, that a field
has integer type or compatible. }
property IFieldByName[ const Name: String ]: Integer read GetIFieldByName write SetIFieldByName;
{* }
property LField[ Idx: Integer ]: Int64 read GetI64Field write SetI64Field;
{* }
property LFieldByName[ const Name: String ]: Int64 read GetI64FldByName write SetI64FldByName;
{* }
property RField[ Idx: Integer ]: Double read GetFltField write SetFltField;
{* Access to a real (Double) field by index. You should be sure, that a field
has numeric (with floating decimal point) type. }
property RFieldByName[ const Name: String ]: Double read GetRFieldByName write SetRFieldByName;
{* }
property DField[ Idx: Integer ]: TDateTime read GetDField write SetDField;
{* }
property DFieldByName[ const Name: String ]: TDateTime read GetDFlfByName write SetDFldByName;
{* }
property IsNull[ Idx: Integer ]: Boolean read GetIsNull write SetIsNull;
{* }
property IsNullByName[ const Name: String ]: Boolean read GetIsNullByName write SetIsNullByName;
{* }
property FieldAsStr[ Idx: Integer ]: String read GetFieldAsStr write SetFieldFromStr;
{* }
property FieldByNameAsStr[ const Name: String ]: String read GetFByNameAsStr write SetFByNameFromStr;
{* }
property FieldAsHex[ Idx: Integer ]: Pointer read GetFieldAsHex;
{* Access to field data directly. If you change field data inplace, call
MarkRecordChanged by yourself. If field IsNull, data found at the address
provided have no sense. }
property FieldByNameAsHex[ const Name: String ]: Pointer read GetFieldByNameAsHex;
{* See FieldByNameAsHex. }
procedure MarkFieldChanged( Idx: Integer );
{* See also MarkRecordChangedByName. }
procedure MarkFieldChangedByName( const Name: String );
{* When record field changed directly (using FieldAsHex property, for ex.),
use this method to signal to record set container, that record is changed,
and to ensure that field no more marked as null. }
end;
function NewQuery( Session: PSession ): PQuery;
{* Creates query object. }
// Error handling routines:
function CheckOLE( Rslt: HResult ): Boolean;
function CheckOLEex( Rslt: HResult; const OKResults: array of HResult ): Boolean;
procedure DummyOleError( Result: HResult );
var OleError: procedure( Result: HResult ) = DummyOleError;
implementation
type
PDBNumeric = ^TDBNumeric;
TDBNUMERIC = packed record
precision: Byte;
scale: Byte;
sign: Byte;
val: array[0..15] of Byte;
end;
PDBVarNumeric = ^TDBVarNumeric;
TDBVARNUMERIC = packed record
precision: Byte;
scale: ShortInt;
sign: Byte;
val: ^Byte;
end;
PDBDate = ^TDBDate;
TDBDATE = packed record
year: Smallint;
month: Word;
day: Word;
end;
PDBTime = ^TDBTIME;
TDBTIME = packed record
hour: Word;
minute: Word;
second: Word;
end;
PDBTimeStamp = ^TDBTimeStamp;
TDBTIMESTAMP = packed record
year: Smallint;
month: Word;
day: Word;
hour: Word;
minute: Word;
second: Word;
fraction: UINT;
end;
var fIMalloc: IMalloc = nil;
(* procedure DummyOleError( Result: HResult );
begin
MsgOK( 'OLE DB error ' + Int2Hex( Result, 8 ) );
Halt;
end; *)
procedure DummyOleError( Result: HResult );
begin
{$IFNDEF FPC}
raise Exception.Create( e_Custom, 'OLE DB error ' + Int2Hex( Result, 8 ) );
{$ENDIF}
end;
function CheckOLE( Rslt: HResult ): Boolean;
begin
Result := Rslt = 0;
if not Result then
OleError( Rslt );
end;
function CheckOLEex( Rslt: HResult; const OKResults: array of HResult ): Boolean;
var I: Integer;
begin
Result := TRUE;
for I := Low( OKResults ) to High( OKResults ) do
if Rslt = OKResults[ I ] then Exit;
Result := FALSE;
OleError( Rslt );
end;
{ TDataSource }
function NewDataSource( const Params: String ): PDataSource;
begin
new( Result, Create );
Result.Initialize( Params );
end;
constructor TDataSource.Create;
var clsid: TCLSID;
begin
inherited;
fSessions := NewList;
//if CheckOLEex( CoInitialize( nil ), [ S_OK, S_FALSE ] ) then
OleInit;
if CheckOLE( CoGetMalloc( MEMCTX_TASK, fIMalloc ) ) then
if CheckOLE( CLSIDFromProgID( 'SQLOLEDB', clsid ) ) then
CheckOLE( CoCreateInstance( clsid, nil, CLSCTX_INPROC_SERVER,
IID_IDBInitialize, fIDBInitialize ) );
end;
destructor TDataSource.Destroy;
var I: Integer;
begin
for I := fSessions.Count - 1 downto 0 do
PObj( fSessions.Items[ I ] ).Free;
fSessions.Free;
if Initialized then
CheckOLE( fIDBInitialize.UnInitialize );
OleUnInit;
inherited;
end;
function TDataSource.Initialize( const Params: String ): Boolean;
var DI: IDataInitialize;
Unk: IUnknown;
begin
Result := FALSE;
if Initialized then
begin
Result := TRUE;
Exit;
end;
if CheckOLE( CoCreateInstance( CLSID_MSDAINITIALIZE, nil,
CLSCTX_ALL, IID_IDataInitialize, DI ) ) then
if CheckOLE( DI.GetDataSource( nil, CLSCTX_ALL, StringToOleStr( Params ),
IID_IDBInitialize, Unk ) ) then
if CheckOLE( Unk.QueryInterface( IID_IDBInitialize, fIDBInitialize ) ) then
if CheckOLE( fIDBInitialize.Initialize ) then
begin
Result := TRUE;
FInitialized := Result;
end;
end;
{ TSession }
function NewSession( ADataSource: PDataSource ): PSession;
var CreateSession: IDBCreateSession;
Unk: IUnknown;
begin
new( Result, Create );
Result.fDataSource := ADataSource;
ADataSource.fSessions.Add( Result );
// Modified by ECM !!! ===============================================================================
if CheckOLE( ADataSource.fIDBInitialize.QueryInterface( IID_IDBCreateSession, CreateSession ) ) then begin
CheckOLE( CreateSession.CreateSession( nil, IID_IDBCreateCommand,
IUnknown( Result.fCreateCommand ) ) );
Unk := Result.fCreateCommand;
if Assigned(Unk) then begin
CheckOLE(Unk.QueryInterface(IID_ITransaction,Result.fTransaction));
CheckOLE(Unk.QueryInterface(IID_ITransactionLocal,Result.fTransactionLocal));
end;
end;
// =================================================================================================
end;
// Added By ECM !!! ==============================================
function TSession.Active: Boolean;
var
xinfo: TXactTransInfo;
Ret: HRESULT;
begin
if not Assigned(fTransaction) then Result := FALSE
else begin
FillChar(xinfo,SizeOf(xinfo),0);
Ret := fTransaction.GetTransactionInfo(xinfo);
Result := Ret = S_OK;
CheckOLE(Ret);
end;
end;
function TSession.Commit(Retaining: BOOL): HRESULT;
begin
Assert(Assigned(fTransaction));
Result := fTransaction.Commit(Retaining,XACTTC_SYNC,0);
CheckOLE(Result);
end;
// ===============================================================
constructor TSession.Create;
begin
inherited;
fQueryList := NewList;
end;
destructor TSession.Destroy;
var I: Integer;
begin
for I := fQueryList.Count - 1 downto 0 do
PObj( fQueryList.Items[ I ] ).Free;
fQueryList.Free;
I := fDataSource.fSessions.IndexOf( @Self );
fDataSource.fSessions.Delete( I );
// Add By ECM !!! ================
// if Active then Rollback(FALSE);
//================================
fCreateCommand := nil;
inherited;
end;
// Added By ECM !!! ===============================================
function TSession.Rollback(Retaining: BOOL): HRESULT;
begin
Assert(Assigned(fTransaction));
Result := fTransaction.Abort(nil,Retaining,FALSE);
CheckOLE(Result);
end;
function TSession.StartTransaction(isoLevel: Integer): HRESULT;
begin
Assert(Assigned(fTransactionLocal));
Result := fTransactionLocal.StartTransaction(isoLevel,0,nil,nil);
CheckOLE(Result);
end;
// ================================================================
{ TQuery }
function NewQuery( Session: PSession ): PQuery;
begin
new( Result, Create );
Result.fSession := Session;
Session.fQueryList.Add( Result );
CheckOLE( Session.fCreateCommand.CreateCommand( nil, IID_ICommandText,
IUnknown( Result.fCommand ) ) );
end;
function TQuery.Changed( Idx: Integer ): Pointer;
begin
fChanged := TRUE;
Result := Pointer( DWORD( fRowBuffers.Items[ fCurIndex ] ) +
fBindings[ Idx ].obStatus );
PDWORD( Result )^ := 0; // set to NOT NULL
end;
procedure TQuery.ClearRowset;
var I: Integer;
AccessorIntf: IAccessor;
begin
ReleaseHandle;
if fAccessor <> 0 then
begin
if CheckOLE( fRowSet.QueryInterface( IID_IAccessor, AccessorIntf ) ) then
AccessorIntf.ReleaseAccessor( fAccessor, nil );
fAccessor := 0;
end;
if fRowBuffers <> nil then
begin
for I := fRowBuffers.Count - 1 downto 0 do
FreeMem( fRowBuffers.Items[ I ] );
fRowBuffers.Free;
fRowBuffers := nil;
end;
fRowSize := 0;
if fBindings <> nil then
begin
//for I := 0 to fColCount - 1 do
// fBindings[ I ].pTypeInfo := nil;
FreeMem( fBindings );
fBindings := nil;
FreeMem( fBindStatus );
fBindStatus := nil;
end;
if fColInfo <> nil then
fIMalloc.Free( fColInfo );
fColInfo := nil;
if fColNames <> nil then
fIMalloc.Free( fColNames );
fColNames := nil;
fColCount := 0;
fRowSetUpd := nil;
fRowSet := nil;
fRowSetChg := nil;
fRowsAffected := 0;
fEOF := TRUE;
end;
procedure TQuery.Close;
begin
Update;
ClearRowset;
end;
procedure TQuery.Delete;
var Params, Results: array of DWORD;
begin
//if fRowHandle = 0 then Exit;
CASE fMode OF
rmUpdateImmediate:
begin
SetLength( Results, 1 );
SetLength( Params, 1 );
Params[ 0 ] := fRowHandle;
CheckOLE( fRowSetUpd.DeleteRows( 0, 1, @ Params[ 0 ], @ Results[ 0 ] ) );
end;
rmUpdateDelayed:
begin
if fDelList = nil then
fDelList := NewList;
fDelList.Add( Pointer( fRowHandle ) );
end;
END;
end;
destructor TQuery.Destroy;
var I: Integer;
begin
Close; //ClearRowset;
I := fSession.fQueryList.IndexOf( @Self );
if I >= 0 then
fSession.fQueryList.Delete( I );
fText := '';
fCommandProps := nil;
fCommand := nil;
fDelList.Free;
inherited;
end;
procedure TQuery.Execute;
begin
ClearRowset;
// first set txt to fCommand just before execute
if CheckOLE( fCommand.SetCommandText( @DBGUID_DBSQL, StringToOleStr( fText ) ) ) then
CheckOLE( fCommand.Execute( nil, IID_NULL, nil, @fRowsAffected, nil ) );
end;
procedure TQuery.FetchData;
var Buffer: Pointer;
begin
if fRowHandle = 0 then
Exit;
if fRowBuffers.Items[ fCurIndex ] = nil then
begin
GetMem( Buffer, fRowSize );
FillChar( Buffer^, fRowSize, 0 ); //fixup the varnumberic random bytes by azsd
fRowBuffers.Items[ fCurIndex ] := Buffer;
CheckOLE( fRowSet.GetData( fRowHandle, fAccessor, fRowBuffers.Items[ fCurIndex ] ) );
end;
end;
function TQuery.FieldPtr(Idx: Integer): Pointer;
begin
if (fRowSet = nil) or (fCurIndex < 0) or (DWORD(Idx) >= ColCount) then
Result := nil
else
Result := Pointer( DWORD( fRowBuffers.Items[ fCurIndex ] ) +
fBindings[ Idx ].obValue );
end;
procedure TQuery.First;
begin
if fCurIndex = 0 then Exit;
ReleaseHandle;
fCurIndex := -1;
if CheckOLE( fRowSet.RestartPosition( 0 ) ) then
begin
fEOF := FALSE;
Next;
end;
end;
function TQuery.FirstColumn: Integer;
var i: integer;
begin
Result := -1;
for i := 0 to fColCount - 1 do begin
if fBindings[i].iOrdinal > 0 then begin
Result := i;
exit;
end;
end;
end;
function TQuery.GetColByName(Name: String): Integer;
var I: Integer;
begin
Result := -1;
for I := 0 to fColCount - 1 do
begin
if AnsiCompareStrNoCase( Name, ColNames[ I ] ) = 0 then
begin
Result := I;
break;
end;
end;
end;
function TQuery.GetColNames(Idx: Integer): String;
begin
Result := fColInfo[ Idx ].pwszName;
end;
function TQuery.GetColType(Idx: Integer): TFieldType;
begin
Result := ftOther;
if fBindings = nil then Exit;
case fBindings[ Idx ].wType of
DBTYPE_I1, DBTYPE_I2, DBTYPE_I4, DBTYPE_BOOL,
DBTYPE_UI1, DBTYPE_UI2, DBTYPE_UI4 : Result := ftInteger;
DBTYPE_I8, DBTYPE_UI8 : Result := ftLargeInt;
DBTYPE_BSTR, DBTYPE_WSTR, DBTYPE_STR: Result := ftString;
DBTYPE_R4, DBTYPE_R8, DBTYPE_CY,
DBTYPE_NUMERIC, DBTYPE_VARNUMERIC,
DBTYPE_DECIMAL : Result := ftReal;// no need new cate here,moved to GetFieldAsStr
DBTYPE_DATE, DBTYPE_FILETIME, //DBTYPE_DBFILETIME,
DBTYPE_DBDATE, DBTYPE_DBTIME,
DBTYPE_DBTIMESTAMP : Result := ftDate;
else Result := ftOther;
end;
end;
function TQuery.GetColTypeByName(const Name: String): TFieldType;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >= 0, 'Incorrect column name (' + Name + ').' );
Result := ColType[ Idx ];
end;
function TQuery.GetDField(Idx: Integer): TDateTime;
var P: Pointer;
ST: TSystemTime;
pD: PDBDate;
pT: PDBTime;
TS: PDBTimeStamp;
pFT: PFileTime;
begin
P := FieldPtr( Idx );
if P = nil then
Result := 0.0
else
begin
FillChar( ST, Sizeof(ST), 0 );
case fBindings[ Idx ].wType of
DBTYPE_DATE: Result := PDouble( P )^ + VCLDate0;
DBTYPE_DBDATE:
begin
pD := P;
ST.wYear := pD.year;
ST.wMonth := pD.month;
ST.wDay := pD.day;
SystemTime2DateTime( ST, Result );
end;
DBTYPE_DBTIME:
begin
pT := P;
ST.wYear := 1899;
ST.wMonth := 12;
ST.wDay := 31;
ST.wHour := pT.hour;
ST.wMinute := pT.minute;
ST.wSecond := pT.second;
SystemTime2DateTime( ST, Result );
Result := Result - VCLDate0;
end;
DBTYPE_DBTIMESTAMP:
begin
TS := P;
ST.wYear := TS.year;
ST.wMonth := TS.month;
ST.wDay := TS.day;
ST.wHour := TS.hour;
ST.wMinute := TS.minute;
ST.wSecond := TS.second;
ST.wMilliseconds := TS.fraction div 1000000;
SystemTime2DateTime( ST, Result );
end;
DBTYPE_FILETIME:
begin
pFT := P;
FileTimeToSystemTime( pFT^, ST );
SystemTime2DateTime( ST, Result );
end;
else Result := 0.0;
end;
end;
end;
function TQuery.GetDFlfByName(const Name: String): TDateTime;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
Result := DField[ Idx ];
end;
function TQuery.GetFByNameAsStr(const Name: String): String;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
Result := FieldAsStr[ Idx ];
end;
function TQuery.GetFieldAsHex(Idx: Integer): Pointer;
begin
{if IsNull[ Idx ] then
Result := nil
else}
Result := FieldPtr( Idx );
end;
function TQuery.GetFieldAsStr(Idx: Integer): String;
begin
if IsNull[ Idx ] then
Result := '(null)'
else
case ColType[ Idx ] of
ftReal:
//added optimize by azsd
begin
case fBindings[ Idx ].wType of
DBTYPE_NUMERIC,DBTYPE_VARNUMERIC:
if ShortInt(PDBNumeric(FieldPtr(Idx)).scale)<>0 then
Result := Double2Str( RField[ Idx ] )
else
Result := Int64_2Str( LField[ Idx ] );
else
Result := Double2Str( RField[ Idx ] );
end;
end;
ftString: Result := SField[ Idx ];
ftDate: Result := DateTime2StrShort( DField[ Idx ] );
ftLargeInt: Result := Int64_2Str( LField[ Idx ] );//add by azsd
//ftInteger:
else Result := Int2Str( IField[ Idx ] );
//else Result := '(?)';
end;
end;
function TQuery.GetFieldByNameAsHex(const Name: String): Pointer;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
Result := FieldAsHex[ Idx ];
end;
function TQuery.GetFltField(Idx: Integer): Double;
var P: Pointer;
begin
P := FieldPtr( Idx );
if P = nil then
Result := 0.0
else
case fBindings[ Idx ].wType of
DBTYPE_R4: Result := PSingle( P )^;
DBTYPE_R8: Result := PDouble( P )^;
DBTYPE_CY: Result := PInteger( P )^ * 0.0001;
//TODO: DBTYPE_DECIMAL
DBTYPE_NUMERIC, DBTYPE_VARNUMERIC:
begin
Result := Int64_2Double(GetFixupNumeric(Idx));
if PDBNumeric(P).sign=0 then Result := 0 - Result;
if PDBNumeric(P).scale<>0 then Result := Result * IntPower( 10, 0 - Shortint(PDBNumeric(P).scale));
end;
else Result := 0.0;
end;
end;
function TQuery.GetFixupNumeric(Idx: Integer): Int64;
var
P: Pointer;
begin
P := FieldPtr( Idx );
Result := MakeInt64( 0, 0 );
if P=nil then Exit;
case fBindings[ Idx ].wType of
DBTYPE_NUMERIC:
Result := PInt64( DWORD(P)+3 )^; //131 filled with 00
DBTYPE_VARNUMERIC:
begin
Result := PInt64( DWORD(P)+3 )^; //139 containing some shit bytes
//vn := P;
//if vn.precision> then
//fix-up done in Fetchdata
end;
else
Result := MakeInt64( PDWORD( DWORD(P)+3 )^, 0 );
end;
end;
function TQuery.GetI64Field(Idx: Integer): Int64;
const His: array[ 0..1 ] of Integer = ( 0, -1 and not 255 );
var P: Pointer;
B: Byte;
begin
P := FieldPtr( Idx );
Result := MakeInt64( 0, 0 );
if P <> nil then
case fBindings[ Idx ].wType of
DBTYPE_I8, DBTYPE_UI8, DBTYPE_CY:
Result := PInt64( P )^;
DBTYPE_I1:
begin
B := PByte( P )^;
Result := Int2Int64( Integer( B ) or His[ B shr 7 ] );
end;
DBTYPE_UI1: Result := MakeInt64( PByte( P )^, 0 );
DBTYPE_I2: Result := Int2Int64( PShortInt( P )^ );
DBTYPE_UI2: Result := MakeInt64( PWord( P )^, 0 );
DBTYPE_I4: Result := Int2Int64( PInteger( P )^ );
DBTYPE_NUMERIC, DBTYPE_VARNUMERIC:
begin
if ShortInt(PDBNumeric(P).scale)<>0 then
Result := Double2Int64( RField[Idx] )
else
Result := GetFixupNumeric(Idx);
end;
//DBTYPE_UI4:
else Result := MakeInt64( PInteger( P )^, 0 );
end;
end;
function TQuery.GetI64FldByName(const Name: String): Int64;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
Result := LField[ Idx ];
end;
function TQuery.GetIFieldByName(const Name: String): Integer;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
Result := IField[ Idx ];
end;
function TQuery.GetIntField(Idx: Integer): Integer;
var P: Pointer;
begin
P := FieldPtr( Idx );
if P = nil then
Result := 0
else
case fBindings[ Idx ].wType of
DBTYPE_I1: begin
Result := PByte( P )^;
if LongBool( Result and $80) then
Result := Result or not $7F;
end;
DBTYPE_UI1: Result := PByte( P )^;
DBTYPE_I2, DBTYPE_UI2, DBTYPE_BOOL: Result := PShortInt( P )^;
DBTYPE_NUMERIC, DBTYPE_VARNUMERIC:
begin
if ShortInt(PDBNumeric(P).scale)<>0 then
Result := Round( RField[Idx] )
else
Result := GetFixupNumeric(Idx).Lo;
end;
//DBTYPE_I4, DBTYPE_UI4, DBTYPE_HCHAPTER:
else Result := PInteger( P )^;
end;
end;
function TQuery.GetIsNull(Idx: Integer): Boolean;
var P: PDWORD;
begin
Result := TRUE;
if (fRowSet = nil) or (fCurIndex < 0) or (DWORD(Idx) >= ColCount) then
Exit;
P := Pointer( DWORD( fRowBuffers.Items[ fCurIndex ] ) +
fBindings[ Idx ].obStatus );
Result := P^ = DBSTATUS_S_ISNULL;
end;
function TQuery.GetIsNullByName(const Name: String): Boolean;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
Result := IsNull[ Idx ];
end;
function TQuery.GetRawType(Idx: Integer): DWORD;
begin
Result := 0;
if fBindings = nil then Exit;
Result := fBindings[ Idx ].wType;
end;
function TQuery.GetRawTypeByName(const Name: String): DWORD;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
Result := RawType[ Idx ];
end;
function TQuery.GetRFieldByName(const Name: String): Double;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
Result := RField[ Idx ];
end;
function TQuery.GetRowCount: Integer;
begin
{if fRowsAffected = DB_S_ASYNCHRONOUS then
begin
// only for asynchronous connections - do not see now
end;}
Result := fRowsAffected;
end;
function TQuery.GetRowsKnown: Integer;
begin
Result := fRowsAffected;
if Result = 0 then
if fRowBuffers <> nil then
Result := fRowBuffers.Count;
end;
function TQuery.GetSFieldByName(const Name: String): String;
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
Result := SField[ Idx ];
end;
function TQuery.GetStrField(Idx: Integer): String;
var P: Pointer;
begin
P := FieldPtr( Idx );
if P = nil then
Result := ''
else
if fBindings[ Idx ].wType = DBTYPE_STR then
Result := PChar( P )
else
Result := PWideChar( P );
end;
procedure TQuery.Last;
begin
while not EOF do
Next; //WOFetch( 0 );
if RowsKnown > 0 then
fCurIndex := RowsKnown;
Prev;
//FetchData;
fEOF := FALSE;
end;
procedure TQuery.MarkFieldChanged(Idx: Integer);
begin
Changed( Idx );
end;
procedure TQuery.MarkFieldChangedByName(const Name: String);
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
MarkFieldChanged( Idx );
end;
procedure TQuery.Next;
begin
NextWOFetch( 0 );
FetchData;
end;
procedure TQuery.NextWOFetch( Skip: Integer );
var Obtained: UINT;
PHandle: Pointer;
hr: HResult;
begin
ReleaseHandle;
PHandle := @fRowHandle;
if (fCurIndex = fRowsAffected) and (Skip = -2) then
hr := fRowSet.GetNextRows( 0, -1, 1, Obtained, @PHandle )
else
hr := fRowSet.GetNextRows( 0, Skip, 1, Obtained, @PHandle );
if hr <> DB_S_ENDOFROWSET then
CheckOLE( hr );
Inc( fCurIndex, Skip + 1 );
if Obtained = 0 then
begin
fEOF := TRUE;
if fRowBuffers <> nil then
fRowsAffected := fRowBuffers.Count;
end
else
begin
if fRowBuffers = nil then
fRowBuffers := NewList;
if fCurIndex >= fRowBuffers.Count then
fRowBuffers.Add( nil );
end;
end;
procedure TQuery.Open;
const
DB_NULLID: DBID = (uguid: (guid: (D1: 0; D2: 0; D3:0; D4: (0, 0, 0, 0, 0, 0, 0, 0)));
ekind: 1 {DBKIND_GUID_PROPID}; uname: (ulpropid:0));
var ColInfo: IColumnsInfo;
AccessorIntf: IAccessor;
I: Integer;
OK: Boolean;
PropSets: array[0..0] of TDBPropset;
Props: array[ 0..0 ] of TDBProp;
begin
ClearRowset;
if CheckOLE( fCommand.SetCommandText( @DBGUID_DBSQL, StringToOleStr( fText ) ) ) then
begin
if Mode = rmReadOnly then
begin
if not CheckOLE( fCommand.Execute( nil, IID_IROWSET, nil, @fRowsAffected, PIUnknown( @fRowSet ) ) ) then
Exit;
end
else
begin
// Add by ECM !!!
{$IFNDEF IBPROVIDER}
if fCommandProps = nil then
begin
if CheckOLE( fCommand.QueryInterface( IID_ICommandProperties, fCommandProps ) ) then
begin
PropSets[0].rgProperties := @ Props[ 0 ];
PropSets[0].cProperties := 1;
PropSets[0].guidPropertySet := DBPROPSET_ROWSET;
Props[0].dwPropertyID := $00000075; //DBPROP_UPDATABILITY
Props[0].dwOptions := 0; //DBPROPOPTIONS_REQUIRED;
Props[0].dwStatus := 0; //DBPROPSTATUS_OK;
Props[0].colid := DB_NULLID;
Props[0].vValue.vt := VT_I4;
Props[0].vValue.lVal := 1; //DBPROPVAL_UP_CHANGE;
end;
end;
CheckOLE( fCommandProps.SetProperties( 1, @ PropSets[ 0 ] ) );
{$ENDIF}
if not CheckOLE( fCommand.Execute( nil, IID_IROWSETCHANGE, nil, nil, PIUnknown( @ fRowSetChg ) ) ) then
Exit;
if not CheckOLE( fRowSetChg.QueryInterface( IID_IROWSET, fRowSet ) ) then
Exit;
if Mode = rmUpdateDelayed then
CheckOLE( fRowSetChg.QueryInterface( IID_IROWSETUPDATE, fRowSetUpd ) );
end;
if fRowsAffected = 0 then
Dec( fRowsAffected ); // RowCount = -1 means that RowCount is an unknown value
if fRowSetChg <> nil then
begin
OK := CheckOLE( fRowSetChg.QueryInterface( IID_IColumnsInfo, ColInfo ) );
end
else
begin
OK := CheckOLE( fRowSet.QueryInterface( IID_IColumnsInfo, ColInfo ) );
end;
if OK then
if CheckOLE( ColInfo.GetColumnInfo( fColCount, PDBColumnInfo( fColInfo ), fColNames ) ) then
begin
fBindings := AllocMem( Sizeof( TDBBinding ) * fColCount);
for I := 0 to fColCount - 1 do
begin
fBindings[ I ].iOrdinal := fColInfo[ I ].iOrdinal;
fBindings[ I ].obValue := fRowSize + 4;
// fBindings[ I ].obLength := 0;
fBindings[ I ].obStatus := fRowSize;
// fBindings[ I ].pTypeInfo := nil;
// fBindings[ I ].pObject := nil;
// fBindings[ I ].pBindExt := nil;
fBindings[ I ].dwPart := 1 + 4; //DBPART_VALUE + DBPART_STATUS;
// fBindings[ I ].dwMemOwner := 0; //DBMEMOWNER_CLIENTOWNED;
// fBindings[ I ].eParamIO := 0; //DBPARAMIO_NOTPARAM;
fBindings[ I ].cbMaxLen := fColInfo[ I ].ulColumnSize;
case fColInfo[ I ].wType of
DBTYPE_BSTR: Inc( fBindings[ I ].cbMaxLen, 1 );
DBTYPE_WSTR: fBindings[ I ].cbMaxLen := fBindings[ I ].cbMaxLen * 2 + 2;
end;
fBindings[ I ].cbMaxLen := (fBindings[ I ].cbMaxLen + 3) and not 3;
// fBindings[ I ].dwFlags := 0;
fBindings[ I ].wType := fColInfo[ I ].wType;
fBindings[ I ].bPrecision := fColInfo[ I ].bPrecision;
fBindings[ I ].bScale := fColInfo[ I ].bScale;
Inc( fRowSize, fBindings[ I ].cbMaxLen + 4 );
end;
fBindStatus := AllocMem( Sizeof( DBBINDSTATUS ) * fColCount );
if fRowSetChg <> nil then
begin
OK := CheckOLE( fRowSetChg.QueryInterface( IID_IAccessor, AccessorIntf ) );
end
else
begin
OK := CheckOLE( fRowSet.QueryInterface( IID_IAccessor, AccessorIntf ) );
end;
if OK then
CheckOLE(
AccessorIntf.CreateAccessor(
2, //DBACCESSOR_ROWDATA, // Accessor will be used to retrieve row data
fColCount, // Number of columns being bound
fBindings, // Structure containing bind info
0, // Not used for row accessors
fAccessor, // Returned accessor handle
PUIntArray( fBindStatus ) // Information about binding validity
)
);
fEOF := FALSE;
fCurIndex := -1;
First;
end;
end;
end;
procedure TQuery.Post;
var R: HResult;
{P: PChar;
I: Integer;}
begin
if not fChanged then Exit;
if fRowSetChg = nil then Exit;
R := fRowSetChg.SetData( fRowHandle, fAccessor, fRowBuffers.Items[ fCurIndex ] );
if R <> HResult( $00040EDA {DB_S_ERRORSOCCURED} ) then
CheckOLE( R )
{ // я вижу только статус DBSTATUS_E_INTEGRITYVIOLATION касательно 0-й колонки,
// которую никто не просил добавлять во время выборки.
else
begin
asm
int 3
end;
for I := 0 to fColCount-1 do
begin
P := Pointer( DWORD( fRowBuffers.Items[ fCurIndex ] ) +
fBindings[ I ].obStatus );
ShowMessage( fColInfo[I].pwszName + '.Status=' + Int2Hex( PDWORD( P )^, 8 ) );
end;
end};
fChanged := FALSE;
end;
procedure TQuery.Prev;
begin
if CurIndex > 0 then
begin
NextWOFetch( -2 ); //***
//Dec( fCurIndex );
fEOF := FALSE;
FetchData; //***
end;
end;
procedure TQuery.ReleaseHandle;
begin
if fRowHandle <> 0 then
CheckOLE( fRowSet.ReleaseRows( 1, @fRowHandle, nil, nil, nil ) );
fRowHandle := 0;
end;
procedure TQuery.SetCurIndex(const Value: Integer);
var OldCurIndex: Integer;
begin
OldCurIndex := fCurIndex;
if fCurIndex = Value then
begin
if fRowHandle = 0 then
FetchData;
if fRowHandle <> 0 then
Exit;
end;
if Value = 0 then
First
else
if Value >= fRowsAffected - 1 then
Last;
fEOF := FALSE;
while (fCurIndex < Value) and not EOF do
Next;
while (fCurIndex > Value) and not EOF do
Prev;
if fCurIndex = Value then
FetchData
else
fCurIndex := OldCurIndex;
end;
procedure TQuery.SetDField(Idx: Integer; const Value: TDateTime);
var P: Pointer;
ST: TSystemTime;
pD: PDBDate;
pT: PDBTime;
TS: PDBTimeStamp;
pFT: PFileTime;
begin
P := FieldPtr( Idx );
if P = nil then Exit;
case fBindings[ Idx ].wType of
DBTYPE_DATE: PDouble( P )^ := Value - VCLDate0;
DBTYPE_DBDATE:
begin
pD := P;
DateTime2SystemTime( Value, ST );
pD.year := ST.wYear;
pD.month := ST.wMonth;
pD.day := ST.wDay;
end;
DBTYPE_DBTIME:
begin
pT := P;
DateTime2SystemTime( Value, ST );
pT.hour := ST.wHour;
pT.minute := ST.wMinute;
pT.second := ST.wSecond;
end;
DBTYPE_DBTIMESTAMP:
begin
TS := P;
DateTime2SystemTime( Value, ST );
TS.year := ST.wYear;
TS.month := ST.wMonth;
TS.day := ST.wDay;
TS.hour := ST.wHour;
TS.minute := ST.wMinute;
TS.second := ST.wSecond;
TS.fraction := ST.wMilliseconds * 1000;
end;
DBTYPE_FILETIME:
begin
pFT := P;
DateTime2SystemTime( Value, ST );
SystemTimeToFileTime( ST, pFT^ );
end;
else Exit;
end;
Changed( Idx );
end;
procedure TQuery.SetDFldByName(const Name: String; const Value: TDateTime);
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
DField[ Idx ] := Value;
end;
procedure TQuery.SetFByNameFromStr(const Name, Value: String);
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
FieldAsStr[ Idx ] := Value;
end;
procedure TQuery.SetFieldFromStr(Idx: Integer; const Value: String);
begin
if StrEq( Value, '(null)' ) and (ColType[ Idx ] <> ftString) then
IsNull[ Idx ] := TRUE
else
case ColType[ Idx ] of
ftInteger: IField[ Idx ] := Str2Int( Value );
ftReal: RField[ Idx ] := Str2Double( Value );
ftString: SField[ Idx ] := Value;
ftDate: DField[ Idx ] := Str2DateTimeShort( Value );
end;
end;
procedure TQuery.SetFltField(Idx: Integer; const Value: Double);
var P: Pointer;
begin
P := FieldPtr( Idx );
if P = nil then
Exit;
case fBindings[ Idx ].wType of
DBTYPE_R4: PExtended( P )^ := Value;
DBTYPE_R8: PDouble( P )^ := Value;
DBTYPE_CY: PInteger( P )^ := Round( Value * 10000 );
//TODO: DBTYPE_NUMERIC, DBTYPE_VARNUMERIC, DBTYPE_DECIMAL
else Exit;
end;
Changed( Idx );
end;
procedure TQuery.SetI64Field(Idx: Integer; const Value: Int64);
begin
end;
procedure TQuery.SetI64FldByName(const Name: String; const Value: Int64);
begin
end;
procedure TQuery.SetIFieldByName(const Name: String; Value: Integer);
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
IField[ Idx ] := Value;
end;
procedure TQuery.SetIntField(Idx: Integer; const Value: Integer);
var P: Pointer;
begin
P := FieldPtr( Idx );
if P = nil then
Exit;
case fBindings[ Idx ].wType of
DBTYPE_I1, DBTYPE_UI1: PByte( P )^ := Byte( Value );
DBTYPE_I2, DBTYPE_UI2: PShortInt( P )^ := Value;
DBTYPE_BOOL: if Value <> 0 then PShortInt( P )^ := -1
else PShortInt( P )^ := 0;
else PInteger( P )^ := Value;
end;
Changed( Idx );
end;
procedure TQuery.SetIsNull(Idx: Integer; const Value: Boolean);
var P: PDWORD;
begin
if not Value then Exit;
if (fRowSet = nil) or (fCurIndex < 0) or (DWORD(Idx) >= ColCount) then
Exit;
P := Changed( Idx );
P^ := DBSTATUS_S_ISNULL;
end;
procedure TQuery.SetIsNullByName(const Name: String; const Value: Boolean);
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
IsNull[ Idx ] := Value;
end;
procedure TQuery.SetRFieldByName(const Name: String; const Value: Double);
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
RField[ Idx ] := Value;
end;
procedure TQuery.SetSFieldByName(const Name: String; const Value: String);
var Idx: Integer;
begin
Idx := ColByName[ Name ];
Assert( Idx >=0, 'TQuery: incorrect column name (' + Name + ').' );
SField[ Idx ] := Value;
end;
procedure TQuery.SetStrField(Idx: Integer; const Value: String);
var P: Pointer;
begin
P := FieldPtr( Idx );
if P = nil then
Exit;
if fBindings[ Idx ].wType = DBTYPE_STR then
StrLCopy( PChar( P ), @ Value[ 1 ], fBindings[ Idx ].cbMaxLen )
else
StringToWideChar( Value, PWideChar( P ), fBindings[ Idx ].cbMaxLen );
Changed( Idx );
end;
procedure TQuery.SetText(const Value: String);
begin
// clear here current rowset if any:
ClearRowset;
{// set txt to fCommand -- do this at the last moment just before execute
CheckOLE( fCommand.SetCommandText( DBGUID_DBSQL, StringToOleStr( Value ) ) );}
FText := Value;
end;
procedure TQuery.Update;
var Params, Results: array of DWORD;
I: Integer;
begin
if Mode <> rmUpdateDelayed then Exit;
if (fDelList <> nil) and (fDelList.Count > 0) then
begin
SetLength( Params, fDelList.Count );
SetLength( Results, fDelList.Count );
for I := 0 to fDelList.Count-1 do
Params[ I ] := DWORD( fDelList.Items[ I ] );
CheckOLE( fRowSetUpd.DeleteRows( 0, fDelList.Count, @ Params[ 0 ], @ Results[ 0 ] ) );
Free_And_Nil( fDelList );
end;
if fRowSetUpd = nil then Exit;
CheckOLE( fRowSetUpd.Update( 0, 0, nil, nil, nil, nil ) );
end;
end.