EUpdateError -2147217900

Delphi XE(delphi7没有这个问题)

在用ADO+TClientDataSet删除数据时,用DataSetProvider.ApplyUpdates更新,DataSetProvider.ResolveToDataSet要设为false,为true时没有这个现象。

如果sqlserver2008数据库中有个触发器,它检查资料被别的表引用到了,用raiseerror拒绝删除。

ALTER TRIGGER [dbo].[csMachinesCategories_Delete]
   ON  [dbo].[csMachinesCategories]
   AFTER DELETE
AS 
BEGIN
	SET NOCOUNT ON;
    if exists(select * from csMachinesSeries ,deleted as d 
              where csMachinesSeries.CategoryOID=d.CategoryOID)
    begin
      raiserror('Current machine category is using by machine series,can`t delete!',11,1) 
      rollback
    end
    
    delete s from csMachinesCategoriesSpecs as s,deleted as d
    where s.CategoryOID=d.CategoryOID
END


BizServer会产生如下错误:

先是这个:

Project Project6.exe raised exception class EDatabaseError with message 'Unable to find record.  No key specified'.


再出现这个:

Project Project6.exe raised exception class EDatabaseError with message '-2147217900 is not a valid value for field 'ERROR_CODE'. The allowed range is 0 to 4294967295'.

-2147217900的16进制是:FFFFFFFF80040E14,delphi的EUpdateError的ErrorCode数据类型是Integer,看起来是超界了,但-2147217900并没有超过integer的范围,integer的范围是-2147483648..2147483647,那怎么回事呢?

跟踪发现错误点在Provider.pas

procedure TUpdateTree.InitErrorPacket(E: EUpdateError; Response: TResolverResponse);
var
  TrueRecNo: LongWord;
begin
  with ErrorDS do
  begin
    if Assigned(Parent) then Parent.InitErrorPacket(nil, rrSkip);
    Self.Delta.UpdateCursorPos;
    Self.Delta.DSCursor.GetRecordNumber(TrueRecNo);
    if not Locate('ERROR_RECORDNO', Integer(TrueRecNo), []) then
      Append else
      Edit;
    if not Assigned(E) then
    begin
      if Response = rrSkip then
      begin
        SetFields([TrueRecNo]);
        Post;
      end else
        SetFields([TrueRecNo, 0, '', '', 0, 0]);
    end else
      SetFields([TrueRecNo, Ord(Response)+1, E.Message, '', 1, E.ErrorCode]);
  end;
end;

而'ERROR_CODE'字段的类型是TLongWordField,在DB.pas对其赋值时,检查了范围:

procedure TLongWordField.SetAsInteger(Value: LongInt);
begin
  if (FMinValue <> 0) or (FMaxValue <> 0) then begin
    if Value < 0 then
      RangeError(Value, FMinValue, FMaxValue);
    CheckRange(Value, FMinValue, FMaxValue)
  end else begin
    if Value < 0 then
      RangeError(Value, FMinRange, FMaxRange);
    CheckRange(Value, FMinRange, FMaxRange);
  end;
  SetData(@Value);
end;

所以,问题在于,delphi认为ErrorCode应该是LongWord,不应该出现负数,或者说SQLServer是使用int64来表示ErrorCode。

如何修改呢或避免呢?

(1)改法1,ds.cpp

      // Set the sixth field for the error code.
      LdStrCpy((pCHAR)pFldDes->szName, szdsERRCODE);
      pFldDes->iFldType = fldUINT32;
      pFldDes->iFldLen = sizeof(UINT32);
      pFldDes++;


把fldUINT32改成fldINT32,改了编译midas.cbproj,还是不行(使用Midaslib.pas)

(2)改法2,DB.pas

procedure TField.AssignValue(const Value: TVarRec);

  procedure Error;
  begin
    DatabaseErrorFmt(SFieldValueError, [DisplayName]);
  end;

begin
  with Value do
    case VType of
      vtInteger:
        //AsInteger := VInteger;   //delete by wxh
        asVariant:=VInteger;       //add by wxh
      vtBoolean:
        AsBoolean := VBoolean;
      vtChar:
        AsAnsiString := VChar;
      vtWideChar:
        AsString := VWideChar;
      vtExtended:
        AsExtended := VExtended^;
      vtString:
        AsString := string(VString^);
      vtPointer:
        if VPointer <> nil then Error;
      vtPChar:
        AsString := string(VPChar);
      vtPWideChar:
        AsString := string(VPWideChar);
      vtObject:
        if (VObject = nil) or (VObject is TPersistent) then
          Assign(TPersistent(VObject))
        else
          Error;
      vtAnsiString:
        AsAnsiString := AnsiString(VAnsiString);
      vtCurrency:
        AsCurrency := VCurrency^;
      vtVariant:
        if not VarIsClear(VVariant^) then AsVariant := VVariant^;
      vtWideString:
        AsWideString := WideString(VWideString);
      vtInt64:
        AsVariant := VInt64^;
      vtUnicodeString:
        AsString := string(VUnicodeString);
    else
      Error;
    end;
end;


但这种改法对这个问题看起来对了,但其实有很大问题。

向Embarcadero报告,答复这里有Hotfix可以解决:

http://edn.embarcadero.com/article/41312

http://cc.embarcadero.com/item/28247

网速极慢,下载后,看到是修改了Provider.pas的TUpdateTree.InitErrorPacket:

      SetFields([TrueRecNo, Ord(Response)+1, E.Message, '', 1, Variant(LongWord(E.ErrorCode))]);

测试后,没有问题了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火星牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值