【问题标题】:In Delphi Rio (10.3.3) fdQuery does not correctly translate conditional function 'iif' when a macro is NULL在 Delphi Rio (10.3.3) 中,当宏为 NULL 时,fdQuery 无法正确转换条件函数 'iif'
【发布时间】:2020-08-05 15:29:01
【问题描述】:

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

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

【问题讨论】:

    标签: delphi macros firedac


    【解决方案1】:

    为了应用基于宏变量的{IIF(…)}{IF}…{FI} 替换,变量值不能为空。这就是Conditional Substitution 的文档所说的。它的字面意思是如果宏变量扩展为非空字符串,则应用替换。这个事实可以通过检查 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 设置为mdRawSQL 属性的值等于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;
    

    【讨论】:

    • 感谢您的详细说明。但是,我注意到在我的测试中,在Clear(宏或参数)之后,类型并没有更改为mdUnknown。关于“使用简单参数”的建议,在我的情况下,这不是一个选项,因为我需要在某些情况下没有过滤器并使用您的建议(...其中:Datevalue 为 null 或 datetest =:Datevalue),这是一个有趣的替代方案,尽管我更喜欢 iif 以使最终的 SQL 更清晰。
    • @AnselmoMS TFDMacro.Clear 的实现非常简单——它只调用SetData(Null, mdUnknown);。由于其极其丑陋的实现,当此方法不会更改DataType 时,存在一些极端情况(值得一试,笑出声)。基本上,如果原始值等于Null,则该方法拒绝将数据类型更改为mdUnknown。这个相等性测试依赖于一大堆全局变量 - 请参阅 NullEqualityRule 和朋友。
    猜你喜欢
    • 2021-06-12
    • 2020-06-01
    • 2020-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    相关资源
    最近更新 更多