我又来找你帮忙了。这一次我相信很少有人会回应,因为我将要提到的问题非常特殊。我从 DataSnap 的世界开始,仍然有一些我不明白我将如何关联这个错误的事情。
我的 Delphi 是 XE(版本 1,Update1)。我正在使用 Postgres,它会在葡萄牙语(巴西葡萄牙语)中生成错误消息,因此错误消息带有重音符号。连接组件是 ZeosLib 包。
我正在使用对话框“协调错误”来显示因应用更新而产生的错误并进行测试,我试图插入一条已经存在的记录,从而违反了唯一键,从而显示了协调错误对话框。
在对话框的备忘录中,出现的消息被截断,即截断。看看这个:
ERRO: duplicar valor da chave viola a restrição de unicidade "uc_usu_va_login"
DETAIL: Chave (va_login)=(admin) já existe.
CONTEXT: comando SQL "INSERT INTO USUARIOS (VA_NOME
,VA_LOGIN
,CH
但实际上应该返回的是这样的:
ERRO: duplicar valor da chave viola a restrição de unicidade "uc_usu_va_login"
DETAIL: Chave (va_login)=(admin) já existe.
CONTEXT: comando SQL "INSERT INTO USUARIOS (VA_NOME
,VA_LOGIN
,CH_SENHA
,VA_EMAIL)
VALUES (pVA_NOME
,pVA_LOGIN
,pCH_SENHA
,pVA_EMAIL)"
PL/pgSQL function "idu_usuarios" line 7 at comando SQL
我在服务器上做了debug,看看是不是ZeosLib的问题,但是发现服务器上生成的错误信息是完整的,证明ZeosLib没有截断信息。一切都是unicode。在我的程序和 ZeosLib 中,所有字符串都是 WideString(默认)。
众所周知,要在服务端抛出,异常是通过DataSnap转发到客户端,而在客户端,TClientDataSet的Reconcile方法验证是否有问题,然后抛出著名的异常EReconcileError,可以在 TClientDataSet 的 OnReconcileError 事件中处理,因此我相信该消息正在被 DataSnap 截断。
在客户端上,我调试 Reconcile 方法 (DBClient.pas) 并在抛出异常之前立即进入 cpp 源代码中的函数,我认为该函数是 midas.dll 库的一部分,更具体地说是 MidasLib.obj,因为我是使用此策略,不必将 DLL 与我的应用程序一起分发。
Check(FDSBase.Reconcile_MD(FReconcileDataSet.FDSBase, FDeltaPacket, VarToDataPacket(Results), Integer(Self), RCB));
此调用在 Delphi XE Update1 上的单元 DBClient.pas 的第 1952 行完成。按 F7,调试器进入源 C++ (cpp),所以我相信它在 midaslib.obj 中。我怎么不太懂 C++,我按 Shift-F8 退出当前方法并返回下一条指令,该指令已经在事件 OnReconcileError 中!!因此,截断必须在我提到的函数内、cpp 源代码内、midaslib 内完成。
我的目的是使 Reconcile Error 对话框不仅成为最终用户的工具,而且还支持个人,分别提供错误、详细信息和上下文信息。这对发现问题有很大帮助。
现在的问题是使消息完整显示。有没有人遇到过这种消息被 midas 截断的问题?
还有一点 DSClient.pas 我可以提取错误消息,因为它被传递给异常:
'Erro SQL: ERRO: duplicar valor da chave viola a restrição de unicidade "uc_usu_va_login"'#$A'DETAIL: Chave (va_login)=(admin) já existe.'#$A'CONTEXT: comando SQL "INSERT INTO USUARIOS (VA_NOME'#$A' ,VA_LOGIN'#$A' ,CH'
如果您删除引号并将#$A(1 个字符)替换为一个空格(一个字符),您将看到该字符串正好有 255 个字符!!
我还发现 dspickle.cpp 中的“GetErrorString”使用在 bdetypes.h 中定义为 127(255 的一半)的常量 DBIMAXMSGLEN。就像我们在 Unicode 的世界中一样,将这个值增加到 255 以便每个字符有两个字节不是问题吗?这只是猜测...
我把这个问题悬而未决,因为我缺乏理解 C++ 的知识 :) 谁能帮忙,看看 dspickle.cpp 中的函数实现“GetErrorString”。有这个:
LoadString((HINSTANCE)hDll, iErrCode, pString, DBIMAXMSGLEN)
pString 是错误消息并且 DBIMAXMSGLEN = 127。