有没有办法让 Delphi 的 FireDAC 识别 FireDAC 生成的 PostgreSQL 位置参数?

Is there a way to make Delphi's FireDAC recognize PostgreSQL positional parameters that FireDAC generated?

我正在使用本机 FireDAC Postgres 驱动程序执行从 FireDAC 到 Postgre 的命名参数查询SQL 11。在准备语句期间,FireDAC 将命名参数转换为位置参数,这是正确的。但是,如果我随后尝试为这些参数赋值,FireDAC 会抛出一个 "Argument out of range" 异常。 FireDAC 似乎无法识别它生成的位置参数。例如,如果原始 SQL 文本看起来像这样:

SELECT * FROM account WHERE accountid = :accid;

调用 FDQuery 的 Prepare 方法后,FireDAC 将此查询转换为:

SELECT * FROM account WHERE accountid = ;

但是当我尝试将值分配给参数时,出现错误。作业看起来像这样:

FDQuery1.Params[0].AsString = strID;

其中 strID 是一个字符串值,accountid 是一个文本字段。此外,如果我使用类似下面的内容,它 returns 0.

ShowMessage( IntToStr( FDQuery1.Params.Count ) );

我已经大大简化了这段代码,但问题是一样的。如何让 FireDAC 识别它生成的位置参数?


Update :正如我提到的,上面的代码被大大简化了。实际发生的是,在我们的框架中,我们有一组例程为 FireDAC 宏赋值,然后我们通过准备查询生成 SQL 语句,然后读取 FDQuery 的文本 属性。然后 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 = ;';
  Query.Params[0].AsString := '4'; // BANG! Argument out of range

我认为可能是FireDAC宏扩展的原因,所以我在实例化FDQuery后添加了以下两行:

Query.ResourceOptions.MacroCreate := False;
Query.ResourceOptions.MacroExpand := False;

没有。那确实有帮助。我猜测 FireDAC 根本无法识别 $1 是 PostgreSQL.

中的有效位置参数

您需要将符号参数标识符(在您的情况下为 :accid)放入 SQL.Text 字符串中,而不是位置代码 (</code>)</p> <p>我刚刚测试了这两个版本。第一个有效,第二个无效。 </p> <pre><code>var MyQ : tfdquery; begin MyQ := Tfdquery.Create(nil); MyQ.Connection := dm1.dbMain; MyQ.SQL.Text := 'Select * from person where lastname = :lname;'; MyQ.Params[0].AsString := 'Brodzinsky'; MyQ.Open(); ShowMessage('Records found = '+MyQ.RecordCount.ToString); MyQ.Close; MyQ.Free; end;

接下来尝试使用定位。当然,FireDac 没有看到冒号,所以不知道有一个参数要创建

var
  MyQ : tfdquery;
begin
  MyQ := Tfdquery.Create(nil);
  MyQ.Connection := dm1.dbMain;
  MyQ.SQL.Text := 'Select * from person where lastname = ;';
  MyQ.Params[0].AsString := 'Brodzinsky';
  MyQ.Open();
  ShowMessage('Records found = '+MyQ.RecordCount.ToString);
  MyQ.Close;
  MyQ.Free;
end;

第一个返回的人table中的11条记录都是我的姓氏;第二,生成参数超出范围错误,因为在 SQL 文本中没有指定参数。注意:我正在访问 MySQL 数据库,但这里的问题是 Delphi & FireDac 预处理代码以发送到数据库服务器。

好的,可能有一种方法可以使用 FireDAC 属性解决此问题,但我还没有找到它。然而,对于这种特殊情况,SQL 是在一种方法中准备的,然后从另一种方法中分配给不同的 FDQuery,我找到了答案。由于 PostgreSQL 允许命名参数使用数字,例如 :1,我所做的就是将 $ 字符替换为 : 字符。如

var
  SQLStmt: String;
  FDQuery: TFDQuery;
begin
  SQLStmt :=  'SELECT * FROM tablename WHERE field2 = ;';
  FDQuery := TFDQuery.Create( nil );
  FDQuery.Connection := FDConnection1;
  FDQuery.SQL.Text := SQLStmt.Replace( '$', ':' );
  FDQuery.Params[0].AsString := 'SomeValue'); // Works!
  ...

而且,是的,如果您的查询包含多个命名参数实例,FireDAC 会将其替换为相同的数字。

如果我找到另一个解决方案,我会post。如果其他人使用 FireDAC 属性提出解决方案,我将 select 该答案作为正确答案。