在 Delphi Rio (10.3.3) 中,当宏为 NULL 时,fdQuery 无法正确转换条件函数 'iif'

In Delphi Rio (10.3.3) fdQuery does not correctly translate conditional function 'iif' when a macro is NULL

我有以下 SQL 命令来 运行 使用 PostgreSQL 作为数据库的 TFDQuery 查询:

fdqr.SQL.Text: = 
  'select * from (values (current_date-1), (current_date), (current_date + 1)) as t (datetest) ' +
  '{iif (! Datevalue, where datetest =! Datevalue)}';

当我使用Clear方法清除宏值时,我希望脚本被解释以便过滤器被消除,但事实并非如此。

fdqr.MacroByName('datevalue').Clear;
fdqr.Open;

生成的数据库日志:

select * from (values(current_date-1), (current_date), (current_date+1)) as t(datetest) 
where datetest = NULL

但是,如果您通过 AsRaw 包含赋值,它会按预期工作,即使先前的值为 ''(空字符串)并且 IsNullTrue.

fdqr.MacroByName('datevalue').Clear;
{ at this point IsNull = True and AsRaw is '' }
fdqr.MacroByName('datevalue').AsRaw := '';
fdqr.Open;

生成的数据库日志:

select * from (values(current_date-1), (current_date), (current_date+1)) as t(datetest) 

这是 FireDAC 错误还是 feature 我没有理解正确?

为了根据宏变量应用 {IIF(…)}{IF}…{FI} 的替换,变量值不能为空。 Conditional Substitution 的文档就是这么说的。它的字面意思是,如果宏变量扩展为 non-empty 字符串,则应用替换。这个事实可以通过检查 FireDAC 源代码来验证,特别是单元 FireDAC.Phys.Meta 中的方法 TFDPhysConnectionMetadata.TranslateEscapeSequence。如果 eskIF 你可以找到:

s := Trim(ASeq.FArgs[0]);
…
else if s <> '' then
  Result := 'True';

让我们看看当您 Clear 宏变量时会发生什么。其 Value 设置为 Null,其 DataType 设置为 mdUnknown。在这种情况下,预处理器将变量扩展为 NULL 文字,这不是空字符串。 AsRaw 的值无关紧要,因为预处理器使用 SQL 属性 进行替换。

除了设置AsRaw := '',似乎没有其他方法可以将宏变量扩展为空字符串。在这种情况下,它的 DataType 设置为 mdRaw 并且值 SQL 属性 等于 AsRaw.

我不确定此行为是错误还是功能,但更改它可能会破坏现有代码库,因此我不希望此问题得到修复。我宁愿说它最终成为一个功能。

除上述之外,您还可以通过使用简单的参数来避免宏:

select * from (values(current_date-1), (current_date), (current_date+1)) as t(datetest) 
where :Datevalue is null or datetest = :Datevalue

通过这种方式,您可以按照预期清除或设置 Datevalue 参数的值:

{ to bind null value }
fdqr.ParamByName('Datevalue').Clear;
{ to bind some value }
fdqr.ParamByName('Datevalue').AsDate := Today;