我正在使用本地 FireDAC Postgres 驱动程序使用从 FireDAC 到 PostgreSQL 11 的命名参数执行查询。在准备语句期间,FireDAC 将命名参数转换为位置参数,这是正确的。但是,如果我随后尝试为这些参数赋值,FireDAC 会引发“参数超出范围”异常。FireDAC 似乎无法识别它生成的位置参数。例如,如果原始 SQL 文本如下所示:
SELECT * FROM account WHERE accountid = :accid;
在调用 FDQuery 的 Prepare 方法后,FireDAC 将此查询转换为:
SELECT * FROM account WHERE accountid = $1;
但是当我尝试将值分配给参数时,我得到了错误。分配看起来像这样:
FDQuery1.Params[0].AsString = strID;
其中 strID 是一个字符串值,accountid 是一个文本字段。此外,如果我使用类似以下的内容,它会返回 0。
ShowMessage( IntToStr( FDQuery1.Params.Count ) );
我已经大大简化了这段代码,但问题是一样的。如何让 FireDAC 识别它生成的位置参数?
更新:正如我所提到的,上面的代码被大大简化了。实际发生的是,在我们的框架中,我们有一组例程为 FireDAC 宏分配值,然后我们通过准备查询然后读取 FDQuery 的 Text 属性来生成 SQL 语句。然后,该 SQL 语句被分配给另一个 FDQuery(也是动态创建的)的 SQL.Text 属性,并且在那里查询失败。所以,这里有一个非常简单的例子,说明代码内部发生了什么:
var
Query: TFDQuery;
begin
Query := TFDQuery.Create( nil );
Query.Connection := PGConnection;
// In reality, the SQL statement below was generated earlier,
// from a function call where the SQL was created by the FireDAC
// SQL preprocessor, as opposed to being a literal expression
Query.SQL.Text := 'SELECT * FROM tablename WHERE field2 = $1;';
Query.Params[0].AsString := '4'; // BANG! Argument out of range
我以为可能是FireDAC宏扩展的原因,所以在实例化FDQuery后添加了以下两行:
Query.ResourceOptions.MacroCreate := False;
Query.ResourceOptions.MacroExpand := False;
没有。这也有帮助。我猜 FireDAC 根本不承认 $1 是 PostgreSQL 中的有效位置参数。