有没有办法让 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 该答案作为正确答案。
我正在使用本机 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 该答案作为正确答案。