Introduction
The two latest tools of z/OS enterprise modernisation solutions are IBM Open Enterprise SDK for Go and IBM Data Virtualization Manager (DVM). Together, they are mix of a modern programming language (Go) and a data access solution (DVM) that provide a unique opportunity to amplify access to a variety of data types and ease of use. This blog dives into using the Go ibmruntimes/go-recordio module to access DVM and how a sample program is created.
Create a Go on z/OS DVM Program
DVM provides a unique opportunity to access virtualized data from anywhere without having to worry about the datatype. DVM also provides simplicity by recognizing SQL commands as the instructions for data.
Go-recordio is used to access the DS Client high-level API provided by the AVZCLIEN module included in the local installation of DVM. This go-recordio loadmod example and the DVM documentation are the foundations of the resulting solution.
The AMODE-31 section of the example code is the applicable part that can be adapted for accessing AVZCLIEN. By adjusting the sample code, the load module was loaded in the following way:
utils.LoadMod("AVZCLIEN")
The DVM documentation shares that the DS Client API “is implemented by passing a parameter list on a set of calls to [the] module AVZCLIEN.” This list consists of five parameters: DVCB control block address, send buffer address, receive buffer address, message buffer address, and SQLDA buffer address. After the Loadmod is loaded, a Call is made using the following method:
mod2.Call(uintptr(unsafe.Pointer(plist31)))
The process can be simplified by looking at just three out of five of these parameters to understand how the communication works. The DVCB control block is written in COBOL (as documented here https://www.ibm.com/docs/en/dvm/1.1.0?topic=api-dvcb-control-block), and it can be represented as a struct in Go to drive the program through the different states of operation that result in the execution of the SQL command. This is done by setting up the struct to match the datatype and size of the DVCB control block exactly. The send buffer is used to hold the SQL statements address, and the receive buffer holds the received data.
There are the four types of requests, and each of those parameters is particularly important in relation to the type of requests in a call. The four call types are: OPEN, SEND, RECV, and CLOS.
Before a call to the loadmodule, the example code changes the request type in the following way:
copy(code[:], "SEND")
utils.AtoE(code[:])
copy(plist31.DVCB_Connect.DVCB_REQUEST_CODE[:], code[:])
The byte slice receives the text “SEND,” followed by converting the ASCII text to EBCDIC, and finally this is copied into the request field in the DVCB_REQUEST_CODE byte array inside DVCB struct.
The SQL command used in the example is the following:
SQLMessage := `SELECT * FROM STAFFVS LIMIT 10`
It is followed by a copy into the sendArea.
copy(plist31.sendArea[:], SQLMessage)
This SQL command selects 10 lines from the data to print be printed out later. Naturally, before the call there is a conversion to EBCIDIC in the following way as seen in the similar earlier example:
utils.AtoE(plist31.DVCB_Connect.DVCB_REQUEST_CODE[:])
A few other values are assigned in the sample code are mandatory, and they are derived from the documentation, and follow the same method of conversion from ASCII to EBCDIC. This shows in the initialization function called fillDVCB(). However, before the call is made, the pointers for the parameters references in the AVZCLIEN call are linked in the following way, allowing them to be readily modified by the DVM program:
plist31.list[0] = uint32(0x0ffffffff & uintptr(unsafe.Pointer(&plist31.DVCB_Connect)))
plist31.list[1] = uint32(0x0ffffffff & uintptr(unsafe.Pointer(&plist31.sendArea)))
plist31.list[2] = uint32(0x0ffffffff & uintptr(unsafe.Pointer(&plist31.recieveArea)))
plist31.list[3] = uint32(0x0ffffffff & uintptr(unsafe.Pointer(&plist31.msgBuff)))
plist31.list[4] = uint32(0x0ffffffff & uintptr(unsafe.Pointer(&plist31.sqldaArea)))
plist31.list[4] |= uint32(0x80000000)
So far this has been a useful working example that can be further modified for specific use cases. Future work by the open-source community may lead to an SQL module for DVM, and this blog can serve as the basis for working with DVM in a fast and simple way. I encourage you to checkout the following resources to learn more and try out DVM on z/OS with Go.
Resources
IBM Open Enterprise SDK for Go Product Page
https://www.ibm.com/products/open-enterprise-sdk-go-zos
go-recordio
https://github.com/ibmruntimes/go-recordio
IBM Data Virtualization Manager for z/OS
https://www.ibm.com/products/data-virtualization-manager-for-zos