7

我又来找你帮忙了。这一次我相信很少有人会回应,因为我将要提到的问题非常特殊。我从 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。

4

1 回答 1

6

与其他人的意见相矛盾,我决定进一步调整并最终弄清楚如何增加“协调”错误消息中的字符数。因为我认为问题出在 midas.dll 中,或者更具体地说是构成 midas dll 的源,因为同一组源可以创建 MidasLib,它不需要 midas dll。为了解决这个问题,我必须安装 Delphi C++ 个性来编译 midas。

在找到错误所在的行后,我发现甚至有一个对 QC 的维修请求(http://qc.embarcadero.com/wc/qcmain.aspx?d=84960),这似乎已被Embarcadero 的工作人员,因为“解决方案”与“推迟到下一个版本”(推迟到下一个版本)一样,但请求是从 2010 年开始的,我使用的是 Delphi XE,在我看来应该有解决方案,但在这里我正在纠正我自己 ;)

问题出在“DSBASE”类的方法“Clone”内部,在第 2133 行(Delphi XE,Update1)的源“ds.cpp”内部。下面是代码块。红线是有问题的线:

// Set the third field for the error string.
LdStrCpy((pCHAR)pFldDes->szName, szdsERRMESSAGE);
pFldDes->iFldType = fldZSTRING;
pFldDes->iUnits1 = 255; // Increased on request.. DBIMAXMSGLEN;
pFldDes++;

请注意,问题线非常有趣。它有一个常数值 255,它限制了错误消息的大小和一个注释“根据请求增加”。另请注意,在评论旁边,有一个常量DBIMAXMSGLEN,我发现并怀疑它是造成问题的原因,但由于没有使用它,我更改了 的值,DBIMAXMSGLEN但错误消息始终没有更改。值得一提的是,有一个分号 (;) 之后DBIMAXMSGLEN让我认为之前(我不知道什么时候)这一行是我修复之后的行:

pFldDes->iUnits1 = DBIMAXMSGLEN;

就好像有人故意将字段值设置为 255,删除了之前真正动态且看似更正确的实现。执行替换行后,我将值DBIMAXMSGLEN增加到 1024。DBIMAXMSGLEN将“bdetypes.h”声明为定义。更正后的行是这样的:

#define DBIMAXMSGLEN         1024           // Max message len

在“ds.cpp”和“bdetypes.h”中进行这两个更改后,我构建、测试,结果如预期:错误消息在 Reconcile 对话框中完整显示。

如果遇到这个问题想尝试的勇敢者,你需要 MIDAS 的源代码,如果我没记错的话,它是 2010 年的 Delphi 附带的。祝你们好运。

于 2012-01-03T17:59:40.987 回答