2210 lines
74 KiB
ObjectPascal
2210 lines
74 KiB
ObjectPascal
unit KOLEdb;
|
|
{* This unit is created for KOL to allow to communicate with DB using OLE DB.
|
|
|<br> ========================================================================
|
|
|<br> Copyright (C) 2001 by Vladimir Kladov.
|
|
|<p>
|
|
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.
|
|
|</p>
|
|
}
|
|
|
|
interface
|
|
|
|
uses Windows, ActiveX, KOL, err;
|
|
|
|
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: PMultiQI): 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: ITypeInfo;
|
|
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.
|
|
|<br>
|
|
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
|
|
raise Exception.Create( e_Custom, 'OLE DB error ' + Int2Hex( Result, 8 ) );
|
|
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.
|