Skip to content

Commit

Permalink
for TSqlDBOleDBStatement: let TSqlDBColumnProperty.ColumnValueDBType
Browse files Browse the repository at this point in the history
to store the raw DBTYPE value
  • Loading branch information
Arnaud Bouchez committed Oct 16, 2021
1 parent c538fa4 commit b916aff
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 37 deletions.
108 changes: 71 additions & 37 deletions src/db/mormot.db.sql.oledb.pas
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ TSqlDBOleDBStatement = class(TSqlDBStatement)
constructor Create(aConnection: TSqlDBConnection); override;
/// release all associated memory and COM objects
destructor Destroy; override;
/// retrieve column information from a supplied IRowSet
/// internal method to retrieve column information from a supplied IRowSet
// - is used e.g. by TSqlDBOleDBStatement.Execute or to retrieve metadata columns
// - raise an exception on error
procedure FromRowSet(RowSet: IRowSet);
Expand Down Expand Up @@ -444,6 +444,7 @@ TSqlDBOleDBStatement = class(TSqlDBStatement)
// since Delphi 2009: you may not loose any data during charset conversion
// - a ftBlob content will be mapped into a TBlobData AnsiString variant
function ColumnToVariant(Col: integer; var Value: Variant): TSqlDBFieldType; override;

/// just map the original Collection into a TSqlDBOleDBConnection class
property OleDBConnection: TSqlDBOleDBConnection
read fOleDBConnection;
Expand Down Expand Up @@ -811,13 +812,14 @@ constructor TSqlDBOleDBStatement.Create(aConnection: TSqlDBConnection);
1:
(Double: double);
2:
( case integer of
0:
(VData: array[0..0] of byte);
1:
(VWideChar: PWideChar);
2:
(VAnsiChar: PAnsiChar)
(
case integer of
0:
(VData: array[0..0] of byte);
1:
(VWideChar: PWideChar);
2:
(VAnsiChar: PAnsiChar)
);
end;

Expand All @@ -828,16 +830,12 @@ procedure TSqlDBOleDBStatement.LogStatusError(Status: integer;
var
msg: RawUtf8;
begin
{$ifndef PUREPASCAL}
if cardinal(Status) <= cardinal(ord(high(TSqlDBOleDBStatus))) then
msg := UnCamelCase(TrimLeftLowerCaseShort(
GetEnumName(TypeInfo(TSqlDBOleDBStatus), Status)))
else
{$else}
Int32ToUtf8(Status, msg);
{$endif}
SynDBLog.Add.Log(sllError, 'Invalid [%] status for column [%] at row % for %',
[{%H-}msg, Column^.ColumnName, fCurrentRow, fSql], self);
GetEnumName(TypeInfo(TSqlDBOleDBStatus), Status)));
SynDBLog.Add.Log(sllError,
'Invalid [%] % status for column [%] at row % for %',
[{%H-}msg, Status, Column^.ColumnName, fCurrentRow, fSql], self);
end;

function TSqlDBOleDBStatement.GetCol(Col: integer;
Expand Down Expand Up @@ -1071,7 +1069,10 @@ function TSqlDBOleDBStatement.ColumnToVariant(Col: integer; var Value: Variant):
begin
VType := MAP_FIELDTYPE2VARTYPE[result];
case result of
ftInt64, ftDouble, ftCurrency, ftDate:
ftInt64,
ftDouble,
ftCurrency,
ftDate:
VInt64 := V^.Int64; // copy 64 bit content
ftUtf8:
begin
Expand Down Expand Up @@ -1220,18 +1221,31 @@ function TSqlDBOleDBStatement.ParamToVariant(Param: integer; var Value: Variant;

const
PARAMTYPE2OLEDB: array[TSqlDBParamInOutType] of DBPARAMIO = (
DBPARAMIO_INPUT, DBPARAMIO_OUTPUT, DBPARAMIO_INPUT or DBPARAMIO_OUTPUT);
DBPARAMIO_INPUT, // paramIn
DBPARAMIO_OUTPUT, // paramOut
DBPARAMIO_INPUT or DBPARAMIO_OUTPUT); // paramInOut

FIELDTYPE2OLEDB: array[TSqlDBFieldType] of DBTYPE = (
DBTYPE_EMPTY, DBTYPE_I4, DBTYPE_I8, DBTYPE_R8, DBTYPE_CY, DBTYPE_DATE,
DBTYPE_WSTR or DBTYPE_BYREF, DBTYPE_BYTES or DBTYPE_BYREF);
DBTYPE_EMPTY, // ftUnknown
DBTYPE_I4, // ftNull
DBTYPE_I8, // ftInt64
DBTYPE_R8, // ftDouble
DBTYPE_CY, // ftCurrency
DBTYPE_DATE, // ftDate
DBTYPE_WSTR or DBTYPE_BYREF, // ftUtf8
DBTYPE_BYTES or DBTYPE_BYREF); // ftBlob

FIELDTYPE2OLEDBTYPE_NAME: array[TSqlDBFieldType] of WideString = (
'', 'DBTYPE_I4', 'DBTYPE_I8', 'DBTYPE_R8', 'DBTYPE_CY', 'DBTYPE_DATE',
'DBTYPE_WVARCHAR', 'DBTYPE_BINARY');
// ftUnknown, ftNull, ftInt64, ftDouble, ftCurrency, ftDate, ftUtf8, ftBlob
'', // ftUnknown
'DBTYPE_I4', // ftNull
'DBTYPE_I8', // ftInt64
'DBTYPE_R8', // ftDouble
'DBTYPE_CY', // ftCurrency
'DBTYPE_DATE', // ftDate
'DBTYPE_WVARCHAR', // ftUtf8
'DBTYPE_BINARY'); // ftBlob

TABLE_PARAM_DATASOURCE: WideString = 'table';
TABLE_PARAM_DATASOURCE: PWideChar = 'table';

procedure TSqlDBOleDBStatement.Prepare(const aSql: RawUtf8; ExpectResults: boolean);
var
Expand Down Expand Up @@ -1308,7 +1322,8 @@ procedure TSqlDBOleDBStatement.ExecutePrepared;
for i := 0 to fParamCount - 1 do
case fParams[i].VType of
ftUnknown:
raise EOleDBException.CreateUtf8('%.Execute: missing #% bound parameter for [%]',
raise EOleDBException.CreateUtf8(
'%.Execute: missing #% bound parameter for [%]',
[self, i + 1, fSql]);
end;
P := pointer(fParams);
Expand Down Expand Up @@ -1380,7 +1395,11 @@ procedure TSqlDBOleDBStatement.ExecutePrepared;
BI.pwszDataSourceType := 'DBTYPE_WVARCHAR';
BI.dwFlags := BI^.dwFlags or DBPARAMFLAGS_ISNULLABLE;
end;
ftInt64, ftDouble, ftCurrency, ftDate: // those types match the VInt64 binary representation :)
ftInt64,
ftDouble,
ftCurrency,
ftDate:
// those types match the VInt64 binary representation :)
B^.cbMaxLen := SizeOf(Int64);
ftBlob:
begin
Expand Down Expand Up @@ -1668,21 +1687,26 @@ function TSqlDBOleDBStatement.BindColumns(ColumnInfo: IColumnsInfo;
Col^.ColumnNonNullable := nfo^.dwFlags and DBCOLUMNFLAGS_MAYBENULL = 0;
Col^.ColumnAttr := result; // offset of status[-length]-value in fRowSetData[]
Col^.ColumnValueInlined := true;
Col^.ColumnValueDBType := nfo^.wType;
B^.iOrdinal := nfo^.iOrdinal;
B^.eParamIO := DBPARAMIO_NOTPARAM;
B^.obStatus := result;
inc(result, SizeOf(PtrInt)); // TColumnValue.Status
B^.wType := FIELDTYPE2OLEDB[Col^.ColumnType];
case Col^.ColumnType of
ftInt64, ftDouble, ftCurrency, ftDate:
ftInt64,
ftDouble,
ftCurrency,
ftDate:
begin
inc(result, SizeOf(PtrUInt)); // ignore TColumnValue.Length
B^.dwPart := DBPART_STATUS or DBPART_VALUE;
B^.obValue := result;
B^.cbMaxLen := SizeOf(Int64);
inc(result, SizeOf(Int64));
end;
ftUtf8, ftBlob:
ftUtf8,
ftBlob:
begin
B^.dwPart := DBPART_STATUS or DBPART_VALUE or DBPART_LENGTH;
B^.obLength := result; // need length field in fRowSetData[]
Expand All @@ -1697,7 +1721,9 @@ function TSqlDBOleDBStatement.BindColumns(ColumnInfo: IColumnsInfo;
if Col^.ColumnType = ftUtf8 then
begin
case nfo^.wType of
DBTYPE_STR, DBTYPE_BSTR, DBTYPE_WSTR:
DBTYPE_STR,
DBTYPE_BSTR,
DBTYPE_WSTR:
len := len * 2; // ulColumnSize = WideChar count
DBTYPE_GUID:
len := 78;
Expand Down Expand Up @@ -2084,6 +2110,17 @@ procedure TSqlDBOleDBConnectionProperties.GetTableNames(out Tables: TRawUtf8DynA
end;
end;

const
DBTYPE_DISPLAY: array[TSqlDBFieldType] of RawUtf8 = (
'???', // ftUnknown
'null', // ftNull
'int', // ftInt64
'double', // ftDouble
'currency', // ftCurrency
'date', // ftDate
'nvarchar', // ftUtf8
'blob'); // ftBlob

procedure TSqlDBOleDBConnectionProperties.GetFields(const aTableName: RawUtf8;
out Fields: TSqlDBColumnDefineDynArray);
var
Expand All @@ -2092,9 +2129,6 @@ procedure TSqlDBOleDBConnectionProperties.GetFields(const aTableName: RawUtf8;
n, i: integer;
F: TSqlDBColumnDefine;
FA: TDynArray;
const
DBTYPE_DISPLAY: array[TSqlDBFieldType] of RawUtf8 = ('???', 'null', 'int',
'double', 'currency', 'date', 'nvarchar', 'blob');
begin
inherited; // first try from SQL, if any (faster)
if Fields <> nil then
Expand Down Expand Up @@ -2166,11 +2200,11 @@ procedure TSqlDBOleDBConnectionProperties.GetForeignKeys;
FromRowSet(Rows);
while Step do
fForeignKeys.Add(TrimU(ColumnUtf8('FK_TABLE_SCHEMA')) + '.' +
TrimU(ColumnUtf8('FK_TABLE_NAME')) + '.' +
TrimU(ColumnUtf8('FK_COLUMN_NAME')),
TrimU(ColumnUtf8('PK_TABLE_SCHEMA')) + '.' +
TrimU(ColumnUtf8('PK_TABLE_NAME')) + '.' +
TrimU(ColumnUtf8('PK_COLUMN_NAME')));
TrimU(ColumnUtf8('FK_TABLE_NAME')) + '.' +
TrimU(ColumnUtf8('FK_COLUMN_NAME')),
TrimU(ColumnUtf8('PK_TABLE_SCHEMA')) + '.' +
TrimU(ColumnUtf8('PK_TABLE_NAME')) + '.' +
TrimU(ColumnUtf8('PK_COLUMN_NAME')));
finally
Free;
end;
Expand Down
1 change: 1 addition & 0 deletions src/db/mormot.db.sql.pas
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ interface
// - for TSqlDBOdbcStatement: used to store the DataType as returned
// by ODBC.DescribeColW() - use private ODBC_TYPE_TO[ColumnType] to
// retrieve the marshalled type used during column retrieval
// - for TSqlDBOleDBStatement: used to store the DBTYPE value
// - for TSqlDBFirebirdStatement: used to store XSQLVAR.sqltype
// - for TSqlDBDatasetStatement: indicates the TField class type, i.e.
// 0=TField, 1=TLargeIntField, 2=TWideStringField
Expand Down

0 comments on commit b916aff

Please sign in to comment.