Hell is PCF.

In Dante’s book “Inferno”, the gates of hell have “Abandon all hope, ye who enter here” inscribed upon them. The book describes Dante’s journey to the deepest levels of hell.

I had a similar journey, not so far, trying to use PCFs in common code.

I thought I knew how to use MQ PCFs to display and extract information about MQ and its objects, but “fools rush in where angels fear to tread”.

Thanks to Morag Hugson of MQGEM for her help in getting me through this journey.

The kindergarten course on using PCF

Do not use PCF, use the display commands and parse the output. Parsing the output is a simpler problem to solve than trying to use PCF.

The high school course.

Instead of using a command DIS Q(…) you use PCF; create a message with a series of control blocks, send the request to a system queue, and get the data back in a similar format.

There is a header control block to define the function, and 0 or more control blocks each of which define a field.

  • The first control block, the header block, defines the request. It has an integer request field, such as MQCMD_INQUIRE_Q.
  • The second and following control blocks are field control blocks, they have
    • A field to define the type of data, for example character string, byte string (may contain hex 00s), integer, 64 bit integer, or arrays of data.
    • A field to define which field is defined, for example the integer MQCA_Q_NAME
    • For strings and byte strings, the length of the data.
    • For strings the code page of the data.
    • The data.

The request is put to a system queue and the response comes back in the reply_to queue you specified. This has a similar format as the request:

  • There is a header giving the request type, (MQCMD_INQUIRE_Q), the condition and reason code, and a count of the fields returned.
  • There are 0 or more field control blocks – the same as above.

Your program can chain down the field control blocks and can display the fields.

The program from the first year high school will report data like

field type 20 has value 1

which is not very usable.

Using the supplied header file CMQSTRC, you can call MQIA_STR(20) and get back “MQIA_Q_TYPE”. So now you know this field is the Queue Type data.

Now you know it is a Q_Type you can use the function MQQT_STR(1) and get back the string “MQQT_LOCAL”. You can determine the queue type value as a string using

if (field_type=MQIA_Q_TYPE ) 
    queue_type= MQQT_STR(value)
else if (field_type=MQIACF_PUBSUB_PROPERTIES,)                
    property_type=MQPSPROP_STR(value)
else if (field_type...)  

You need a bit of code to match up the field type to the routing you need to call to get the data back. I am working on a function getValue(20,0) to get back “MQIA_Q_TYPE”, and “MQQT_LOCAL”. One call which returns, the data type and its character representation of the value, which will make life much easier for the programmer. There are over 200 field types and it is hard to find the mapping for the value.

In early days of MQ there were two choices of header. You issued a header with type MQCFT_COMMAND and got back one reply with a header type MQCFT_RESPONSE, and all of the data.

Not too difficult so far.

Going down to the next level of hell with z/OS. The request “inquire_chinit” goes to the command server, which sends back “Request received”. The command server then sends the request to the chinit, which sends the response back to the command server, which sends it on to your reply to queue.

You now have to manage at least two reply messages, one for the “Request received”, and one or more for the data.

The next complication which takes you down to the next level of hell, is Shared Queue on z/OS.

You can issue the PCF request saying “hello all queue managers, please give me information about the queue status as you see it for queue COLINPAICEQ”. This request can now go to multiple queue managers, and you get multiple replies back which you have to manage.

This is not well documented in the official documentation. It jumps straight to the PhD class.

I’ll try to explain the data you get back with some examples.

Example 1 Inquire queue manager.

I sent the PCF request with MQCMD_INQUIRE_Q_MGR.

Two messages were returned. They had the same msgid and correlid

The first message was type MQCFT_XR_ITEM with sequence number 1, the second message was MQCFT_XR_SUMMARY with sequence number 2.

First message

  • Type MQCFT_XR_ITEM: Message is an extended response to an Inquire command. It contains item data.
  • Command Request MQCMD_INQUIRE_Q_MGR
  • Condition code 0
  • Reason code 0
  • Sequence number 1
  • It is not last message in set.
  • Parameter count 107

Data fields

  1. MQBACF_RESPONSE_ID … a 24 character string with hexadecimal values. Think of this as a correlator field, so you can match all the responses for this request.
  2. MQCACF_RESPONSE_Q_MGR_NAME : ‘CSQ9’. This is the queue manager which sent the response.
  3. MQCA_Q_MGR_NAME : ‘CSQ9’
  4. MQCA_Q_MGR_DESC : ‘CSQ9, IBM MQ for z/OS – V9.0.1’
  5. MQIA_PLATFORM : MQPL_ZOS
  6. MQIA_CPI_LEVEL : 100
  7. MQIA_COMMAND_LEVEL : MQCMDL_LEVEL_924

Second message

Header

  • Type: MQCFT_XR_SUMMARY . Message is an extended response to a command. It contains summary information.
  • Request INQ_QMGR
  • Condition code 0
  • Reason code 0
  • Sequence number 2
  • It is the last message in set.
  • Number of parameters 2
  1. MQBACF_RESPONSE_ID: …. same as above.
  2. MQCACF_RESPONSE_Q_MGR_NAME: ‘CSQ9’

These two fields are used to correlate requests. I think …XR_SUMMARY really means end of messages in this set.

Example 2 Inquire chinit.

I sent the PCF request with MQCMD_INQUIRE_CHANNEL_INIT.

Five messages were returned. They all had the same msgid and correlid

The first response message was type MQCFT_XR_MSG with sequence number 1.

The the remaining four messages were part of one set. They had

  1. Queue manager information, such as number of dispatchers.
  2. Information about the TCP/IP listener
  3. Information about the LU 62 listener
  4. The “end” or summary record

First set, single message

  • Type 17 MQCFT_XR_MSG: Message is an extended response to a command. It contains informational or error details.
  • Command MQCMD_INQUIRE_CHANNEL_INIT
  • Condition code 0
  • Reason code 0
  • Sequence number 1
  • It is the last message in set.
  • 4 field control blocks were returned.

Field control blocks

  1. MQBACF_RESPONSE_ID: Value: 24 bytes of data (with the queue manager name in it
  2. MQCACF_RESPONSE_Q_MGR_NAME: 48 character queue manager name
  3. MQIACF_COMMAND_INFO : MQCMDI_COMMAND_ACCEPTED
  4. MQBACF_RESPONSE_SET: Same value as the first field control block

Set 2, first message

Header

  • Type: MQCFT_XR_ITEM: Message is an extended response to an Inquire command. It contains item data.
  • Request Command MQCMD_INQUIRE_CHANNEL_INIT
  • Reason code 0
  • Sequence number 1
  • It is not the last message in set.
  • Parameter count 20.

Field control blocks – information about the chinit

  1. MQBACF_RESPONSE_ID: Value: 24 bytes of data (with the queue manager name in it)
  2. MQCACF_RESPONSE_Q_MGR_NAME: 48 character queue manager name
  3. MQIACF_CHINIT_STATUS : MQSVC_STATUS_RUNNING
  4. MQIACH_ADAPS_STARTED : 8
  5. MQIACH_ADAPS_MAX :8
  6. MQIACH_DISPS_STARTED :5
  7. MQIACH_DISPS_MAX :5

Set 2, second message

Header

  • Type: MQCFT_XR_ITEM Message is an extended response to an Inquire command. It contains item data.
  • Request Command MQCMD_INQUIRE_CHANNEL_INIT
  • Reason code 0
  • Sequence number 2
  • It is not the last message in set.
  • Parameter count 7.

Field control blocks – status of TCP listener

  1. MQBACF_RESPONSE_ID …
  2. MQCACF_RESPONSE_Q_MGR_NAME : b’CSQ9′
  3. MQIACH_LISTENER_STATUS : MQSVC_STATUS_RUNNING
  4. MQIACH_XMIT_PROTOCOL_TYPE : MQXPT_TCP
  5. MQIACH_INBOUND_DISP: MQINBD_Q_MGR
  6. MQIACH_PORT_NUMBER :1414
  7. MQCACH_IP_ADDRESS : b’*’

Set 2, third message

Header

  • Type: MQCFT_XR_ITEM Message is an extended response to an Inquire command. It contains item data.
  • Request Command MQCMD_INQUIRE_CHANNEL_INIT
  • Reason code 0
  • Sequence number 2
  • It is not the last message in set
  • Parameter count 5.

Field control blocks – status of LU62 listener

  1. MQBACF_RESPONSE_ID ….
  2. MQCACF_RESPONSE_Q_MGR_NAME : b’CSQ9′
  3. MQIACH_LISTENER_STATUS : MQSVC_STATUS_STOPPED
  4. MQIACH_XMIT_PROTOCOL_TYPE : MQXPT_LU62
  5. MQIACH_INBOUND_DISP MQINBD_Q_MGR

Set 2, fourth (and last) message

Header

  • Type: 18 MQCFT_XR_SUMMARY Message is an extended response to a command. It contains summary information.
  • Request Command MQCMD_INQUIRE_CHANNEL_INIT
  • Reason code 0
  • Sequence number 4
  • It is the last message in set.
  • Parameter count 2.

Field control blocks

  1. MQBACF_RESPONSE_ID …
  2. MQCACF_RESPONSE_Q_MGR_NAME : ‘CSQ9’

I do not have access to a QSG, so cannot document the records for a QSG wide query.

Creating the data fields

If you want to create a PCF command to change a queue, you need the PCF header to describe the command, and data fields to identify the queue, and changed attributes.

The header is defined with control block MQCFH (not MQPCFH, I keep trying to use). There are several fields, the key one is Command. In this case we need MQCMD_CHANGE_Q. All request begin with MQCMD. There is MQCMD_INQUIRE_Q for displaying information about a queue.

There is a good post on PCF fields, called Morag’s Quirk’s #14: MQCFH Versions which contains some good information on data types and their usage.

There is a variety of data field record types, such as Byte string, Character string, Integer; and different usages

The field can be

  • passed with the command, (a selector), and returned. For example MQIA_, MQCA_
  • returned (but not passed through with a command); for queue manager for example MQCACF, and MQIACF) and for the CHINIT for example (MQCACH and MQIACH)

or to look at it a different way…

  • MQIA_ are the set used on MQINQ – and thus defined in cmqc.h. They can also be used in PCF rather than defining a second ID for the same parameter.
  • MQIACF_  are the set used solely for PCF – and thus defined in cmqcfc.h. They are not used on MQINQ.
  • MQIACH_ are the set used for channel commands, they are defined in cmqcfc.h.

The same logic is for for MQCA_/MQCACF_/MQCACH_.

Each field has a unique number, and the field types are generally grouped within a range, but not all of them. The monitoring integers and 64 bit integers are all mixed up.

To find the string representation of the unique number you can call the formatting functions (*MQBACF_STR, *MQCA_STR, *MQCACF_STR, *MQCACH_STR, *MQIA_STR, *MQIACF_STR, *MQIACH_STR, *MQIAMO_STR, *MQIAMO64_STR) in CMQSTRC.h. These routines return a string matching the number or the empty string ”. I found I have to go through them each in turn until there is a match.

In more detail.

  • Individual fields
    • A byte string (MQCFBS) . This is a string which can include hexadecimal characters, such as a message id or correlid. It does not get converted to a different code page. There are fields
      • MQBACF_ (Byte Parameter Types ) and are in the range 7001 to 7039.
    • A character string(MQCFST). This is a string such as queue name. This has a code page associated with it. This allows you to convert from ASCII to EBCDIC (or other conversion). There are fields
      • MQCA_ (Character Attribute Selectors) and are in the range 2001 to 2999 range (and 4000) for queue manager values .
      • MQCACF_ (Character Queue Manager Parameter Types) in the range 3000 to 3211 + a couple in the 55xx range.
      • MQCACH_ (Character Channel Parameter Types) in the range 3500 to 3573
    • An integer (MQCFIN), such as queue depth, or the value to mean “Enabled” or “Disabled”. There are fields
      • MQIA_, (Integer Attribute Selectors) integers in the range of 1 to 275 ( and 2000).
      • MQIACF_, (Integer Queue Manager Parameter Types) and are number in the range of 1 to 1440.
      • MQIACH_, (Integer Channel Types) and in the range 1501 to 1646.
    • A 64 bit integer(MQCFIN64). For example MQIAMO64_GET_BYTES, the number of bytes got as a integer 64 number. The values are intermixed with MQIAMO_ numbers. These are only used by the monitoring code – there are no MQIA*64 for anything else
  • Lists of fields
    • 64 bit integers(MQCFIL64). These are used in the midrange monitoring
    • integers(MQCFIL)
    • character strings(MQCFSL)
  • A group of (sub) parameters (MQCFGRP).
    • For example with application activity. This has a several groups. One of these groups is “Operations” which contains a set of PCF data for Operation type, Operation time, QMGR name).
    • They are also used in command events – but not used in command server messages.
    • These have a type field of MQGACF_ and are in the range 8001 to 9000
  • Filters – which provides the same function as the “WHERE” clause on a command.
    • Passing in a byte string (MQCFBF),
    • Passing a string (MQCFSF)
    • Passing in an integer string(MQCFIF).

Using PCF

It takes a while to understand how to use PCF. I found I had to write a lot of code to handle the PCF data and covert from numeric values to useful character strings so as to produce useful output. It does all work – it is just hard to get it to work.
To make it just a touch more complex, you may need to worry about data conversion and strings having different length when doing conversion, but I’ll leave this “as an exercise for the reader”1.


(1)Quote: The phrase is sometimes used as a joke. When a writer gets to the difficult part of a problem and he doesn’t want to take the trouble to solve it, or doesn’t know how to solve, he says this is “left as an exercise for the reader”, as if it was too trivial to waste space in the book discussing, when really the issue is that he can’t figure out the answer himself.

One thought on “Hell is PCF.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s