SQL语句GET DIAGNOSTICS
的{{3}}表示您可以请求将诊断数据放置在特定的变量中,并列出相关的变量名称和类型。文章documentation和here展示了如何在RPG程序的上下文中使用此SQL语句。
从DB2获得的一些结果似乎与文档和文章所说的不匹配。我使用的是IBM i版本7.3。
我正在查看从SQL用户定义的表函数(UDTF)返回的诊断数据。如果使用子句“ ALL”,则可以获得包含所有值的字符串:
COMMAND_FUNCTION=FETCH;
COMMAND_FUNCTION_CODE=+45;
DB2_NUMBER_CONNECTIONS=+1;
MORE=N;
NUMBER=+1;
CONDITION_NUMBER=+1;
DB2_MESSAGE_ID=SQL0443;
DB2_MESSAGE_ID1=CPF503E;
DB2_MODULE_DETECTING_ERROR=QSQFETCH;
DB2_ORDINAL_TOKEN_1=*N.*N;
DB2_ORDINAL_TOKEN_2=DUMMYUDTF;
DB2_ORDINAL_TOKEN_3=*******.DUMMYUDTF;
DB2_ORDINAL_TOKEN_4=Parameter '2' cannot be null.;
DB2_RETURNED_SQLCODE=-443;
DB2_TOKEN_COUNT=+4;
DB2_TOKEN_STRING=*N.*NDUMMYUDTFDUMMYUDTFParameter '2' cannot be null.;
MESSAGE_LENGTH=Parameter '2' cannot be null.;
MESSAGE_OCTET_LENGTH=Parameter '2' cannot be null.;
MESSAGE_TEXT=Parameter '2' cannot be null.;
RETURNED_SQLSTATE=90002;
ROUTINE_NAME=DUMMYUDTF;
ROUTINE_SCHEMA=QGPL;
SERVER_NAME=******;
SPECIFIC_NAME=DUMMYUDTF;
DB2_SQLERRD_SET=Y;
DB2_SQLERRD1=-168758331;
CONNECTION_NAME=******;
DB2_AUTHORIZATION_ID=********;
DB2_CONNECTION_METHOD=D;
DB2_CONNECTION_NUMBER=+1;
DB2_CONNECTION_STATE=+1;
DB2_CONNECTION_TYPE=+1;
DB2_PRODUCT_ID=QSQ07030;
DB2_SERVER_CLASS_NAME=DB2 for i;
DB2_SERVER_NAME=******;
文档指出,字段MESSAGE_LENGTH
和MESSAGE_OCTET_LENGTH
应该是整数。如您所见,它们都是VARCHAR。如果我编写将这些变量定义为整数的代码,则会在作业日志中得到转义消息:Scalar operand does not have attributes required by instruction.
和两个诊断(严重性为50 SQL system error.
)以及SQL服务转储QSQSVCDMP
。另一个怪异之处是变量DB2_MESSAGE_ID2
看起来好像没有实现,并且会使程序在SQL为其分配的行上崩溃。
相反,如果我在内置函数上使用GET DIAGNOSTICS
,则数据类型都与文档中所说的相匹配,并且所有变量似乎都可用:
COMMAND_FUNCTION=SELECT;
COMMAND_FUNCTION_CODE=+65;
DB2_NUMBER_CONNECTIONS=+1;
MORE=N;
NUMBER=+1;
CLASS_ORIGIN=ISO9075;
CONDITION_NUMBER=+1;
DB2_MESSAGE_ID=SQL0138;
DB2_MESSAGE_ID1=CPF4278;
DB2_MESSAGE_ID2=CPD4317;
DB2_MODULE_DETECTING_ERROR=QSQOPEN;
DB2_ORDINAL_TOKEN_1=*N;
DB2_RETURNED_SQLCODE=-138;
DB2_TOKEN_COUNT=+1;
DB2_TOKEN_STRING=*N;
MESSAGE_LENGTH=+47;
MESSAGE_OCTET_LENGTH=+47;
MESSAGE_TEXT=Argument *N of substringing function not valid.;
RETURNED_SQLSTATE=22011;
ROUTINE_CATALOG=******;
SERVER_NAME=******;
SUBCLASS_ORIGIN=ISO9075;
DB2_SQLERRD_SET=Y;
DB2_SQLERRD1=-185403400;
DB2_SQLERRD2=-185339401;
CONNECTION_NAME=******;
DB2_AUTHORIZATION_ID=********;
DB2_CONNECTION_METHOD=D;
DB2_CONNECTION_NUMBER=+1;
DB2_CONNECTION_STATE=+1;
DB2_CONNECTION_TYPE=+1;
DB2_PRODUCT_ID=QSQ07030;
DB2_SERVER_CLASS_NAME=DB2 for i;
DB2_SERVER_NAME=******;
这是应该报告给IBM的错误吗?如何做到这一点?我制作了一个UDTF和一个调用RPGLE程序来演示该问题。如果有人要验证我的发现,则该代码在下面。您可能必须在RPGLE程序TSTDIAUDTF
中注释掉几行,因为您没有我的错误消息服务程序ERRFUNC
。
DUMMYUDTF
是外部用户定义的SQL函数,具有SQL和RPGLE中的代码。 TSTDIAUDTF
是我用来测试GET DIAGNOSTICS
SQL语句行为的RPGLE程序。
这似乎与过去报告的某些错误(例如here)大致相似,但是细节有所不同。
编辑: 纠正了早期的粘贴操作带来的代码格式错误。
DUMMYUDTF,TXT
-- Build function by calling:
-- RUNSQLSTM SRCFILE(*******/QTXTSRC) SRCMBR(DUMMYUDTF) COMMIT(*NONE)
CREATE OR REPLACE FUNCTION DummyUDTF(
parm1 NUMERIC(7,0),
parm2 VARCHAR(7)
parm3 VARCHAR(4))
RETURNS TABLE (Out1 NUMERIC(7,0),
Out2 VARCHAR(13),
Out3 VARCHAR(4),
Out4 NUMERIC(7,2),
Out5 NUMERIC(5,4))
LANGUAGE RPGLE
DETERMINISTIC
READS SQL DATA
CALLED ON NULL INPUT
DISALLOW PARALLEL
NOT FENCED
EXTERNAL NAME '******/DUMMYUDTF'
PARAMETER STYLE DB2SQL;
DUMMYUDTF,SQLRPGLE
/IF DEFINED (*CRTBNDRPG)
H DFTACTGRP(*NO) ACTGRP('DUMMYUDTF')
/ENDIF
H DEBUG
H ALWNULL(*USRCTL) OPTION(*NoDebugIO) EXTBININT(*YES)
D DUMMYUDTF PI
* Input Parameters
D parm1 7S 0
D parm2 7A VARYING
D parm3 4A VARYING
* Columns to be returned
D out1 7S 0
D out2 13A VARYING
D out3 4A VARYING
D out4 7S 2
D out5 5S 4
* NULL Indicators for all input and output parameters
D parm1_n 5I 0
D parm2_n 5I 0
D parm3_n 5I 0
D out1_n 5I 0
D out2_n 5I 0
D out3_n 5I 0
D out4_n 5I 0
D out5_n 5I 0
* SQL Function Parameters
D OutputSQLState 5A
D FunctionName 517A VARYING CONST
D SpecificName 128A VARYING CONST
D MessageText 1000A VARYING
D CallType 10I 0
* Locals
D CallTypeFirst C CONST(-2)
D CallTypeOpen C CONST(-1)
D CallTypeFetch C CONST(0)
D CallTypeClose C CONST(1)
D CallTypeFinal C CONST(2)
D out DS TEMPLATE QUALIFIED
D out1 7S 0
D out2 13A VARYING
D out3 4A VARYING
D out4 7S 2
D out5 5S 4
D results DS DIM(99) LIKEDS(out)
D index S 2S 0
D count S 2S 0
D var4 S 7S 2
D var5 S 5S 4
MONITOR;
OutputSQLState = *ZEROS; // Initialize Output Parameters
CLEAR MessageText;
SELECT;
WHEN CallType = CallTypeOpen;
IF parm1_n = -1;
MessageText = BuildNullError('1');
RETURN;
ENDIF;
IF parm2_n = -1;
MessageText = BuildNullError('2');
RETURN;
ENDIF;
IF parm3_n = -1;
MessageText = BuildNullError('3');
RETURN;
ENDIF;
IF parm1 < 1;
OutputSQLState = '90002';
MessageText = 'Parameter 1 must be a number greater than 0.';
RETURN;
ENDIF;
EXSR BuildDummyData;
WHEN CallType = CallTypeFetch;
index += 1;
IF index > count;
OutputSQLState = '02000';
RETURN;
ENDIF;
out1 = results(index).out1;
out2 = results(index).out2;
out3 = results(index).out3;
out4 = results(index).out4;
out5 = results(index).out5;
WHEN CallType = CallTypeClose;
*INLR = *ON;
ENDSL;
ON-ERROR;
DUMP; // This dump ends up in the output queue QUSRSYS\QEZDEBUG
OutputSQLState = '90001';
MessageText = 'Error occurred in RPG program ''DUMMYUDTF''. ' +
'See program dump for additional details.';
ENDMON;
RETURN;
********************************************************************
BEGSR BuildDummyData;
EXEC SQL SELECT 350.05, .65
INTO :var4, :var5
FROM SYSIBM.SYSDUMMY1;
SaveToResults(parm1 : parm2 : parm3 : var4 : var5);
SaveToResults(219 : 'ABCDEF' : 'ZYXW' : 20.1 : .65);
SaveToResults(438 : 'GHIJKLMNOP' : 'ZYXW' : 2.95 : 0);
ENDSR;
********************************************************************
P BuildNullError...
P B
D PI 1000A VARYING
D parmName 20A VALUE VARYING
OutputSQLState = '90002';
RETURN 'Parameter ''' + parmName + ''' cannot be null.';
P E
********************************************************************
P SaveToResults...
P B
D PI
D loc1 7S 0 VALUE
D loc2 13A VALUE VARYING
D loc3 4A VALUE VARYING
D loc4 7S 2 VALUE
D loc5 5S 4 VALUE
IF count = 99;
OutputSQLState = '10Z01';
MessageText = 'SQL warning in DUMMYUDTF +
More than 99 parts generated.';
ELSE;
count += 1;
results(count).out1 = loc1;
results(count).out2 = loc2;
results(count).out3 = loc3;
results(count).out4 = loc4;
results(count).out5 = loc5;
ENDIF;
P E
TSTDIAUDTF,SQLRPGLE
H DEBUG(*YES)
H MAIN(Main)
H DFTACTGRP(*NO)
H BNDDIR('ERRFUNC')
/copy QRPGLESRC,ERRFUNCPR
D Message DS LIKEDS(ErrorMsg)
D success S 3I 0
D failure S 3I 0
D diagAll S 32740A VARYING
D displayText S 52A
D dummyItem DS INZ
D out1 7S 0
D out2 13A
D out3 4A
D out4 7S 2
D out5 5S 4
D SQLDiagData DS INZ
D MessageID 10A
D MessageID1 7A
D MessageID2 7A
D MessageLength 5I 0
D MessageText 32740A VARYING
D otherType 32740A VARYING
D ReturnedSQLCode...
D 5A
D ReturnedSQLState...
D 5A
D RowCount 10I 0
P Main B
DSPLY 'Beginning of test';
TestDummyUDTF();
TestDiagnoticsFromUDTF();
TestDiagnoticsFromBIF();
DSPLY ('Successful tests: ' + %char(success));
DSPLY ('Failed tests: ' + %char(failure));
RETURN;
BEGSR *PSSR;
DUMP;
DSPLY 'Unexpected error while running tests.';
GetErrorMsg(Message);
DSPLY ('Message.MsgId: ' + Message.MsgId);
DSPLY (%subst(Message.MsgText:1:52));
RETURN;
ENDSR;
P E
********************************************************************
P TestDiagnoticsFromBIF...
P B
D text S 10A
DSPLY 'Causing error from SUBSTR to read diagnostics.';
EXEC SQL SELECT SUBSTR('ABC', 1, -1) INTO :text
FROM SYSIBM.SYSDUMMY1;
IF SQLSTATE = '00000';
failure +=1;
DSPLY 'Test failed. Data returned, no error.';
ELSEIF SQLSTATE = '02000';
failure +=1;
DSPLY 'Test failed. No error returned.';
ELSE;
ReadSQLDiagnosticsAll();
IF diagAll <> '';
success += 1;
DisplayTextWindow(diagAll : 'CPF9898':'QCPFMSG');
DSPLY 'GET DIAGNOSTICS ALL succeeded.';
ELSE;
failure +=1;
DSPLY 'GET DIAGNOSTICS ALL failed.';
ENDIF;
ReadSQLDiagnosticsAllCondition();
IF diagAll <> '';
success += 1;
DisplayTextWindow(diagAll : 'CPF9898':'QCPFMSG');
DSPLY 'GET DIAGNOSTICS ALL CONDITION succeeded.';
ELSE;
failure +=1;
DSPLY 'GET DIAGNOSTICS ALL CONDITION failed.';
ENDIF;
ReadSQLDiagnostics();
IF ReturnedSQLCode <> '-138 ' OR
ReturnedSQLState <> '22011';
failure +=1;
DSPLY 'Test failed. Unexpected diagnostic.';
displayText = 'SQLCODE ' + ReturnedSQLCode +
' SQLSTATE ' + ReturnedSQLState;
DSPLY displayText;
ELSE;
displayText = MessageText;
DSPLY displayText;
displayText = 'MESSAGE_LENGTH ' + %char(MessageLength);
DSPLY displayText;
displayText = 'DB2_MESSAGE_ID ' + MessageID +
' DB2_MESSAGE_ID1 ' + MessageID1;
DSPLY displayText;
displayText = 'DB2_MESSAGE_ID2 ' + MessageID2;
DSPLY displayText;
IF MessageText <> '';
success += 1;
DSPLY 'GET DIAGNOSTICS MessageText succeeded.';
ELSE;
failure +=1;
DSPLY 'GET DIAGNOSTICS MessageText failed.';
ENDIF;
ENDIF;
ENDIF;
P E
********************************************************************
P TestDiagnoticsFromUDTF...
P B
D var2 S 7A
D var2_n S 5I 0
var2_n = -1;
DSPLY 'Causing error from DummyUDTF to read diagnostics.';
EXEC SQL DECLARE CUR_DIAG_UDTF CURSOR FOR (
SELECT ITEMS.*
FROM TABLE (QGPL.DummyUDTF(22, :var2 :var2_n, 'ZZ')) AS ITEMS
);
EXEC SQL OPEN CUR_DIAG_UDTF;
DOW 1=1;
EXEC SQL FETCH CUR_DIAG_UDTF INTO :dummyItem;
IF SQLSTATE = '00000';
failure +=1;
DSPLY 'Test failed. Records returned, no error.';
LEAVE;
ELSEIF SQLSTATE = '02000';
failure +=1;
DSPLY 'Test failed. No error returned.';
LEAVE;
ELSE;
ReadSQLDiagnosticsAll();
IF diagAll <> '';
success += 1;
DisplayTextWindow(diagAll : 'CPF9898':'QCPFMSG');
DSPLY 'GET DIAGNOSTICS ALL succeeded.';
ELSE;
failure +=1;
DSPLY 'GET DIAGNOSTICS ALL failed.';
ENDIF;
ReadSQLDiagnosticsAllCondition();
IF diagAll <> '';
success += 1;
DisplayTextWindow(diagAll : 'CPF9898':'QCPFMSG');
DSPLY 'GET DIAGNOSTICS ALL CONDITION succeeded.';
ELSE;
failure +=1;
DSPLY 'GET DIAGNOSTICS ALL CONDITION failed.';
ENDIF;
ReadSQLDiagnosticsUDTF();
IF ReturnedSQLCode <> '-443 ' OR
ReturnedSQLState <> '90002';
failure +=1;
DSPLY 'Test failed. Unexpected diagnostic.';
displayText = 'SQLCODE ' + ReturnedSQLCode +
' SQLSTATE ' + ReturnedSQLState;
DSPLY displayText;
ELSE;
* DSPLY MessageID;
* DSPLY %char(MessageLength);
displayText = MessageText;
DSPLY displayText;
displayText = 'MESSAGE_LENGTH ' + OtherType;
DSPLY displayText;
displayText = 'DB2_MESSAGE_ID ' + MessageID +
' DB2_MESSAGE_ID1 ' + MessageID1;
DSPLY displayText;
IF MessageText <> '';
success += 1;
DSPLY 'GET DIAGNOSTICS MessageText succeeded.';
ELSE;
failure +=1;
DSPLY 'GET DIAGNOSTICS MessageText failed.';
ENDIF;
ENDIF;
LEAVE;
ENDIF;
ENDDO;
EXEC SQL CLOSE CUR_DIAG_UDTF;
P E
********************************************************************
P TestDummyUDTF...
P B
D expected DS DIM(3) LIKEDS(dummyItem)
D index S 3I 0
expected(1).out1 = 22;
expected(1).out2 = 'AAAA';
expected(1).out3 = 'ZZ';
expected(1).out4 = 350.05;
expected(1).out5 = .65;
expected(2).out1 = 219;
expected(2).out2 = 'ABCDEF';
expected(2).out3 = 'ZYXW';
expected(2).out4 = 20.1;
expected(2).out5 = .65;
expected(3).out1 = 438;
expected(3).out2 = 'GHIJKLMNOP';
expected(3).out3 = 'ZYXW';
expected(3).out4 = 2.95;
expected(3).out5 = 0;
DSPLY 'Running test on DummyUDTF, success expected.';
EXEC SQL DECLARE CUR_UDTF CURSOR FOR (
SELECT ITEMS.*
FROM TABLE (QGPL.DummyUDTF(22, 'AAAA', 'ZZ')) AS ITEMS
);
EXEC SQL OPEN CUR_UDTF;
DOW 1=1;
EXEC SQL FETCH CUR_UDTF INTO :dummyItem;
IF SQLSTATE = '00000';
index += 1;
IF out1 <> expected(index).out1 OR
out2 <> expected(index).out2 OR
out3 <> expected(index).out3 OR
out4 <> expected(index).out4 OR
out5 <> expected(index).out5;
failure +=1;
DSPLY 'Test failed. Data mismatch from UDTF.';
ELSE;
success += 1;
DSPLY 'Test succeeded.';
ENDIF;
LEAVE;
ELSEIF SQLSTATE = '02000';
IF index = 0;
failure +=1;
DSPLY 'Test failed. No records returned.';
ENDIF;
LEAVE;
ELSE;
failure +=1;
DSPLY ('Test failed. SQLSTATE ' + SQLSTATE);
// ReadSQLDiagnostics();
LEAVE;
ENDIF;
ENDDO;
EXEC SQL CLOSE CUR_UDTF;
RETURN;
P E
**************************************************************************
P ReadSQLDiagnostics...
P B
D PI
D condition# 5I 0 VALUE OPTIONS(*NOPASS)
IF %parms = 0 OR condition# < 1;
condition# = 1;
ENDIF;
EXEC SQL GET DIAGNOSTICS CONDITION :condition#
:SQLDiagData.ReturnedSQLCode = DB2_RETURNED_SQLCODE,
:SQLDiagData.ReturnedSQLState = RETURNED_SQLSTATE,
:SQLDiagData.MessageText = MESSAGE_TEXT,
:SQLDiagData.MessageLength = MESSAGE_LENGTH,
:SQLDiagData.MessageID = DB2_MESSAGE_ID,
:SQLDiagData.MessageID1 = DB2_MESSAGE_ID1,
:SQLDiagData.MessageID2 = DB2_MESSAGE_ID2;
RETURN;
P E
**************************************************************************
P ReadSQLDiagnosticsUDTF...
P B
D PI
D condition# 5I 0 VALUE OPTIONS(*NOPASS)
IF %parms = 0 OR condition# < 1;
condition# = 1;
ENDIF;
EXEC SQL GET DIAGNOSTICS CONDITION :condition#
:SQLDiagData.ReturnedSQLCode = DB2_RETURNED_SQLCODE,
:SQLDiagData.ReturnedSQLState = RETURNED_SQLSTATE,
:SQLDiagData.MessageText = MESSAGE_TEXT,
:SQLDiagData.otherType = MESSAGE_LENGTH,
:SQLDiagData.MessageID = DB2_MESSAGE_ID,
:SQLDiagData.MessageID1 = DB2_MESSAGE_ID1;
// :SQLDiagData.MessageLength = MESSAGE_LENGTH,
// :SQLDiagData.MessageID = DB2_MESSAGE_ID;
RETURN;
P E
************************4*************************************************
P ReadSQLDiagnosticsAll...
P B
EXEC SQL GET DIAGNOSTICS :diagAll = ALL;
RETURN;
P E
**************************************************************************
P ReadSQLDiagnosticsAllCondition...
P B
D PI
D condition# 5I 0 VALUE OPTIONS(*NOPASS)
IF %parms = 0 OR condition# < 1;
condition# = 1;
ENDIF;
EXEC SQL GET DIAGNOSTICS :diagAll = ALL CONDITION;
RETURN;
P E
P DisplayTextWindow...
P B Export
D PI
D Text 8192 Const Varying
D MessageId 7 Const
D MessageFile 21 Const
D ErrCode DS
D BytesIn 10I 0 INZ(0)
D BytesOut 10I 0 INZ(0)
DQUILNGTX PR EXTPGM('QUILNGTX')
D MsgText 8192 CONST
D MsgLength 10I 0 CONST
D MessageId 7 CONST
D MessageFile 21 CONST
D dsErrCode LIKE(ErrCode)
QUILNGTX(Text : %Len(Text) :
MessageId : MessageFile : ErrCode);
P E
答案 0 :(得分:1)
是的,看起来可能是一个错误...或者与您链接的PTF ...在使用外部UDTF时可能是GET DIAGNOSTICS
的限制。
我在7.2上看到了同样的事情。
您处于什么PTF级别?如果不是最新版本,IBM将要求您了解最新信息。
您可以在此处报告问题:https://www-946.ibm.com/support/servicerequest/Home.action
IBM可能会要求复制代码。您可能希望将示例缩减到最低限度以进行重现。实际上,最好在下次将其发布到stackoverflow之前这样做。
作为示例,调用UDTF来查看问题时,这里需要做的所有事情:
**free
ctl-opt actgrp(*NEW) main(mainline) cvtopt(*NOVARCHAR) debug(*yes);
dcl-pr mainline extpgm('TESTRPGLE');
end-pr;
dcl-proc mainline;
dcl-s diagAll varchar(32740);
dcl-ds dummyItem qualified;
out1 zoned(7);
out2 varchar(13);
out3 varchar(4);
out4 zoned(7:2);
out5 zoned(5:4);
end-ds;
dcl-s nullArr int(5) dim(5);
exec sql
declare C1 cursor for (
SELECT ITEMS.*
FROM TABLE (DummyUDTF(22, cast(null as varchar(7)), 'ZZ')) AS ITEMS
);
exec sql
open C1;
//I expected SQLSTATE to be 90002 here, but it's not
if sqlstate <> *ZEROS;
exec sql
get diagnostics :diagAll = ALL;
dump;
return;
endif;
exec sql
fetch C1 into :dummyItem :nullArr;
//here's where the SQLSTATE of 90002 is returned.
if sqlstate <> *ZEROS;
exec sql
get diagnostics :diagAll = ALL;
dump;
return;
endif;
return;
end-proc;
边注:开始使用完全免费的格式;)