DL/I-specific tasks

Here are specific instructions for performing the following DL/I tasks: All the examples in these instructions use the Example DL/I database.

Using path calls to access multiple segments

If you invoke an EGL I/O statement with a dependent segment record object, you can read in any of the segments on the path from the root to the object at the same time. You can do this simply by adding the records for the path call to the statement. For example, when retrieving an order segment from our example customer database, you can read in the customer segment and the location segment on the same call:
get myCustomer, myLocation;
This statement generates the following DL/I pseudocode:
GU STSCCST*D (STQCCNO = :myCustomer.customerNo) 
   STSCLOC (STQCLNO = :myLocation.locationNo)
If you use the D command code on a get...forUpdate statement, the subsequent replace statement affects every segment retrieved. You can prevent replacement of a selected segment by specifying an explicit N command code in the SSA for the replace keyword, as in the following example:
get myCustomer, myLocation forUpdate;
replace myLocation with #dli{
	REPL STSCCST*N
	     STSCLOC };
The default DL/I call EGL builds for a delete function that follows a get forUpdate statement with D command codes does not delete each segment retrieved. It deletes only the I/O object segment.

Reading all segments with a single call

You can use a single function to read all segments in a database. If you issue a DL/I get next call with no SSAs, DL/I returns the next segment in the database regardless of its type. Follow these steps to use this technique:
  1. Write a get next statement for the record that represents the largest segment in the database. This ensures that any segment you read will not exceed allocated memory.
  2. Edit the statement's default DL/I call to delete the single SSA.
  3. Create records matching the other segments in the database. Declare them as redefined records for the record in step 1.
  4. Check DLIVar.segmentName after the get next statement to determine the type of segment that was retrieved.
  5. Access the retrieved segment from the redefined record structure, or assign the redefined structure to another record of the same type.
Here is an example of code that will print everything in the customer database. In this example, myHistoryRecordPart is the largest DLISegment record:
redefCustomer myCustomerRecordPart {redefines=myHistoryRecordPart};
redefLocation myLocationRecordPart {redefines=myHistoryRecordPart};
...


//read next segment, whatever type it is, into history record
while (myHistory not EOF)
	get next myHistory with #dli{
		GN };

	//so what type was it?
	case (DLIVar.segmentName)
		when "STSCCST"                   // it was a customer
 			myCustomer = redefCustomer;
			printCustomer();               // myCustomer is global
		when "STSCLOC"                   // it was a location
 			myLocation = redefLocation;
			printLocation();
		...
	end
end

Searching with a secondary index

There are several ways to add secondary indexing to a database. The simplest is to add a secondaryIndex field to the @PCB property to the DB_PCBRecord variable in your PSB record. If this is the first DB_PCBRecord in the PSB record, EGL will use this secondary index by default. For example, if you wanted to search for customers based on the orderReference field (STFCORF) in the orders segment, you could add a secondary index to the customerPCB in our example database, as follows:
// database PCB 	
customerPCB DB_PCBRecord { @PCB {
	pcbType = DB,
	pcbName = "STDCDBL",
	secondaryIndex = "STFCORF", //use DL/I name
	hierarchy = [
		@Relationship { segmentRecord = "myCustomerRecordPart"},
	 	@Relationship { 
			segmentRecord = "LocationRecord", 
			parentRecord = "myCustomerRecordPart" }, 			
		@Relationship {
 			segmentRecord = "OrderRecord",
			parentRecord = "myLocationRecordPart" },
		...
Perform a get operation to locate a customer, as in the following example:
get myCustomer;
EGL will generate the following code by default:
	GU STSCCST (STFCORF = :myOrder.orderReference)
If you wish to be able to choose between accessing customers by orderReference or by customerNo, create a second PCB for your secondary index. In the following example the second PCB is named orderReferencePCB:
// database PCB--access by customer number	
customerPCB DB_PCBRecord { @PCB {
	pcbType = DB,
	pcbName = "STDCDBL",
	hierarchy = [
		@Relationship { segmentRecord = "myCustomerRecordPart"},
	 	@Relationship { 
			segmentRecord = "LocationRecord", 
			parentRecord = "myCustomerRecordPart" }, 			
		@Relationship {
 			segmentRecord = "OrderRecord",
			parentRecord = "myLocationRecordPart" },
		...

// database PCB--access by order reference	
orderReferencePCB DB_PCBRecord { @PCB {
	pcbType = DB,
	pcbName = "STDXDBL",
	secondaryIndex = "STFCORF", //use DL/I name
	hierarchy = [
		@Relationship { segmentRecord = "myCustomerRecordPart"},
	 	@Relationship { 
			segmentRecord = "LocationRecord", 
			parentRecord = "myCustomerRecordPart" }, 			
		@Relationship {
 			segmentRecord = "OrderRecord",
			parentRecord = "myLocationRecordPart" },
		...
The pcbName must match an actual DL/I PCB. Now EGL's default behavior will once more be to access a customer record using the customerNo field. To access it using the alternate key, your EGL I/O statement must specify the orderReferencePCB with the usingPCB keyword, as in the following example:
get myCustomer usingPCB orderReferencePCB;
You can also have a more complex case, where you want to change the structure of the entire database as your program sees it. (Again, keep in mind that the PCB structure in your EGL program must match an existing DL/I PCB.) Suppose you want the customer database to look like an orders database to your program, with the unique reference number as the key to the orders segment. You can have a PCB with the following structure:
// orders view of customer database
ordersPCB DB_PCBRecord { @PCB {
	pcbType = DB,
	pcbName = "STDCDBL",
	secondaryIndex = "STFCORF", //use DL/I name
	hierarchy = [
		@Relationship { segmentRecord = "myOrderRecordPart" },
		@Relationship { 
			segmentRecord = "myLocationRecordPart", 
			parentRecord = "myOrderRecordPart" },
		@Relationship { 
			segmentRecord = "myCustomerRecordPart", 
			parentRecord = "myLocationRecordPart" },
		@Relationship { 
			segmentRecord = "myCreditRecordPart", 
			parentRecord = "myCustomerRecordPart" },
		@Relationship { 
			segmentRecord = "myHistoryRecordPart", 
			parentRecord = "myCustomerRecordPart" },
		@Relationship { 
			segmentRecord = "myItemRecordPart", 
			parentRecord = "myOrderRecordPart" }]}};
end
Assuming the order reference number is unique to each customer and order, and assuming ordersPCB is now your default PCB, you can find the customer for an order by doing a modified path call that removes the qualifications for the location and the customer:
get myOrder, my Customer with #dli{
	GU STPCORD (STQCODN = :myOrder.orderReference)
	   STSCLOC
	   STSCCST };

Searching with another non-key field

You can use any field in a segment as a search argument on a DL/I call by modifying the search arguments (SSAs) for the call. For example, if you wanted to read through the customer database and retrieve the customer segment and credit segment for each customer with a credit balance greater than a specified amount, you would define the DL/I call search arguments as follows:
  1. You want to search on the creditBalance field (STFCSBL) in the credit segment (STSCSTA). To do this, define a variable of type MONEY (for example, "targetBalance") that contains the specified amount that you want to search for.
  2. Write a get statement for the myCrStatus record.
  3. Add a #dli directive to the line, modifying the default code. Add a qualified SSA that looks for a segment where the amount in the creditBalance field is greater than targetBalance.
  4. Include a path command code (*D) to retrieve the customer segment (STSCCST) that corresponds to the credit segment.
The following sample code illustrates this process:
	targetBalance MONEY;
	targetBalance = 10,000.00;

	get myCrStatus with #dli{
		GU STSCCST*D STSCSTA (STFCSBL >= :targetBalance) };
You might also want to search based on information in another record. For example, if you wish to look up a customer based on a customer number (invCustNo) in an invoice record (myInvoice) that is of a type (myInvoiceRecordPart) that is a basic record and not part of the database. The code would look something like the following:
get myCustomer with #dli{
	GU STSCCST (STQCCNO = :myInvoice.invCustNo) };

Related concepts:
DL/I database support
IMS runtime support

Related reference:
DLIVar
Example DL/I database

Feedback
(C) Copyright IBM Corporation 2000, 2005. All Rights Reserved.