正在查找任何OS/400 API封装在用户定义的SQL函数中的外部SQL存储过程中的工作示例
目前有两个问题: 1) 下面的示例使用外部SQL存储过程包装OS/400 API,外部SQL存储过程是SQL用户定义表函数中的进一步包装,它编译和运行时都不会出错,但在传递作业名称(即当前作业)的“*”时,它会为作业信息返回空格和零。任何关于原因的提示都将不胜感激。注意:如果我传递了一个不存在的作业,那么QUSRJOBI api会正确地抛出一个错误,因此代码的行为部分正确。如果我传递了正确的活动工单名称、工单用户和工单编号,则不会发生错误,但仍会返回空格和零。我已经试过用CHAR(85)和VARCHAR(85)作为RECEIVER_变量。接下来,我将尝试对RECEIVER_变量使用二进制(85),但将二进制转换回CHAR和INT返回列可能会很困难 2) 一些OS/400API参数要求使用数据结构,而系统上V7R1上的DB2 SQL尚未直接支持数据结构(即,尚未直接支持结构化类型)。但是,表示可以使用二进制字符串实现,但未提供示例:(.经过广泛搜索,我还没有找到仅使用SQL对象包装OS400 api的示例。如果任何人有任何示例,说明如何仅使用SQL(由CHAR和其他数据类型(特别是INT)混合组成)来形成二进制字符串,请发布一个。api错误代码参数就是一个示例这是通常需要的。我将错误代码相关代码注释掉,因为如果重新激活该代码,它将生成错误CPF3CF1“错误代码参数无效”。如果有人能告诉我错误代码二进制字符串数据结构的形成方式有什么问题,请告诉我。我已经尝试了两个字符(16)和二进制(16)表示错误代码结构。我已经测试了错误代码形成的当前技术,将结果转储到表中,并在十六进制模式下使用DSPPFM查看表结果,使其看起来“二进制(十六进制(提供的错误代码字节))等工作正常。但是,我遗漏了一些东西 我知道有很多使用RPG包装OS/400API的例子,但我只想将这些包装作为SQL代码正在查找任何OS/400 API封装在用户定义的SQL函数中的外部SQL存储过程中的工作示例,sql,api,stored-procedures,db2,ibm-midrange,Sql,Api,Stored Procedures,Db2,Ibm Midrange,目前有两个问题: 1) 下面的示例使用外部SQL存储过程包装OS/400 API,外部SQL存储过程是SQL用户定义表函数中的进一步包装,它编译和运行时都不会出错,但在传递作业名称(即当前作业)的“*”时,它会为作业信息返回空格和零。任何关于原因的提示都将不胜感激。注意:如果我传递了一个不存在的作业,那么QUSRJOBI api会正确地抛出一个错误,因此代码的行为部分正确。如果我传递了正确的活动工单名称、工单用户和工单编号,则不会发生错误,但仍会返回空格和零。我已经试过用CHAR(85)和VAR
create or replace procedure M_GET_JOB_INFORMATION
( out OUT_RECEIVER_VARIABLE char(85)
,in IN_LENGTH_OF_RECEIVER_VARIABLE int
,in IN_FORMAT_NAME char(8)
,in IN_QUALIFIED_JOB_NAME char(26)
,in IN_INTERNAL_JOB_IDENTIFIER char(16)
-- ,inout INOUT_ERROR_CODE binary(16)
)
program type main
external name QSYS/QUSRJOBI
parameter style general
not deterministic
modifies SQL data
specific M_JOBINFO
set option dbgview = *source
,commit = *nc
,closqlcsr = *endmod
,tgtrls = V7R1M0
;
create or replace function M_GET_JOB_INFORMATION_BASIC
( IN_JOB_NAME varchar(10)
,IN_JOB_USER varchar(10)
,IN_JOB_NUMBER varchar(6)
,IN_INTERNAL_JOB_IDENTIFIER varchar(16)
)
returns table( JOB_NAME char(10)
,JOB_USER char(10)
,JOB_NUMBER char(6)
,INTERNAL_JOB_IDENTIFIER char(16)
,JOB_STATUS char(10)
,JOB_TYPE char(1)
,JOB_SUBTYPE char(1)
,RUN_PRIORITY int
,TIME_SLICE int
,DEFAULT_WAIT int
,ELIGIBLE_FOR_PURGE char(10)
)
language SQL
specific M_JOBINFBF
not deterministic
disallow parallel
no external action
modifies SQL data
returns null on null input
not fenced
set option dbgview = *source
,commit = *nc
,closqlcsr = *endmod
,tgtrls = V7R1M0
-- ,output = *PRINT
begin
declare RECEIVER_VARIABLE char(85) default ''; --receives "JOBI0100" format output from API
declare LENGTH_OF_RECEIVER_VARIABLE int default 85; --length of "JOBI0100" Format
declare FORMAT_NAME char(8) default 'JOBI0100'; --basic job information
declare QUALIFIED_JOB_NAME char(26);
declare INTERNAL_JOB_IDENTIFIER char(16);
declare ERROR_CODE binary(16);
--ERROR_CODE "ERRC0100" Format:
declare ERROR_CODE_BYTES_PROVIDED int default 8; --Size of API Error Code data structure passed to API
declare ERROR_CODE_BYTES_RETURNED int default 0; --Number of exception data bytes returned by the API
declare ERROR_CODE_EXCEPTION_ID char(7) default ''; --Exception / error message ID returned by the API
declare ERROR_CODE_RESERVED char(1) default ''; --Reserved bytes
declare ERROR_CODE_EXCEPTION_DATA char(1) default ''; --Exception data returned by the API
if IN_INTERNAL_JOB_IDENTIFIER = '' then
set QUALIFIED_JOB_NAME = char( IN_JOB_NAME, 10 ) || char( IN_JOB_USER, 10 ) || char( IN_JOB_NUMBER, 6 );
set INTERNAL_JOB_IDENTIFIER = '';
else
set QUALIFIED_JOB_NAME = '*INT';
set INTERNAL_JOB_IDENTIFIER = IN_INTERNAL_JOB_IDENTIFIER;
end if;
set ERROR_CODE = binary( hex( ERROR_CODE_BYTES_PROVIDED ) ) ||
binary( hex( ERROR_CODE_BYTES_RETURNED ) ) ||
binary( ERROR_CODE_EXCEPTION_ID ) ||
binary( ERROR_CODE_RESERVED )
-- || binary( ERROR_CODE_EXCEPTION_DATA )
;
call M_GET_JOB_INFORMATION
( RECEIVER_VARIABLE --out
,LENGTH_OF_RECEIVER_VARIABLE --in
,FORMAT_NAME --in
,QUALIFIED_JOB_NAME --in
,INTERNAL_JOB_IDENTIFIER --in
-- ,ERROR_CODE --in/out --Results in error CPF3CF1 "Error code parameter not valid" if code line reactivated
);
return values( char( substr( RECEIVER_VARIABLE, 8, 10 ), 10 ) --JOB_NAME
,char( substr( RECEIVER_VARIABLE, 18, 10 ), 10 ) --JOB_USER
,char( substr( RECEIVER_VARIABLE, 28, 6 ), 6 ) --JOB_NUMBER
,char( substr( RECEIVER_VARIABLE, 28, 16 ), 16 ) --INTERNAL_JOB_IDENTIFIER
,char( substr( RECEIVER_VARIABLE, 50, 10 ), 10 ) --JOB_STATUS
,char( substr( RECEIVER_VARIABLE, 60, 1 ), 1 ) --JOB_TYPE
,char( substr( RECEIVER_VARIABLE, 61, 1 ), 1 ) --JOB_SUBTYPE
,case when substr( RECEIVER_VARIABLE, 64, 4 ) = ''
then 0
else int( substr( RECEIVER_VARIABLE, 64, 4 ) )
end --RUN_PRIORITY
,case when substr( RECEIVER_VARIABLE, 68, 4 ) = ''
then 0
else int( substr( RECEIVER_VARIABLE, 68, 4 ) )
end --TIME_SLICE
,case when substr( RECEIVER_VARIABLE, 72, 10 ) = ''
then 0
else int( substr( RECEIVER_VARIABLE, 72, 4 ) )
end --DEFAULT_WAIT
,char( substr( RECEIVER_VARIABLE, 76, 10 ), 10 ) --ELIGIBLE_FOR_PURGE
)
;
end
;
select * from table( M_GET_JOB_INFORMATION_BASIC( '*', '', '', '' ) ) as JOB_INFO
;
我在I 6.1中使用此函数调用QDBRTVFD API:
CREATE PROCEDURE SQLEXAMPLE.DBRTVFD (
INOUT FD CHAR(1024) ,
IN SZFD INTEGER ,
INOUT RTNFD CHAR(20) ,
IN FORMAT CHAR(8) ,
IN QF CHAR(20) ,
IN "RCDFMT" CHAR(10) ,
IN OVRPRC CHAR(1) ,
IN SYSTEM CHAR(10) ,
IN FMTTYP CHAR(10) ,
IN ERRCOD CHAR(8) )
LANGUAGE CL
SPECIFIC SQLEXAMPLE.DBRTVFD
NOT DETERMINISTIC
NO SQL
CALLED ON NULL INPUT
EXTERNAL NAME 'QSYS/QDBRTVFD'
PARAMETER STYLE GENERAL ;
首先,默认值是语言C
,您可能不希望QUSRJOBI是一个OPM程序。在这里,传递CL语言参数对于可预测性来说是一个更好的选择
此外,您可能希望将其设置为无SQL
,而不是修改SQL数据
,因为您没有修改SQL数据。可能需要删除设置选项
,以便将问题降到最低
如果您对M_GET_JOB_INFORMATION过程进行了这些更改,请查看它是否返回有用的值。如果没有,我们可以深入挖掘
对于您的特定API,我使用此代码在I 6.1上测试结果:
CREATE PROCEDURE SQLEXAMPLE.M_GET_JOB_INFORMATION (
INOUT OUT_RECEIVER_VARIABLE CHAR(85) ,
IN IN_LENGTH_OF_RECEIVER_VARIABLE INTEGER ,
IN IN_FORMAT_NAME CHAR(8) ,
IN IN_QUALIFIED_JOB_NAME CHAR(26) ,
IN IN_INTERNAL_JOB_IDENTIFIER CHAR(16) ,
IN IN_ERROR_CODE CHAR(8) )
LANGUAGE CL
SPECIFIC SQLEXAMPLE.M_JOBINFO
NOT DETERMINISTIC
NO SQL
CALLED ON NULL INPUT
EXTERNAL NAME 'QSYS/QUSRJOBI'
PARAMETER STYLE GENERAL ;
创建了一个基本包装器,如下所示:
CREATE PROCEDURE SQLEXAMPLE.GENRJOBI (
INOUT JOBI VARCHAR(85) ,
IN QJOB VARCHAR(26) )
LANGUAGE SQL
SPECIFIC SQLEXAMPLE.GENRJOBI
NOT DETERMINISTIC
MODIFIES SQL DATA
CALLED ON NULL INPUT
SET OPTION ALWBLK = *ALLREAD ,
ALWCPYDTA = *OPTIMIZE ,
COMMIT = *NONE ,
DBGVIEW = *LIST ,
CLOSQLCSR = *ENDMOD ,
DECRESULT = (31, 31, 00) ,
DFTRDBCOL = *NONE ,
DLYPRP = *NO ,
DYNDFTCOL = *NO ,
DYNUSRPRF = *USER ,
RDBCNNMTH = *RUW ,
SRTSEQ = *HEX
P1 : BEGIN
DECLARE JOBII CHAR ( 85 ) ;
DECLARE SZJOBI INTEGER ;
DECLARE FORMATI CHAR ( 8 ) ;
DECLARE QJOBI CHAR ( 26 ) ;
DECLARE JOBIDI CHAR ( 16 ) ;
DECLARE ERRCODI CHAR ( 8 ) ;
DECLARE STKCMD CHAR ( 10 ) ;
SET JOBII = X'00000000' ;
SET SZJOBI = 85 ;
SET FORMATI = 'JOBI0100' ;
SET QJOBI = QJOB ;
SET JOBIDI = ' ' ;
SET ERRCODI = X'0000000000000000' ;
SET STKCMD = '*LOG' ;
CALL SQLEXAMPLE . M_GET_JOB_INFORMATION ( JOBII , SZJOBI , FORMATI , QJOBI , JOBIDI , ERRCODI ) ;
CALL SQLEXAMPLE . LOGSTACK ( STKCMD ) ;
SET JOBI = JOBII ;
END P1 ;
包装器只提供了一个调用API proc的示例。它对API返回的结构不做任何处理,只将其传递回调用方。您最初的问题包括从结构中提取子字段的代码位,因此我不认为在这里放类似的代码有什么意义
这两个过程在iNav的“运行SQL脚本”中进行了测试,以获取有关我正在运行的交互式作业的信息,结果如下所示:
输出区域以字符显示结构,可以看到整数子字段与字符子字段混合在一起。根据需要解构结构。我可能会创建一个附加过程,将结构作为输入并返回单个结构元素。您知道IBM已经包装了Get Job Info API吗 按版本/发布的所有服务
获取工作信息
1/5/2015更新版本:增强以使返回错误ID和错误数据的错误代码正常工作,并删除一些不必要的相关代码行。添加了M_HEX_STRING_to_INTEGER函数,用于在RECEIVER_变量中获取API返回的整数并将其转换为实整数。二进制(十六进制(my_int))代码没有如我所希望的那样工作,所以这个版本以十六进制传递错误代码“bytes provided”的大小。为了解决这个问题,我想我需要编写一个函数来获取一个整数并返回一个二进制(4),以便在二进制字符串应用程序中使用,直到IBM在系统I上给我们提供结构化类型。/更新结束 我解决了问题。主要问题是我调用的API是语言PLI,我想我错过了尝试该语言设置。我还有其他问题,包括忘记将一些偏移量转换为字节位置,我能够执行该操作的唯一方法是对与错误代码相关的代码使用VARBINARY。INOUT OUT\u RECEIVER\u变量需要。如果设置为OUT而不是INOUT,并且传递了无效的作业信息,则API程序将返回在上一次调用中返回的任何内容(返回上一次调用而非当前调用的剩余内存值)。我还必须编写一个函数来获取API返回的二进制INT数据,将其转换为实整数。如果我们有结构化类型(用户定义的数据结构)对于SQL和DB2的其他版本一样,我们可能可以避免大部分或所有二进制内容,从而使事情变得更简单 现在我已经整理好了包装这些API的基础知识,现在我应该能够非常快速地包装它们:)
--M_GET_JOB_INFORMATION(M_JOBINFO)—获取作业信息的外部SQL用户定义过程。
--围绕ibma的包装
--M_GET_JOB_INFORMATION (M_JOBINFO) - external SQL user defined procedure to fetch job information.
--Wrapper around IBM api QUSRJOBI (retrieve job information).
--May be used for any of the format data structures returned by the api, assuming a UDTF function has been created to consume the desired format data structure.
create or replace procedure M_GET_JOB_INFORMATION
( inout RECEIVER_VARIABLE char(86) for bit data --must use inout
,in LENGTH_OF_RECEIVER_VARIABLE int
,in FORMAT_NAME char(8)
,in QUALIFIED_JOB_NAME char(26)
,in INTERNAL_JOB_IDENTIFIER char(16)
,inout ERROR_CODE char(48) for bit data
)
program type main
external name 'QSYS/QUSRJOBI'
language PLI
parameter style general
not deterministic
modifies SQL data
specific M_JOBINFO
set option dbgview = *source
,commit = *nc
,closqlcsr = *endmod
,tgtrls = V7R1M0
;
--M_GET_JOB_INFORMATION_BASIC (M_JOBINFBF) - SQL user defined Table function to fetch job name, user, number, and other basic job information.
--Wrapper around IBM api QUSRJOBI retrieved data format JOBI0100 (basic job information).
--From IBM manual QUSRJOBI api:
--The JOBI0100 format information is valid for active jobs and jobs on queues.
--For jobs on queues, this format returns zeros or blanks for the attributes.
--If the Change Job (CHGJOB) command was run against a job on a *JOBQ, the attributes returned are the attributes specified on the CHGJOB command.
--If the job status changes to *OUTQ, the status field returned is *OUTQ and the API returns no information other than the number of bytes returned,
--the number of bytes available, the qualified job name, the job type, the job subtype, and the internal job identifier.
--Examples of use:
--select * from table( M_GET_JOB_INFORMATION_BASIC( '*', '', '', '' ) ) as JOB_INFO --Get current job and basic info
--select * from table( M_GET_JOB_INFORMATION_BASIC( 'QZDASOINIT', 'QUSER', '123456', '' ) ) as JOB_INFO --Get a specific job's basic info
create or replace function M_GET_JOB_INFORMATION_BASIC
( IN_JOB_NAME varchar(10)
,IN_JOB_USER varchar(10)
,IN_JOB_NUMBER varchar(6)
,IN_INTERNAL_JOB_IDENTIFIER varchar(16)
)
returns table( JOB_NAME char(10)
,JOB_USER char(10)
,JOB_NUMBER char(6)
,INTERNAL_JOB_IDENTIFIER char(16)
,JOB_STATUS char(10)
,JOB_TYPE char(1)
,JOB_SUBTYPE char(1)
,RUN_PRIORITY int
,TIME_SLICE int
,DEFAULT_WAIT int
,ELIGIBLE_FOR_PURGE char(10)
,ERROR_ID char(7) --returned as blank if valid job requested, else IBM error message ID returned.
,ERROR_DATA char(32) --returned as blank if valid job requested, else IBM error message data returned.
)
language SQL
specific M_JOBINFBF
not deterministic
disallow parallel
no external action
modifies SQL data
called on null input
not fenced
cardinality 1 --helps SQL optimizer
set option dbgview = *source
,commit = *nc
,closqlcsr = *endmod
,dftrdbcol = *none
,tgtrls = V7R1M0
begin
declare RECEIVER_VARIABLE char(86) for bit data default ''; --receives "JOBI0100" format output from API
declare LENGTH_OF_RECEIVER_VARIABLE int default 86; --length of "JOBI0100" Format
declare FORMAT_NAME char(8) default 'JOBI0100'; --basic job information
declare QUALIFIED_JOB_NAME char(26);
declare INTERNAL_JOB_IDENTIFIER char(16);
declare ERROR_CODE char(48) for bit data default ''; --ERROR_CODE "ERRC0100" Format - Input: bytes provided (4); Output: bytes available (4), error message ID (7), reserved bytes (1), error data (32) = 48 bytes
if IN_INTERNAL_JOB_IDENTIFIER = '' then
set QUALIFIED_JOB_NAME = char( IN_JOB_NAME, 10 ) || char( IN_JOB_USER, 10 ) || char( IN_JOB_NUMBER, 6 );
set INTERNAL_JOB_IDENTIFIER = '';
else
set QUALIFIED_JOB_NAME = '*INT';
set INTERNAL_JOB_IDENTIFIER = IN_INTERNAL_JOB_IDENTIFIER;
end if;
set ERROR_CODE = bx'00000030'; --put size of ERROR_CODE here in hex (Bytes Provided) hex 30 = dec 48
call M_GET_JOB_INFORMATION
( RECEIVER_VARIABLE --in/out
,LENGTH_OF_RECEIVER_VARIABLE --in
,FORMAT_NAME --in
,QUALIFIED_JOB_NAME --in
,INTERNAL_JOB_IDENTIFIER --in
,ERROR_CODE --in/out
);
return values( char( substr( RECEIVER_VARIABLE, 9, 10 ), 10 ) --JOB_NAME
,char( substr( RECEIVER_VARIABLE, 19, 10 ), 10 ) --JOB_USER
,char( substr( RECEIVER_VARIABLE, 29, 6 ), 6 ) --JOB_NUMBER
,char( substr( RECEIVER_VARIABLE, 35, 16 ), 16 ) --INTERNAL_JOB_IDENTIFIER
,char( substr( RECEIVER_VARIABLE, 51, 10 ), 10 ) --JOB_STATUS
,char( substr( RECEIVER_VARIABLE, 61, 1 ), 1 ) --JOB_TYPE
,char( substr( RECEIVER_VARIABLE, 62, 1 ), 1 ) --JOB_SUBTYPE
,case when substr( RECEIVER_VARIABLE, 65, 4 ) = ''
then int( 0 )
else M_HEX_STRING_TO_INTEGER( hex( substr( RECEIVER_VARIABLE, 65, 4 ) ) )
end --RUN_PRIORITY
,case when substr( RECEIVER_VARIABLE, 69, 4 ) = ''
then int( 0 )
else M_HEX_STRING_TO_INTEGER( hex( substr( RECEIVER_VARIABLE, 69, 4 ) ) )
end --TIME_SLICE
,case when substr( RECEIVER_VARIABLE, 73, 10 ) = ''
then int( 0 )
else M_HEX_STRING_TO_INTEGER( hex( substr( RECEIVER_VARIABLE, 73, 4 ) ) )
end --DEFAULT_WAIT
,char( substr( RECEIVER_VARIABLE, 77, 10 ), 10 ) --ELIGIBLE_FOR_PURGE
,char( substr( ERROR_CODE, 9, min( M_HEX_STRING_TO_INTEGER( hex( substr( ERROR_CODE, 5, 4 ) ) ), 7 ) ), 7 ) --ERROR_ID
,char( substr( ERROR_CODE, 17, min( M_HEX_STRING_TO_INTEGER( hex( substr( ERROR_CODE, 5, 4 ) ) ), 32 ) ), 32 ) --ERROR_DATA
);
end
;
--M_HEX_STRING_TO_INTEGER - M_HEXTOINT - scalar SQL UDF to convert a hex string of an integer to an integer return value
--Use for working with binary strings and OS/400 system APIs.
--Throws an error if an invalid byte is found inside the input hex string.
create or replace function M_HEX_STRING_TO_INTEGER
( IN_HEX_STRING varchar(8) )
returns int
language SQL
specific M_HEXTOINT
not deterministic
disallow parallel
no external action
modifies SQL data
returns null on null input
not fenced
set option dbgview = *source
,commit = *nc
,closqlcsr = *endmod
,tgtrls = V7R1M0
begin
declare BYTE_CHAR char(1);
declare POS int default 1;
declare ACCUM_VALUE int;
declare BIGINT_RESULT bigint default 0;
declare STRING_LENGTH int;
set STRING_LENGTH = length( IN_HEX_STRING );
while POS <= STRING_LENGTH do
set BYTE_CHAR = substr( IN_HEX_STRING, POS, 1 );
if BYTE_CHAR between '0' and '9' then
set ACCUM_VALUE = int( BYTE_CHAR );
else
set ACCUM_VALUE = case BYTE_CHAR
when 'A' then 10
when 'B' then 11
when 'C' then 12
when 'D' then 13
when 'E' then 14
when 'F' then 15
else raise_error( 'MG010', 'Function M_HEX_STRING_TO_INTEGER encountered invalid INT hex byte=' || BYTE_CHAR )
end;
end if;
if ACCUM_VALUE <> 0 then
set BIGINT_RESULT = BIGINT_RESULT + ( ACCUM_VALUE * power( 16, STRING_LENGTH - POS ) ) ;
end if;
set POS = POS + 1;
end while;
return int( case when BIGINT_RESULT > 2147483647 then BIGINT_RESULT - 4294967296 else BIGINT_RESULT end );
end