将Oracle CLOB字段设置为null失败,ORA 22275

将Oracle CLOB字段设置为null失败,ORA 22275,oracle,delphi,clob,firedac,delphi-10.2-tokyo,Oracle,Delphi,Clob,Firedac,Delphi 10.2 Tokyo,我们有一个(!)客户,将Oracle CLOB字段设置为NULL失败,原因是 [FireDAC][Phys][Ora] ORA 22275 - Invalid LOB locator specified 发送到数据库*的查询是 但是,这些声明已经不再需要了 在SQLPLUS中,我可以在我们自己的Oracle 12c数据库上执行这些操作而不会出现问题,因此这似乎无关紧要: update tt_hrs set tt_info='test' where tt_hrs_id=276727; updat

我们有一个(!)客户,将Oracle CLOB字段设置为NULL失败,原因是

[FireDAC][Phys][Ora] ORA 22275 - Invalid LOB locator specified
发送到数据库*的查询是

但是,这些声明已经不再需要了

在SQLPLUS中,我可以在我们自己的Oracle 12c数据库上执行这些操作而不会出现问题,因此这似乎无关紧要:

update tt_hrs set tt_info='test' where tt_hrs_id=276727;
update tt_hrs set tt_info=NULL where tt_hrs_id=276727;
update tt_hrs set tt_info=empty_clob() where tt_hrs_id=276727;
  • 如错误消息所示,我们在Delphi Tokyo 10.2.2中使用FireDAC 32位Windows应用程序
  • 字段上没有NOT NULL约束,它不在索引中, 没有触发器
  • 客户端使用OracleDB12版本1
  • 我们的更新代码是由FireDAC从TClientDataSet生成的 连接到用户编辑的网格
问题

Oracle设置中是否有任何东西可以解释此行为?
也许他们设置了一些“兼容性模式”来支持旧的应用程序或其他东西。。。我对甲骨文不够熟悉

注意:它可能与2字节字符的问题无关

抓住这里的救命稻草


*我们可以记录这一点,因为我们有一个TDataSetProvider子体,它记录在重写的
dobeforexecute
中发送的内容

我们一直无法找到确切的原因,但已经找到了解决办法

受影响的代码都是通过
TClientDataSet
工作的,我们已经使用了一个
TDataSetProvider
子体和一个重写的
dobeforexecute
来记录发送到数据库的实际SQL(用于调试目的)。这在我们的代码中调用了一个日志过程,我们在其中添加了以下内容:

// Force parameter to ftOraClob when NULL:
if TFDQuery(TDataSetProvider(Sender).Dataset).Connection.Params.DriverID = S_FD_OraId then
  for i := 0 to params.count-1 do
    if (params[i].DataType = ftMemo) and (VarIsNull(params[i].Value) or VarIsClear(params[i].Value)) then
       params[i].DataType := ftOraClob;
这将强制
Datasnap.Provider.pas
中的
tsqlsolver.GenUpdateSQL
中的
AddField
子例程遵循以下路径:

else if UseFieldInUpdate(Field) then
begin
  Result := True;
  if (Field.DataType = ftOraClob) and (not InformixLob) then
  begin
    NoParam := True;
    if InObject then
      SQL.Add(string.Format(' %s.%s = EMPTY_CLOB(),', [Alias, QuoteFullName(Field.FullName, PSQLInfo(Tree.Data).QuoteChar),   { Do not localize }
        Field.FullName]))
从而写入
=EMPTY\u CLOB()
而不是
=NULL
,Oracle DB欣然接受这一点

注意:我们测试ftMemo是因为我们有一个映射规则是活动的

with AConnection.FormatOptions.MapRules.Add do 
begin
  SourceDataType := dtWideHMemo;
  TargetDataType := dtMemo;
end;
(见)
如果您没有此功能,则需要测试
ftWideMemo

else if UseFieldInUpdate(Field) then
begin
  Result := True;
  if (Field.DataType = ftOraClob) and (not InformixLob) then
  begin
    NoParam := True;
    if InObject then
      SQL.Add(string.Format(' %s.%s = EMPTY_CLOB(),', [Alias, QuoteFullName(Field.FullName, PSQLInfo(Tree.Data).QuoteChar),   { Do not localize }
        Field.FullName]))
with AConnection.FormatOptions.MapRules.Add do 
begin
  SourceDataType := dtWideHMemo;
  TargetDataType := dtMemo;
end;