With Delphi 10.2 (Tokyo), I just want to do something as simple as:
function ShowFinalSQL(const qry: TFDQuery): String;
var
cSQL: String;
oParam: TFDParam;
begin
cSQL := qry.SQL.Text;
for oParam in qry.Params do
cSQL := cSQL.Replace(oParam.Name, oParam.Value);
Result := cSQL;
end;
But I always get the error message:
[dcc32 Error] DTUtilBD.pas(3115): E2010 Incompatible types: 'TFDParam' and 'TCollectionItem'
Is there a way of doing it?
TFDQuery.Params
is a TFDParams
, which can be iterated with a for..in
loop as it has a public GetEnumerator()
method. However, that method is inherited from TCollection
to iterate TCollectionItem
items, so it is not specialized for TFDParam
items (feel free to file a bug report about that oversight).
As such, when the loop iteration tries to assign the enumerator's Current
property to your oParam
variable, it fails to compile because a TCollectionItem
cannot be assigned to a TFDParam
. Which is exactly what the compiler error is complaining about.
Your code basically gets compiled as-if it had been written like this:
function ShowFinalSQL(const qry: TFDQuery): String;
var
cSQL: String;
oParam: TFDParam;
cEnum: TCollectionEnumerator;
begin
cSQL := qry.SQL.Text;
//for oParam in qry.Params do
cEnum := qry.Params.GetEnumerator;
while cEnum.MoveNext do
begin
oParam := cEnum.Current; // <-- ERROR HERE - cEnum.Current is TCollectionItem!
cSQL := cSQL.Replace(oParam.Name, oParam.Value);
end;
Result := cSQL;
end;
To fix this, you need to change your oParam
variable to be a TCollectionItem
instead of a TFDParam
. You will just have to type-cast it when you want to access any TFDParam
-specific members, eg:
function ShowFinalSQL(const qry: TFDQuery): String;
var
cSQL: String;
oParam: TCollectionItem;
begin
cSQL := qry.SQL.Text;
for oParam in qry.Params do
cSQL := cSQL.Replace(TFDParam(oParam).Name, TFDParam(oParam).Value);
Result := cSQL;
end;
Alternatively:
function ShowFinalSQL(const qry: TFDQuery): String;
var
cSQL: String;
oItem: TCollectionItem;
oParam: TFDParam;
begin
cSQL := qry.SQL.Text;
for oItem in qry.Params do
begin
oParam := TFDParam(oItem);
cSQL := cSQL.Replace(oParam.Name, oParam.Value);
end;
Result := cSQL;
end;
UPDATE: Alternatively, if you want to avoid type-casting manually, you can use absolute
:
function ShowFinalSQL(const qry: TFDQuery): String;
var
cSQL: String;
oItem: TCollectionItem;
oParam: TFDParam absolute oItem;
begin
cSQL := qry.SQL.Text;
for oItem in qry.Params do
begin
cSQL := cSQL.Replace(oParam.Name, oParam.Value);
end;
Result := cSQL;
end;