EUpdateError -2147217900 .

http://blog.csdn.net/acrodelphi/article/details/6934815

 

Delphi XE(delphi7没有这个问题)

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

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

  1. ALTER TRIGGER [dbo].[csMachinesCategories_Delete]  
  2.    ON  [dbo].[csMachinesCategories]  
  3.    AFTER DELETE  
  4. AS   
  5. BEGIN  
  6.     SET NOCOUNT ON;  
  7.     if exists(select * from csMachinesSeries ,deleted as d   
  8.               where csMachinesSeries.CategoryOID=d.CategoryOID)  
  9.     begin  
  10.       raiserror('Current machine category is using by machine series,can`t delete!',11,1)   
  11.       rollback  
  12.     end  
  13.       
  14.     delete s from csMachinesCategoriesSpecs as s,deleted as d  
  15.     where s.CategoryOID=d.CategoryOID  
  16. END  
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

  1. procedure TUpdateTree.InitErrorPacket(E: EUpdateError; Response: TResolverResponse);  
  2. var  
  3.   TrueRecNo: LongWord;  
  4. begin  
  5.   with ErrorDS do  
  6.   begin  
  7.     if Assigned(Parent) then Parent.InitErrorPacket(nil, rrSkip);  
  8.     Self.Delta.UpdateCursorPos;  
  9.     Self.Delta.DSCursor.GetRecordNumber(TrueRecNo);  
  10.     if not Locate('ERROR_RECORDNO', Integer(TrueRecNo), []) then  
  11.       Append else  
  12.       Edit;  
  13.     if not Assigned(E) then  
  14.     begin  
  15.       if Response = rrSkip then  
  16.       begin  
  17.         SetFields([TrueRecNo]);  
  18.         Post;  
  19.       end else  
  20.         SetFields([TrueRecNo, 0''''00]);  
  21.     end else  
  22.       SetFields([TrueRecNo, Ord(Response)+1, E.Message, ''1, E.ErrorCode]);  
  23.   end;  
  24. end;  
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对其赋值时,检查了范围:

  1. procedure TLongWordField.SetAsInteger(Value: LongInt);  
  2. begin  
  3.   if (FMinValue <> 0or (FMaxValue <> 0then begin  
  4.     if Value < 0 then  
  5.       RangeError(Value, FMinValue, FMaxValue);  
  6.     CheckRange(Value, FMinValue, FMaxValue)  
  7.   end else begin  
  8.     if Value < 0 then  
  9.       RangeError(Value, FMinRange, FMaxRange);  
  10.     CheckRange(Value, FMinRange, FMaxRange);  
  11.   end;  
  12.   SetData(@Value);  
  13. end;  
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

  1. // Set the sixth field for the error code.   
  2. LdStrCpy((pCHAR)pFldDes->szName, szdsERRCODE);  
  3. pFldDes->iFldType = fldUINT32;  
  4. pFldDes->iFldLen = sizeof(UINT32);  
  5. pFldDes++;  
      // 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

  1. procedure TField.AssignValue(const Value: TVarRec);  
  2.   
  3.   procedure Error;  
  4.   begin  
  5.     DatabaseErrorFmt(SFieldValueError, [DisplayName]);  
  6.   end;  
  7.   
  8. begin  
  9.   with Value do  
  10.     case VType of  
  11.       vtInteger:  
  12.         //AsInteger := VInteger;   //delete by wxh   
  13.         asVariant:=VInteger;       //add by wxh   
  14.       vtBoolean:  
  15.         AsBoolean := VBoolean;  
  16.       vtChar:  
  17.         AsAnsiString := VChar;  
  18.       vtWideChar:  
  19.         AsString := VWideChar;  
  20.       vtExtended:  
  21.         AsExtended := VExtended^;  
  22.       vtString:  
  23.         AsString := string(VString^);  
  24.       vtPointer:  
  25.         if VPointer <> nil then Error;  
  26.       vtPChar:  
  27.         AsString := string(VPChar);  
  28.       vtPWideChar:  
  29.         AsString := string(VPWideChar);  
  30.       vtObject:  
  31.         if (VObject = nilor (VObject is TPersistent) then  
  32.           Assign(TPersistent(VObject))  
  33.         else  
  34.           Error;  
  35.       vtAnsiString:  
  36.         AsAnsiString := AnsiString(VAnsiString);  
  37.       vtCurrency:  
  38.         AsCurrency := VCurrency^;  
  39.       vtVariant:  
  40.         if not VarIsClear(VVariant^) then AsVariant := VVariant^;  
  41.       vtWideString:  
  42.         AsWideString := WideString(VWideString);  
  43.       vtInt64:  
  44.         AsVariant := VInt64^;  
  45.       vtUnicodeString:  
  46.         AsString := string(VUnicodeString);  
  47.     else  
  48.       Error;  
  49.     end;  
  50. end;  
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:

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

测试后,没有问题了。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值