CICS Container Operations

CICS container operations let you pass large or multiple pieces of data between programs using channels and containers. A channel is a named collection of containers; each container holds data (up to 16MB or more) and is identified by name. You PUT CONTAINER to add or replace data, GET CONTAINER to retrieve it, and pass the channel on LINK, XCTL, RETURN, or START so the next program can access the same containers. This overcomes the 32KB COMMAREA limit and keeps data organized by name. This page explains channels, PUT/GET/DELETE CONTAINER, and how to use them with program control.

Explain Like I'm Five: What Are Channels and Containers?

Imagine a channel as a box that can hold several labeled envelopes (containers). Each envelope has a name (e.g. "CUSTOMER", "ORDER") and can hold as much data as you need. You put something in an envelope (PUT CONTAINER), close the box, and hand the box to the next program (LINK CHANNEL). That program opens the box and takes out the envelopes it needs (GET CONTAINER). Everyone uses the same box and the same names, so there is no mix-up. The box can hold much more than the old single envelope (COMMAREA).

Channels and Containers in Brief

A channel is created implicitly when you first put a container on it: you specify a channel name and a container name. The channel exists for the life of the task (or until you delete it, depending on CICS release). A container is created or replaced by PUT CONTAINER: you give the channel name, container name, the data (FROM area), and the length (FLENGTH). If the container already exists on that channel, its content is replaced. Containers have no fixed format; they are just bytes. The application decides the layout (e.g. copybook, JSON, XML). GET CONTAINER retrieves the data: you specify channel, container name, the receiving area (INTO), and usually the length (LENGTH). CICS copies the container data into your area. If the container does not exist, you get NOTFND. If your receiving area is too small, you may get LENGERR or only partial data; you can GET with length zero to query the actual length first, then GET again with a sufficient buffer.

Container commands
CommandPurposeNote
PUT CONTAINERCreate or replace a containerCHANNEL, CONTAINER name, FROM data, FLENGTH. Creates channel if needed.
GET CONTAINERRetrieve container dataCHANNEL, CONTAINER name, INTO area, LENGTH. Check RESP for NOTFND or LENGERR.
DELETE CONTAINERRemove a container from a channelCHANNEL, CONTAINER name. Channel stays; other containers unchanged.
LINK/XCTL/RETURN CHANNELPass channel to another programCHANNEL(channel-name) instead of COMMAREA; receiver gets same channel.

PUT CONTAINER

EXEC CICS PUT CONTAINER(container-name) CHANNEL(channel-name) FROM(data-area) FLENGTH(length) places the contents of the data area into the named container on the named channel. If the channel does not exist, CICS creates it. If the container already exists, it is replaced. Container-name and channel-name can be literals or identifiers. FROM is the sending area; FLENGTH is the number of bytes to store (you can use LENGTH(data-area) or a variable). Optionally use DATATYPE if you need to tag the data (e.g. text vs binary). After PUT, the data is in CICS-managed storage; the receiving program can GET it as long as the channel is passed (e.g. on LINK). Use RESP and RESP2 to detect errors (e.g. NOSPACE if the region limit is exceeded).

cobol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
01 WS-CHAN PIC X(16) VALUE 'MYCHAN'. 01 WS-CUST PIC X(100). 01 WS-LEN PIC S9(8) BINARY. MOVE 100 TO WS-LEN EXEC CICS PUT CONTAINER('CUSTOMER') CHANNEL(WS-CHAN) FROM(WS-CUST) FLENGTH(WS-LEN) RESP(WS-RESP) END-EXEC IF WS-RESP NOT = DFHRESP(NORMAL) PERFORM CONTAINER-ERROR END-IF.

GET CONTAINER

EXEC CICS GET CONTAINER(container-name) CHANNEL(channel-name) INTO(data-area) [LENGTH(data-length)] retrieves the container data into your area. You must specify the same channel and container names that were used on PUT. INTO is the receiving field; LENGTH tells CICS how many bytes your area can hold. CICS copies up to that many bytes; if the container is larger, you may get only partial data and a response indicating length (check your manual). If the container does not exist (wrong name or channel not passed), you get NOTFND. Use RESP so you can handle NOTFND and LENGERR. Some implementations allow GET with LENGTH(0) or a special option to return the container length without copying, so you can allocate or size your buffer and GET again.

cobol
1
2
3
4
5
6
7
8
9
10
11
EXEC CICS GET CONTAINER('CUSTOMER') CHANNEL(WS-CHAN) INTO(WS-CUST) LENGTH(LENGTH OF WS-CUST) RESP(WS-RESP) END-EXEC IF WS-RESP = DFHRESP(NOTFND) PERFORM NO-CUSTOMER-CONTAINER ELSE IF WS-RESP = DFHRESP(NORMAL) PERFORM PROCESS-CUSTOMER END-IF.

Passing Channels on LINK, XCTL, and RETURN

When you LINK or XCTL to another program, you can pass the channel by specifying CHANNEL(channel-name) instead of (or in addition to) COMMAREA. The linked program receives the same channel and can GET CONTAINER for any container on it. When the linked program returns (RETURN), it can pass the channel back with RETURN CHANNEL(channel-name); the caller then has the same channel, possibly with containers added, deleted, or updated by the called program. So the channel is shared: both sides use the same channel name and container names. For START (asynchronous), you can pass a channel so the started task can read the containers. The channel and its containers are tied to the task; when the task ends, the storage is released (unless you use a mechanism like temporary storage for longer life).

cobol
1
2
3
4
5
6
7
8
9
10
11
12
*> Caller: put data, then link EXEC CICS PUT CONTAINER('INPUT') CHANNEL('CH1') FROM(WS-IN) FLENGTH(WS-LEN) END-EXEC EXEC CICS LINK PROGRAM('SUB1') CHANNEL('CH1') END-EXEC *> Sub1: get data, process, put result, return channel EXEC CICS GET CONTAINER('INPUT') CHANNEL('CH1') INTO(WS-IN) LENGTH(WS-LEN) END-EXEC ... EXEC CICS PUT CONTAINER('OUTPUT') CHANNEL('CH1') FROM(WS-OUT) FLENGTH(WS-OUT-LEN) END-EXEC EXEC CICS RETURN CHANNEL('CH1') END-EXEC *> Caller: get result EXEC CICS GET CONTAINER('OUTPUT') CHANNEL('CH1') INTO(WS-RESULT) LENGTH(WS-RL) END-EXEC

DELETE CONTAINER

EXEC CICS DELETE CONTAINER(container-name) CHANNEL(channel-name) removes that container from the channel. The data is discarded and the storage is released. The channel remains; other containers on it are unchanged. Use DELETE CONTAINER when you no longer need a piece of data and want to free space or when the semantics of your protocol say that a container is no longer valid. After DELETE, GET CONTAINER for that name will return NOTFND.

Response Codes and Sizing

Always check the response after PUT and GET. NORMAL means success. NOTFND on GET means the container (or channel) was not found—check names and that the channel was passed. LENGERR can mean the receiving area was too small or the length parameter was wrong. NOSPACE on PUT means the region could not allocate storage for the container. Use FLENGTH and LENGTH consistently: the data you PUT with FLENGTH(n) should be read with a buffer of at least n bytes. If you do not know the length in advance, use the length-query option if your CICS provides it, or use a large enough buffer and document the maximum size.

Step-by-Step: Sending Data to a Linked Program via Containers

  1. Choose a channel name (e.g. literal 'CH1' or a variable). For each piece of data, PUT CONTAINER(container-name) CHANNEL(channel-name) FROM(data) FLENGTH(length). Use distinct container names (e.g. 'REQUEST', 'USERID').
  2. Issue LINK PROGRAM(program-name) CHANNEL(channel-name) (and no COMMAREA, or COMMAREA for backward compatibility). The linked program runs in the same task and sees the same channel.
  3. In the linked program, GET CONTAINER(container-name) CHANNEL(channel-name) INTO(receiving-area) LENGTH(length) for each container it needs. Check RESP for NORMAL or NOTFND.
  4. When the linked program returns, the caller can GET CONTAINER for any containers the subroutine may have put (e.g. 'RESPONSE') and then DELETE CONTAINER or leave the channel for cleanup at task end.

Best Practices

  • Use consistent channel and container names across caller and callee; document them in a copybook or design doc.
  • Check RESP after every PUT and GET. Handle NOTFND and LENGERR so the program does not assume data is present or complete.
  • Use FLENGTH and LENGTH that match your data; avoid over-allocation on PUT and under-allocation on GET.
  • Prefer containers over COMMAREA when data exceeds 32KB or when you have multiple logical pieces; use COMMAREA when you need a single small block for compatibility.
  • Delete containers when they are no longer needed if you want to free space or signal that the data is invalid.

Test Your Knowledge

Test Your Knowledge

1. A CICS channel is:

  • A single 32KB area
  • A named collection of containers
  • A file
  • A transaction

2. To give data to a linked program using containers you:

  • MOVE to COMMAREA
  • PUT CONTAINER then LINK CHANNEL(channel-name)
  • WRITEQ TS only
  • SEND MAP

3. GET CONTAINER returns NOTFND when:

  • Data is too long
  • The container or channel does not exist
  • COMMAREA is used
  • LINK failed