EUpdateError -2147217900 .

来源:互联网 发布:多线程并发编程 编辑:程序博客网 时间:2024/04/27 13:25

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

 

Delphi XE(delphi7没有这个问题)

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

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

[sql] view plaincopyprint?
  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  


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

[delphi] view plaincopyprint?
  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;  

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

[delphi] view plaincopyprint?
  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;  

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

如何修改呢或避免呢?

(1)改法1,ds.cpp

[cpp] view plaincopyprint?
  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++;  


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

(2)改法2,DB.pas

[delphi] view plaincopyprint?
  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;  


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

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

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

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

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

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

测试后,没有问题了。

 

原创粉丝点击