Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timestamp parameters of stored procedures get assigned as date [ODBC27] #28

Closed
firebird-automations opened this issue May 25, 2007 · 5 comments

Comments

@firebird-automations
Copy link

Submitted by: Milan Babuskov (babuskov)

I have Delphi code like this:

storedProc: TADOStoredProc;
storedProc := TADOStoredProc.Create(nil);
try
with storedProc do
begin
ProcedureName := 'SetMyTime';

with Parameters\.AddParameter do
begin
  Name := '@Id';
  DataType := ftInteger;
  Value := 1;
end;

with Parameters\.AddParameter do
begin
  Name := '@MyTime';
  DataType := ftDateTime;
  Value := now;
end;

ExecProc;
end;

The call succeeds, but only date part is written into database. Here's how the stored procedure looks like:

create table t1 ( x integer, tm timestamp );
insert into t1 (x, tm) values (1, current_timestamp);

create procedure SetMyTime ( id integer, mytime timestamp )
as
begin
update t1 set tm = :mytime where x = :id;
end

@firebird-automations
Copy link
Author

Modified by: @alexpotapchenko

assignee: Vladimir Tsvigun [ praktik ] => Alexander Potapchenko [ lightfore ]

@firebird-automations
Copy link
Author

Commented by: @alexpotapchenko

It is not a bug of ODBC driver, It is ADO trouble.
ADO transfers ftDateTime parameter into SQLBindParameter (ODBC driver level) as SQL_C_TYPE_DATE in this case.

You need the following code:
with Parameters.AddParameter do
begin
Name := 'MyTime';
DataType := ftString;
Value := FormatDateTime('yyyy-mm-dd hh:nn:ss', now);
end;

@firebird-automations
Copy link
Author

Modified by: @alexpotapchenko

status: Open [ 1 ] => Resolved [ 5 ]

resolution: Won't Fix [ 2 ]

Fix Version: 2.0 Beta [ 10043 ]

@firebird-automations
Copy link
Author

Modified by: @alexpotapchenko

status: Resolved [ 5 ] => Closed [ 6 ]

@firebird-automations
Copy link
Author

Commented by: Ľubomír Herda (lubomir)

The bug is in ADODB unit (adodb.pas).

Solution: Replace original code by fixed code (search all "Fix" word in text).

...
DataTypeValues: array[TDataType] of TOleEnum = (
adEmpty, adVarChar, adSmallint, adInteger, adUnsignedSmallint,
// Orig adBoolean, adDouble, adDouble, adCurrency, adDate, adDate,
adBoolean, adDouble, adCurrency, adDouble, adDBDate, adDBTime, // Fix
adDate, adBinary, adVarBinary, adInteger, adLongVarBinary,
adLongVarChar, adLongVarBinary, adLongVarBinary, adLongVarBinary,
adLongVarBinary, adLongVarBinary, adEmpty, adChar, adVarWChar, adBigInt,
adEmpty, adEmpty, adEmpty, adEmpty, adEmpty, adEmpty, adVariant,
// Orig adIUnknown, adIDispatch, adGuid, adEmpty, adEmpty
adIUnknown, adIDispatch, adGuid, adDBTimeStamp, adEmpty // Fix
);
...
function ADOTypeToFieldType(const ADOType: DataTypeEnum; EnableBCD: Boolean = True): TFieldType;
begin
case ADOType of
adEmpty: Result := ftUnknown;
adTinyInt, adSmallInt: Result := ftSmallint;
adError, adInteger, adUnsignedInt: Result := ftInteger;
adBigInt, adUnsignedBigInt: Result := ftLargeInt;
adUnsignedTinyInt, adUnsignedSmallInt: Result := ftWord;
adSingle, adDouble: Result := ftFloat;
adCurrency: Result := ftBCD;
adBoolean: Result := ftBoolean;
adDBDate: Result := ftDate;
adDBTime: Result := ftTime;
// Orig adDate, adDBTimeStamp, adFileTime, adDBFileTime: Result := ftDateTime;
adDate, adFileTime, adDBFileTime: Result := ftDateTime; // Fix
adChar: Result := ftFixedChar;
adVarChar: Result := ftString;
adBSTR, adWChar, adVarWChar: Result := ftWideString;
adLongVarChar, adLongVarWChar: Result := ftMemo;
adLongVarBinary: Result := ftBlob;
adBinary: Result := ftBytes;
adVarBinary: Result := ftVarBytes;
adChapter: Result := ftDataSet;
adPropVariant, adVariant: Result := ftVariant;
adIUnknown: Result := ftInterface;
adIDispatch: Result := ftIDispatch;
adGUID: Result := ftGUID;
adDBTimeStamp: Result := ftTimeStamp; // Fix
adDecimal, adNumeric, adVarNumeric:
if EnableBCD then Result := ftBCD
else Result := ftFloat;
else
Result := ftUnknown;
end;
end;
...
function FieldTypeToADOType(const FieldType: TFieldType): DataTypeEnum;
begin
case FieldType of
ftUnknown: Result := adEmpty;
ftString, ftWideString: Result := adVarChar;
ftSmallint: Result := adSmallint;
ftInteger, ftAutoInc: Result := adInteger;
ftWord: Result := adUnsignedSmallInt;
ftBoolean: Result := adBoolean;
ftFloat: Result := adDouble;
ftCurrency, ftBCD: Result := adCurrency;
ftDate: Result := adDBDate;
ftTime: Result := adDBTime;
// Orig ftDateTime: Result := adDBTimeStamp;
ftDateTime: Result := adDate; // Fix
ftBytes: Result := adBinary;
ftVarBytes: Result := adVarBinary;
ftMemo: Result := adLongVarChar;
ftBlob, ftGraphic..ftTypedBinary: Result := adLongVarBinary;
ftFixedChar: Result := adChar;
ftLargeint: Result := adBigInt;
ftVariant: Result := adVariant;
ftInterface: Result := adIUnknown;
ftIDispatch: Result := adIDispatch;
ftGuid: Result := adGUID;
ftTimeStamp: Result := adDBTimeStamp; // Fix
else
DatabaseErrorFmt(SNoMatchingADOType, [FieldTypeNames[FieldType]]);
Result := adEmpty;
end;
end;
...
procedure AddFieldDef(F: Field; FieldDefs: TFieldDefs);
var
FieldType: TFieldType;
FieldDef: TFieldDef;
I: Integer;
FName: string;
FSize: Integer;
FPrecision: Integer;
begin
FieldType := ADOTypeToFieldType(F.Type_, EnableBCD);
if FieldType <> ftUnknown then
begin
FSize := 0;
FPrecision := 0;
FieldDef := FieldDefs.AddFieldDef;
with FieldDef do
begin
FieldNo := FieldDefs.Count;
I := 0;
FName := http://F.Name;
while (FName = '') or (FieldDefs.IndexOf(FName) >= 0) do
begin
Inc(I);
if http://F.Name = '' then
FName := Format('COLUMN%d', [I]) else { Do not localize }
FName := Format('%s_%d', [http://F.Name, I]);
end;
Name := FName;
if (F.Type_ = adNumeric) and (F.NumericScale = 0) and
(F.Precision < 10) then
FieldType := ftInteger;
case FieldType of
ftString, ftWideString, ftBytes, ftVarBytes, ftFixedChar:
FSize := F.DefinedSize;
ftBCD:
begin
FPrecision := F.Precision;
FSize := ShortInt(F.NumericScale);
if FSize < 0 then FSize := 4;
end;
ftInteger:
if HasAutoIncProp and (F.Properties[SIsAutoInc].Value = True) then
FieldType := ftAutoInc;
ftTimeStamp:
FieldType := ftDateTime; // Fix
ftGuid:
FSize := 38;
end;

    if \(\(adFldRowID and F\.Attributes\) <\> 0\) then
       Attributes := Attributes \+ \[faHiddenCol\];
    if \(\(adFldFixed and F\.Attributes\) <\> 0\) then
       Attributes := Attributes \+ \[faFixed\];
    if \(\(\(adFldUpdatable\+adFldUnknownUpdatable\) and F\.Attributes\) = 0\) or
       \(FieldType = ftAutoInc\) then
      Attributes := Attributes \+ \[faReadOnly\];
    DataType := FieldType;
    Size := FSize;
    Precision := FPrecision;
    if \(DataType = ftDataSet\) and \(Fields\.Count = 0\) then
      ObjectView := True;
  end;
end;

end;
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants