I have a TFDConnection
to a FireBird database for which I apply Data type mapping for backward compatibility with a previous data access technology (SQLDirect):
with FormatOptions.MapRules.Add do // TIMESTAMP will be ftDateTime instead of ftTimeStamp
begin
SourceDataType := dtDateTimeStamp;
TargetDataType := dtDateTime;
end;
with FormatOptions.MapRules.Add do // FLOAT will be ftFloat instead of ftSingle
begin
SourceDataType := dtSingle;
TargetDataType := dtDouble;
end;
FormatOptions.OwnMapRules := true;
At runtime I create a TFDQuery that I link to that TFDConnection.
I can see that it inherits the mapping rules: FormatOptions.MapRules.count=2
I assign an INSERT query to its SQL.Text:
insert into TT_ACT (TT_ACT_ID,TT_PARENT_ID,TT_FROMDATE,TT_TODATE,TT_NAME,TT_NR,TT_CODE,TT_GROUP...)
values (:TT_ACT_ID,:TT_PARENT_ID,:TT_FROMDATE,:TT_TODATE,:TT_NAME,:TT_NR,:TT_CODE,:TT_GROUP,...)
This gives me params.count=42
with parameters with datatype ftUnknown (of course).
I then call Prepare for the query.
If I now inspect a known datetime parameter, I see params[x].datatype = ftTimeStamp
, not ftDateTime
.
So when the query goes back to the database to look at the fields, it does not seem to listen to the data mapping rules when setting up the parameters.
Is this a bug?
In a later stage in my code this got me into trouble, resulting in the famous 338 error:
[FireDac][Phys][IB]-338 Param [TT_FROMDATE] type changed from [ftSQLTimeStamp] to [ftDateTime]. Query must be reprepared.
I managed to work around that error, so that is not part of the question. But I would expect the Params to follow data type mapping rules as well, that would have made all this easier.
You just misdefined the mapping rule definitions. For parameters, it is transformation of target into source. The Data Type Mapping topic says that as well:
So to map command parameters from TIMESTAMP to dtDateTime and FLOAT to dtDouble just swap source with target in your definition:
It's worth adding that mapping rules for parameters do the only thing. They only map data types for parameters when command is being prepared (data types must be determinable for them). They're not converting parameter values as they are passed to the driver. Consider this code:
So as you can see, it's quite a lot of effort for almost nothing (changing determined parameter data type to another only). Parameter values are converted automatically regardless mapping rules. So, even if your parameter data type won't match DBMS data type but will be convertible, FireDAC will simply convert it for you no matter what (this magic is inside ConvertRawData method):
So even here I would repeat, that parameter collections should be defined manually rather than by the DBMS from a prepared command (developer must know what values fill into which fields).