使用 SQLDirect 组件时 TClientDataset.ApplyUpdates 失败并显示 'SQL not supported'
TClientDataset.ApplyUpdates fails with 'SQL not supported' when using SQLDirect components
从 DelphiXE2 更新到 Delphi Seattle 10 Update 1 后,我们在使用 SQLDirect components 版本 6.4 时执行 TClientDataSet
ApplyUpdates
调用时遇到问题。 5
我做了一个小测试应用程序。
组件:TDBGrid -> TDataSource -> TClientDataSet -> TDataSetProvider -> TSDQuery -> TSDDatabase
查询是 select * from tt_plan_task
,提供者有 UpdateMode=upWhereAll
,客户端数据集有 IndexFieldName=tt_plan_task_id
。
我们修改字段 tt_plan_task.tt_prj
.
的一个值
当执行ApplyUpdates(0)
时,代码追踪到TSQLResolver.InternalDoUpdate
in DataSnap.Provider
(for UpdateKind=ukModify
).
在那里,生成的 SQL 和参数看起来符合预期。
然后代码跳转到
procedure TSQLResolver.DoExecSQL(SQL: TStringList; Params: TParams);
var
RowsAffected: Integer;
begin
RowsAffected := (Provider.DataSet as IProviderSupportNG).PSExecuteStatement(SQL.Text, Params);
此语句崩溃并出现错误 SQL not supported
(Data.DBConsts 中的 SProviderSQLNotSupported)
但由于这是一个接口,我无法进一步追踪。
我不知道如何从这里着手解决这个问题。 有什么建议如何做,或者会发生什么?
附加信息:
- 通过 TSDQuery 组件执行 SELECT 和(参数化)UPDATE 查询工作正常。
- 将客户端数据集与所有 FireDac 组件 (
TDBGrid -> TDataSource -> TClientDataSet -> TDataSetProvider -> TFDQuery -> TDFConnection
)(不同的测试应用程序)一起使用效果很好
- 这是一个使用数据库方言 3 的 FireBird 数据库
- FireBird 版本为 2.5.3.26778
- Delphi 10 没有安装 Interbase 组件
- 这一切都在一个 Win7 VM 中,其中 Delphi XE2 已被删除(所有内容 'Borland/CodeGear/Embarcadero' 已清除),并安装了 Seattle。我的同事在干净的 Win10 VM 中安装干净的 Seattle 时遇到了类似的问题。
- 应用程序和 FireBird 是 Win32,操作系统是 Win64
[注意:自我回答这个问题是因为我花了很长时间才弄明白。可能对其他人有帮助.]
当 Googling the error message I stumbled upon this post SProviderSQLNotSupported on DOA with Delphi XE3 用户遇到与 Oracle Direct Access 类似的问题时。
它建议:
1) 以牺牲性能为代价设置TDataSetProvider.ResolveToDataSet=true
。这适用于测试应用程序。
2) PSExecuteStatement
可能未在第 3 方软件中实现(覆盖),其来自 data.db
的基本过程开始:
function TDataSet.PSExecuteStatement(const ASQL: string; AParams: TParams): Integer;
begin
Result := 0;
DatabaseError(SProviderSQLNotSupported, Self);
end;
第二种情况就是这样。 SQLDirect 代码确实有 TSDDataSet 方法的覆盖
function PSExecuteStatement(const ASQL: string; AParams: TParams; {$IFDEF SD_CLR} var ResultSet: TObject {$ELSE} {$IFDEF SD_VCL17} var ResultSet: TDataSet {$ELSE} ResultSet: TSDPtr = nil {$ENDIF} {$ENDIF}): Integer; overload; override;
在 Delphi 西雅图 resolves/compiles 下覆盖:
function PSExecuteStatement(const ASQL: string; AParams: TParams; var ResultSet: TDataSet): Integer; overload; override;
但是
有 none
function TDataSet.PSExecuteStatement(const ASQL: string; AParams: TParams): Integer;
解决方法是加一个:
在SDEngine.pas中TSDDateSet的保护方法中,更新如下:
function PSExecuteStatement(const ASQL: string; AParams: TParams): Integer; overload; override; // New override
function PSExecuteStatement(const ASQL: string; AParams: TParams; {$IFDEF SD_CLR} var ResultSet: TObject {$ELSE} {$IFDEF SD_VCL17} var ResultSet: TDataSet {$ELSE} ResultSet: TSDPtr = nil {$ENDIF} {$ENDIF}): Integer; overload; override;
实施:
function TSDDataSet.PSExecuteStatement(const ASQL: string; AParams: TParams): Integer; // JD 20-4-2016
var
ds: TDataSet;
begin
ds := nil;
Result := InternalPSExecuteStatement( ASQL, AParams, false, ds );
end;
我在 TAsaDataSet + TDataSetProvider + TClientDataSet
从 Delphi 2009 年迁移到西雅图 10 时遇到了类似的问题
我们解决了更改一些属性的问题:
AsaDataSet.readyOnly := true;
DataSetProvider.ResolveToDataSet := True;
然后在我们代码的某个点,我们确保 TAsaDataSet 能够 table。
TAsaDataSet .Close;
TAsaDataSet .Session := DmConection.AsaConnection;
TAsaDataSet .SQL.Text := 'SELECT * FROM dba.table_name';
TAsaDataSet .Open;
我们还注意到从 2009 年到西雅图的方法签名 OnGetTableName
来自:
(Sender: TObject; DataSet: TDataSet; var TableName: WideString);
至:
(Sender: TObject; DataSet: TDataSet; var TableName: string);
希望对你有所帮助。
从 DelphiXE2 更新到 Delphi Seattle 10 Update 1 后,我们在使用 SQLDirect components 版本 6.4 时执行 TClientDataSet
ApplyUpdates
调用时遇到问题。 5
我做了一个小测试应用程序。
组件:TDBGrid -> TDataSource -> TClientDataSet -> TDataSetProvider -> TSDQuery -> TSDDatabase
查询是 select * from tt_plan_task
,提供者有 UpdateMode=upWhereAll
,客户端数据集有 IndexFieldName=tt_plan_task_id
。
我们修改字段 tt_plan_task.tt_prj
.
当执行ApplyUpdates(0)
时,代码追踪到TSQLResolver.InternalDoUpdate
in DataSnap.Provider
(for UpdateKind=ukModify
).
在那里,生成的 SQL 和参数看起来符合预期。
然后代码跳转到
procedure TSQLResolver.DoExecSQL(SQL: TStringList; Params: TParams);
var
RowsAffected: Integer;
begin
RowsAffected := (Provider.DataSet as IProviderSupportNG).PSExecuteStatement(SQL.Text, Params);
此语句崩溃并出现错误 SQL not supported
(Data.DBConsts 中的 SProviderSQLNotSupported)
但由于这是一个接口,我无法进一步追踪。
我不知道如何从这里着手解决这个问题。 有什么建议如何做,或者会发生什么?
附加信息:
- 通过 TSDQuery 组件执行 SELECT 和(参数化)UPDATE 查询工作正常。
- 将客户端数据集与所有 FireDac 组件 (
TDBGrid -> TDataSource -> TClientDataSet -> TDataSetProvider -> TFDQuery -> TDFConnection
)(不同的测试应用程序)一起使用效果很好 - 这是一个使用数据库方言 3 的 FireBird 数据库
- FireBird 版本为 2.5.3.26778
- Delphi 10 没有安装 Interbase 组件
- 这一切都在一个 Win7 VM 中,其中 Delphi XE2 已被删除(所有内容 'Borland/CodeGear/Embarcadero' 已清除),并安装了 Seattle。我的同事在干净的 Win10 VM 中安装干净的 Seattle 时遇到了类似的问题。
- 应用程序和 FireBird 是 Win32,操作系统是 Win64
[注意:自我回答这个问题是因为我花了很长时间才弄明白。可能对其他人有帮助.]
当 Googling the error message I stumbled upon this post SProviderSQLNotSupported on DOA with Delphi XE3 用户遇到与 Oracle Direct Access 类似的问题时。
它建议:
1) 以牺牲性能为代价设置TDataSetProvider.ResolveToDataSet=true
。这适用于测试应用程序。
2) PSExecuteStatement
可能未在第 3 方软件中实现(覆盖),其来自 data.db
的基本过程开始:
function TDataSet.PSExecuteStatement(const ASQL: string; AParams: TParams): Integer;
begin
Result := 0;
DatabaseError(SProviderSQLNotSupported, Self);
end;
第二种情况就是这样。 SQLDirect 代码确实有 TSDDataSet 方法的覆盖
function PSExecuteStatement(const ASQL: string; AParams: TParams; {$IFDEF SD_CLR} var ResultSet: TObject {$ELSE} {$IFDEF SD_VCL17} var ResultSet: TDataSet {$ELSE} ResultSet: TSDPtr = nil {$ENDIF} {$ENDIF}): Integer; overload; override;
在 Delphi 西雅图 resolves/compiles 下覆盖:
function PSExecuteStatement(const ASQL: string; AParams: TParams; var ResultSet: TDataSet): Integer; overload; override;
但是
有 nonefunction TDataSet.PSExecuteStatement(const ASQL: string; AParams: TParams): Integer;
解决方法是加一个:
在SDEngine.pas中TSDDateSet的保护方法中,更新如下:
function PSExecuteStatement(const ASQL: string; AParams: TParams): Integer; overload; override; // New override
function PSExecuteStatement(const ASQL: string; AParams: TParams; {$IFDEF SD_CLR} var ResultSet: TObject {$ELSE} {$IFDEF SD_VCL17} var ResultSet: TDataSet {$ELSE} ResultSet: TSDPtr = nil {$ENDIF} {$ENDIF}): Integer; overload; override;
实施:
function TSDDataSet.PSExecuteStatement(const ASQL: string; AParams: TParams): Integer; // JD 20-4-2016
var
ds: TDataSet;
begin
ds := nil;
Result := InternalPSExecuteStatement( ASQL, AParams, false, ds );
end;
我在 TAsaDataSet + TDataSetProvider + TClientDataSet
从 Delphi 2009 年迁移到西雅图 10 时遇到了类似的问题
我们解决了更改一些属性的问题:
AsaDataSet.readyOnly := true;
DataSetProvider.ResolveToDataSet := True;
然后在我们代码的某个点,我们确保 TAsaDataSet 能够 table。
TAsaDataSet .Close;
TAsaDataSet .Session := DmConection.AsaConnection;
TAsaDataSet .SQL.Text := 'SELECT * FROM dba.table_name';
TAsaDataSet .Open;
我们还注意到从 2009 年到西雅图的方法签名 OnGetTableName
来自:
(Sender: TObject; DataSet: TDataSet; var TableName: WideString);
至:
(Sender: TObject; DataSet: TDataSet; var TableName: string);
希望对你有所帮助。