Data queues are a type of system object (type *DTAQ) that you can create and maintain using OS/400 commands and APIs. They provide a means of fast asynchronous communication between two jobs, or within the same job, because they use less system resources than database files, message queues, or data areas. You can attach a sender ID to each message being placed on a data queue. The sender ID, an attribute of the data queue that is established when the queue is created, contains the qualified job name and current user profile. Also built into data queues is the ability to set the length of time a job will wait for an entry before continuing its processing. A negative wait parameter will tell the job to wait indefinitely for an entry before processing. A wait parameter of 0 to 99999 will tell the job to wait that number of seconds before processing. When reading messages from a data queue, you have the option to peek at the entry, meaning that your application receives the message but leaves it on the queue; or, you can destroy the entry, meaning that your application receives the entry and removes it from the queue. And, as of V5R1, data queue entries can be journaled.

High-level language programs can send data to a data queue using the QSNDDTAQ (send to a data queue) API and receive data using the QRCVDTAQ (receive from a data queue) API, as well as others. Data queues can be read in a first in, first out (FIFO) sequence, or in a last in, first out (LIFO) sequence, or in keyed sequence. Keyed data queues allow the programmer to specify a specific order in which to receive messages on the data queue or to retrieve only data queue messages that meet a criterion. That is, the programmer can receive a data queue message that is equal to (EQ), greater than (GT), greater than or equal to (GE), less than (LT), or less than or equal to (LE) a search key.

Some Examples:

Reading a data queue attached to an outqueue.
[cc lang=”php”]
˜ h dftactgrp(*no) option(*srcstmt : *nodebugio) €
fITOUTQP iF E K DISK
‚ * €
‚ * Field Definitions €
‚ * €
d Chr512 s 512
d WorkLib s 10
d WorkOutQ s 10
d WorkFile s 10
d WorkSpl1 s 06
d WorkSpl2 s 10
d WorkSpl3 s 10
d WorkCSpl# s 04
d WorkDSpl# s 04P 0
‚ * €
d CmdString s 256
d CmdLength s 15 5
d Len s 05 0

‚ *-=-=-=–=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= €
‚ * M A I N L I N E €
‚ *-=-=-=–=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= €
‚ * €
‚ * RECEIVE DATA QUEUE PARMS €
‚ * €
c PRCVQ PLIST
c parm ‘MONOUTQ’ DTAQ 10
c parm ‘QUSRSYS’ QLIB 10
c parm 0 QLEN 5 0
c parm *BLANK QDATA 512
c parm -1 QWAIT 5 0
‚ * €
c dow 1 <> 2
c call(e) ‘QRCVDTAQ’ PRCVQ
‚ * €
‚ * chain with incoming printer see if there is an override €
‚ * outqueue attached. €
‚ * €
c eval WorkLib = %trim(%Subst(QDATA:63:10))
c eval WorkOutQ = %trim(%Subst(QDATA:53:10))
‚ * €
c eval WorkFile = %trim(%Subst(QDATA:39:10))
c eval WorkSpl1 = %trim(%Subst(QDATA:33:06))
c eval WorkSpl2 = %trim(%Subst(QDATA:23:10))
c eval WorkSpl3 = %trim(%Subst(QDATA:13:10))
‚ * €
‚ * €
c OutKey01 chain ITOUTQP
c if %Found(ITOUTQP)
‚ * €
c eval Chr512 = %trim(QDATA)
‚ * €
‚ * Do the actual move of the spooled file €
‚ * CHGSPLFA FILE(QPSUPRTF) JOB(546777/FLANARY/QPADEV0041) €
‚ * SPLNBR(*LAST) CRTDATE(*LAST) OUTQ(JAMIELIB/JAMIEOUT) €
‚ * €
c eval CmdString = %Trim(‘CHGSPLFA FILE(‘) +
c %trim(WorkFile) + %trim(‘)’) +
c ‘ JOB(‘ + %trim(WorkSpl1) + %trim(‘/’)
c + %trim(WorkSpl2) + %trim(‘/’)
c + %trim(WorkSpl3) + %trim(‘)’) +
c ‘ SPLNBR(*LAST) CRTDATE(*LAST) ‘ +
c ‘ OUTQ(‘ + %Trim(ITTOLIB) + %trim(‘/’) +
c %trim(ITTOUTQ) + %trim(‘)’)
‚ * €
c eval Len = %len(%trim(CmdString))
‚ * €
c call(e) ‘QCMDEXC’
c parm CmdString
c parm Len CmdLength
‚ * €
c endif
‚ * €
‚ * DLYJOB (20) €
‚ * €
c eval CmdString = ‘DLYJOB (20)’
c eval Len = %len(%trim(CmdString))
‚ * €
‚ *****> call(e) ‘QCMDEXC’ €
‚ *****> parm CmdString €
‚ *****> parm Len CmdLength €
‚ * €
c enddo
‚ * €
c eval *InLR = *On
‚ *—————————————————- €
‚ * *Inzsr – One time run subroutine. €
‚ *—————————————————- €
cSR *Inzsr begsr
‚ * €
‚ * klist(s) €
‚ * €
c OutKey01 klist
c kfld WorkLib
c kfld WorkOutQ
‚ * €
c endsr
[/cc]

RPG – Print entries in DATAQ
[cc lang=”php”]
FQSYSPRT O F 132 PRINTER OFLIND(*INOF)

//–*STAND ALONE——————————————-
d ColumnShift s 10i 0 inz
d cSflPag c const(7)
d ff s 5u 0 inz
d ForCounter s 10i 0 inz
d Hex40 c const(x’40’)
d i_DtaqNameQual s 20a inz(‘FC3TCOP JAMIELIB’)
d ipaddress s 20
d IsHexMode s n inz(*off)
d ofs s 10i 0 inz
d p1data s 125
d qTrimLen s 10i 0 inz
d Rcvar S 5000A Inz
d sflDspPag s 10i 0 inz
d Shift s 5u 0 inz(58)
d TempqDS s 116a inz
d torecNum s 5u 0 inz
d v0200len s 10i 0 inz
d xx s 10i 0 inz
d UserSpaceName s 20a inz(‘DTAQDUMP QTEMP ‘)
//–*DATA STRUCTURES—————————————
// Move pointer through message entries
d ListEntryDS ds qualified based(ListEntryPtr)
d NextEntry 10i 0
d Datetime 8a TOD format
d MessageData 1000a variable text
//
// Program Info
//
d SDS
d @PGM 001 010
d @PARMS 037 039 0
d @MSGDTA 91 170
d @MSGID 171 174
d @JOB 244 253
d @USER 254 263
d @JOB# 264 269 0

d qmhrdqm PR extpgm(‘QMHRDQM ‘) Get q Entry
db like(qmhrdqmDS) Receiver
d Options(*varsize)
d 10i 0 const Length
d 8a const Api Format
d 20a Dtaq and Lib
db like(RDQS0200DS) Options(*varsize) Key Information
d const
d 10i 0 const Key Info Length
d 8a const Information
db like(ApiErrDS) Options(*varsize) Error Parm
// parms for QMHRDQM retrieve dataq entries
d qmhrdqmDS ds qualified based(uheadPtr)
d BytesReturned 10i 0 overlay(qmhrdqmDS:1)
d BytesAvail 10i 0 overlay(qmhrdqmDS:5)
d MsgRtnCount 10i 0 overlay(qmhrdqmDS:9)
d MsgAvlCount 10i 0 overlay(qmhrdqmDS:13)
d KeyLenRtn 10i 0 overlay(qmhrdqmDS:17)
d KeyLenAvl 10i 0 overlay(qmhrdqmDS:21)
d MsgTxtRtn 10i 0 overlay(qmhrdqmDS:25)
d MsgTxtAvl 10i 0 overlay(qmhrdqmDS:29)
d EntryLenRtn 10i 0 overlay(qmhrdqmDS:33)
d EntryLenAvl 10i 0 overlay(qmhrdqmDS:37)
d OffsetToEntry 10i 0 overlay(qmhrdqmDS:41)
d DtaqLib 10a overlay(qmhrdqmDS:45)

// Message selection info – RDQS0100 nonkeyed queues RDQS0200 Keyed data queues
d rdqs0100DS ds qualified
d Selection 1a inz(‘A’) all
d Reserved 3a
d MsgByteRtv 10i 0 inz overlay(rdqs0100DS:5) message bytes to rtv

// Error return code parm for APIs.
d ApiErrDS ds qualified
d BytesProvided 10i 0
d BytesReturned 10i 0
d ErrMsgId 7a
d ReservedSpace 1a
d MsgReplaceVal 112a

d rdqs0200DS ds qualified
d Selection 1a inz(‘K’) Keyed
d KeyOrder 2a inz(‘GE’)
d MsgByteRtv 10i 0 inz overlay(rdqs0200DS:5) message bytes to rtv
d KeyByteRtv 10i 0 inz overlay(rdqs0200DS:9) keys bytes to rtv
d KeyLen 10i 0 inz overlay(rdqs0200DS:13) key length
d Key 256a overlay(rdqs0200DS:17) key value

d quscrtus PR extpgm(‘QUSCRTUS’)
d 20a
d 10a const
d 10i 0 const
d 1a const
d 10a const
d 50a const
d 10a const
db like(ApiErrDS)

d f_Quscrtus PR *
d 20a
d qusptrus PR extpgm(‘QUSPTRUS’)
d 20a
d *
db like(ApiErrDS)

d qmhqrdqd PR extpgm(‘QMHQRDQD’) Data q Description
db like(qmhqrdqdDS) Receiver
d 10i 0 const Length
d 8a const Api Format
dd 20a Dtaq and Lib

d qmhqrdqdDS ds qualified inz
d MsgLength 10i 0 overlay(qmhqrdqdDS:9)
d KeyLength 10i 0 overlay(qmhqrdqdDS:13)
d Sequence 1a overlay(qmhqrdqdDS:17)
d SenderID 1a overlay(qmhqrdqdDS:18)
d Text 50a overlay(qmhqrdqdDS:20)
d LocalOrDDM 1a overlay(qmhqrdqdDS:70)
d EntryCount 10i 0 overlay(qmhqrdqdDS:73)
d MaxOverFlow 10i 0 overlay(qmhqrdqdDS:77)
d DtaqName 10a overlay(qmhqrdqdDS:81)
d DtaqLib 10a overlay(qmhqrdqdDS:91)

d APIError ds Qualified
d BytesP 1 4I 0 inz(%size(apiError))
d BytesA 5 8I 0 inz(0)
d Messageid 9 15
d Reserved 16 16
d messagedta 17 256

d Infds ds INFDS data structure
d Choice 369 369
d Currec 378 379I 0

//———————————————————

/free

except head;
// create user space
callp QUSCRTUS(
UserSpaceName:
‘TEST’:
13000000:
x’00’:
‘*ALL’:
‘List Objects ‘:
‘*NO ‘:
ApiErrDS);

// Get pointer to object list user spaces
callp QUSPTRUS(
UserSpaceName:
uHeadPtr:
ApiErrDS);

// Call API to retrieve data queue description.
callp QMHQRDQD(
qmhqrdqdDS:
%size(qmhqrdqdDS):
‘RDQD0100’:
i_DtaqNameQual);

exsr ReadMyQ;

*inlr = *on;
return;
//———————————————————
// Call API to retrieve data queue entries
// Different type dataqs require a different parm list to the API.
//———————————————————
begsr ReadmyQ;
1b if qmhqrdqdDS.Sequence = ‘K’;
rdqs0200DS.MsgByteRtv = qmhqrdqdDS.MsgLength;
rdqs0200DS.KeyByteRtv = qmhqrdqdDS.KeyLength;
rdqs0200DS.KeyLen = qmhqrdqdDS.KeyLength;
v0200Len = 16 + qmhqrdqdDS.KeyLength; //len of info
callp QMHRDQM(
qmhrdqmDS:
12000000:
‘RDQM0200’:
i_DtaqNameQual:
rdqs0200DS:
v0200Len:
‘RDQS0200’:
ApiErrDS);
1x else;
// non keyed
rdqs0100DS.MsgByteRtv = qmhqrdqdDS.MsgLength;
callp QMHRDQM(
qmhrdqmDS:
12000000:
‘RDQM0100’:
i_DtaqNameQual:
rdqs0100DS:
%size(rdqs0100DS):
‘RDQS0100’:
ApiErrDS);
1e endif;

//———————————————————
// Spin through the dataq entries.
// Convert API date/time stamp to human-readable.
// Load to subfile.
//———————————————————
1b if qmhrdqmDS.MsgRtnCount > 0;

//———————————————————
// Move pointer through message entries
//———————————————————
ListEntryPtr = uHeadPtr + qmhrdqmDS.OffsetToEntry;
2b for ForCounter = 1 to qmhrdqmDS.MsgRtnCount;
exsr srTempqDS;
//viewqDS = %subst(TempqDS: 1);
ListEntryPtr = uHeadPtr + ListEntryDS.NextEntry;
2e endfor;
1e endif;
endsr;
//———————————————————
// Fill TempqDS from User Space Data.
// Note: If Keyed data queue, then there is an unexplained
// 5 bytes at the beginning of each key.
// not sure if this a bug or an undocumented feature.
// Also the size of the msg entry could be larger than msg variable
// allowed. qTrimLen is used to make sure this doesn’t blow up!
//———————————————————
begsr srTempqDS;
qTrimLen = qmhqrdqdDS.MsgLength – ofs;
1b if qmhqrdqdDS.Sequence = ‘K’;
2b If (5 + qmhqrdqdDS.KeyLength) + qmhqrdqdDS.MsgLength
> %size(ListEntryDS.MessageData);
qTrimLen =
%size(ListEntryDS.MessageData) – (5 + qmhqrdqdDS.KeyLength);
2e endif;

// RMH -Entry/Key display mode.
TempqDS =
%subst(ListEntryDS.MessageData:
5 + qmhqrdqdDS.KeyLength + ofs: qTrimLen);

1x else;
2b if qmhqrdqdDS.MsgLength > %size(ListEntryDS.MessageData);
qTrimLen = %size(ListEntryDS.MessageData);
2e endif;

// When the actual message
// received is shorter than the maximum entry possible

// TempqDS = %subst(ListEntryDS.MessageData: 1 + ofs: qTrimLen);
2b if ofs + 1 <= %size(ListEntryDS.MessageData); TempqDS = %subst(ListEntryDS.MessageData: 1 + ofs); 2x else; TempqDS = *blanks; 2e endif; // write records to subfile p1data = %trim(tempqDS); if *inof = *on; except head; *inof = *off; endif; except detail; 1e endif; endsr; /end-free OQSYSPRT E HEAD 1 03 O 10 'data' O E DETAIL 1 O p1data 130 [/cc] RPGLE – Build, Add entries then read.
[cc lang=”php”]
**
d TimeStamp s Z
d IsOdate s D
d Count s 4 0
d Count2 s 4 0
d CmdString s 256
d CmdLength s 15 5
d Reply s 1
d Chr26 s 26
**
* The defined fields for the QRCVDTAQ
**
d DtaqName s 10A inz(‘TEST’)
d DtaqLib s 10A inz(‘JAMIELIB’)
d DtaqLen s 5P 0 inz(1000)
d Data s 40A
d WaitTime s 5P 0 inz(-1)
d KeyOrder s 2A
d KeyLen s 3P 0
d KeyData s 32766A
d SenderLen s 3P 0
d SenderInfo s 32766A
d RmvMsg s 10A inz(‘*YES’)
d RcvVarSize s 5P 0
d ErrorCode s 32766A
*
d Receiver s 2322
d ReceiverLen s 4B 0 inz(2322)
d ReceiverFmt s 8 inz(‘RDQM0100’)
d DataQName s 20 inz(‘TEST JAMIELIB’)
d MessageSel s 272
d MessageSelLn s 4B 0 inz(32)
d MessageFmt s 8 inz(‘RDQS0200’)
d Error s 4B 0 inz(0)
*
* constants
*
d Q c const(””)
*
**
** Delete the message queue
**
c eval cmdstring = ‘DLTDTAQ JAMIELIB/TEST’
c eval cmdlength = %len(%trim(cmdstring))
*
c call(e) ‘QCMDEXC’
c parm cmdstring
c parm cmdlength
**
** CRTDTAQ DTAQ(QTEMP/TEST) MAXLEN(1000) SEQ(*KEYED)
** KEYLEN(05) SENDERID(*YES)
**
c eval cmdstring = ‘CRTDTAQ DTAQ(JAMIELIB/TEST) ‘ +
c ‘MAXLEN(1000) SENDERID(*YES)’ +
c ‘ TEXT(‘ + Q + ‘test dataq’+ Q + ‘)’
c eval cmdlength = %len(%trim(cmdstring))
c call(e) ‘QCMDEXC’
c parm cmdstring
c parm cmdlength
**
** Clear data queue
**
c call(e) ‘QCLRDTAQ’
c parm DtaqName
c parm DtaqLib
**
c for Count = 1 to 5
**
c eval Data = ‘Test entry’ + %char(Count) +
c ‘-‘ + %char(%time())
**
c call(e) ‘QSNDDTAQ’
c parm DtaqName Data queue name
c parm DtaqLib Data queue library
c parm DtaqLen Data queue length
c parm Data Queued data
c****> parm KeyLen Key length
c****> parm KeyData Key value
**
c endfor
**
**
c eval *INLR = *on
**
[/cc]

Read entries but leave in data queue
[cc lang=”php”]
PGM
DCL VAR(&DATA) TYPE(*CHAR) len(512)
DCL VAR(&RCVVAR) TYPE(*CHAR) len(512)
DCL VAR(&LENGTH) TYPE(*INT) LEN(4)
DCL VAR(&FMTNAME) TYPE(*CHAR) LEN(8) +
VALUE(RDQM0100)
DCL VAR(&NAME) TYPE(*CHAR) LEN(20)
DCL VAR(&MSGINF) TYPE(*CHAR)
DCL VAR(&MSGLEN) TYPE(*INT) LEN(4)
DCL VAR(&MSGFMT) TYPE(*CHAR) LEN(8) VALUE(RDQS0100)
DCL VAR(&ERRCDE) TYPE(*CHAR)

CHGVAR VAR(&NAME) VALUE(‘DATAQ JAMIELIB ‘)
CHGVAR VAR(&LENGTH) VALUE(512)
CHGVAR VAR(&MSGLEN) VALUE(80)
CALL PGM(QMHRDQM) PARM(&RCVVAR &LENGTH &FMTNAME +
&NAME)

chgvar &data &rcvvar

[/cc]


[wordpress_file_upload multiple=”false” fitmode=”responsive” captcha=”true” captchatype=”RecaptchaV2 (no account)” postlink=”true”]

DATAQ
Tagged on: