Sei sulla pagina 1di 17

Connecting to a DB2 database using PL/I Before attempting to connect to a DB2 database, you must first configure a database

connection (refer to Configuring a database connection) and then configure your workbench to use that database connection with the Database Connection wizard (refer to Setting up the connection to a DB2 UDB zSeries database for an example of how to connect to an OS/390 DB2 database). 1. Create a local PL/I project for your source code. 2. Link the DB2 library to your project by opening the Local Link Optionsproperty page. 3. Type /de db2api.lib in the Link Options field. 4. Click Local PL/I Build Options in the list on the left and provide the following information: Compile Options TEST,MACRO,OPTIONS SYSLIB installation_directory\EXTRAS\INCLUDE\PLI Note: Replace installation_directory with your DB2 installation directory. 5. Select Source contains embedded SQL. 6. Click Browse and select your DB2 connection. If you have not yet set up a connection to your database, click New Connection. 7. Optional: Enter additional options to pass onto the SQL preprocessor in the Other SQL options field. Separate multiple SQL options with commas. 8. Click OK. Note: Do not specify DB2-related options in the Compile Options field. The necessary compiler options and sub-options will automatically be generated for you from your selected DB2 connection and the options you enter in the Other SQL options field. 9. Insert the following statement before using any SQL statements in your code: 10. EXEC SQL INCLUDE SQLCA; EXEC SQL INCLUDE SQLDA; Also ensure that all of your SQL statements are formatted as follows in your code: EXEC SQL statement; where statement is your SQL statement. Sample PL/I code to access a DB2 database *PROCESS MARGINS(1,100) LANGLVL(SAA2) MACRO; *PROCESS SOURCE XREF; *PROCESS NOT('^') DFT(BYVALUE) ; *PROCESS INCLUDE (EXT('CPY','INC','PLP','MRP')); /*********************************************************************/ /* Author : Your name */ /* Date-written : 7/07/04 */ /* Primary Function(s) : Perfom a select on the Sample db2 DB */ /* */ /* What you need to change: */ /* Make sure you change the USERNAME and PASSWORD for your Sample */ /* DB2 database BOTH in the *PROCESS PP(SQL... statment and in the */

/* Connect query towards the middle of this example code. */ /* */ /*********************************************************************/ DB2Samp: PROCEDURE OPTIONS(MAIN); DISPLAY('EXAMPLE STARTED.'); /*******************************************************************/ /* declare SQL structures */ /*******************************************************************/ EXEC SQL INCLUDE SQLCA; EXEC SQL INCLUDE SQLDA; EXEC SQL WHENEVER SQLERROR CONTINUE; DCL VALCODE DCL GOODCODE DCL FIRSTNME BINARY(31) FIXED INIT(0); BINARY(31) FIXED INIT(0); CHAR(30) var init('NOVAL');

/*******************************************************************/ /* CONNECT TO DATABASE IS MANDATORY OR TABLE WON'T BE FOUND */ /*******************************************************************/ EXEC SQL CONNECT TO sample USER 'USERNAME' using 'PASSWORD'; CALL PRSQLC ('CONNECT TO SAMPLE');

/********************************************************************/ /*Performs a SELECT to get the first name of the employee */ /*with and employee number of '000010' and store it in the variable */ /*FIRSTNME and then displays it. */ /********************************************************************/ EXEC SQL SELECT firstnme INTO :FIRSTNME FROM employee WHERE empno = '000010'; DISPLAY('FIRSTNME'); DISPLAY('========'); DISPLAY(FIRSTNME); DISPLAY(''); CALL PRSQLC ('SELECT');

/****************************************************/ /****************************************************/

/* The PRSQLC procedure verifys that the SQL worked.*/ /* If it does not work, it will display the SQLCode */ /* as well as the SQL error message. */ /* */ /* Written by: person */ /****************************************************/ /****************************************************/ PRSQLC: PROCEDURE(FUNCTION); DECLARE FUNCTION CHARACTER (80) VARYING; IF (SQLCODE = GOODCODE) THEN PUT SKIP(2) EDIT (FUNCTION, ' WAS SUCCESSFUL') (A(LENGTH(FUNCTION)), A(15)); ELSE DO; IF (SQLCODE ^= 1) THEN DO; PUT SKIP(2) EDIT (FUNCTION, ' GOT SQLCODE ', sqlcode) (A(LENGTH(FUNCTION)), A(13), F(8)); PUT SKIP(2) EDIT (FUNCTION, ' GOT SQLERRM ', SQLERRM) (A(LENGTH(FUNCTION)), A(13), A(70)); VALCODE = VALCODE + 1; PUT SKIP(2) EDIT ('| VALCODE = ', VALCODE) (A(12), F(8)); END; ELSE PUT SKIP(2) EDIT (FUNCTION, ' REACHED BOTTOM OF TABLE') (A(LENGTH(FUNCTION)), A(24)); END; END PRSQLC; /**************************************************/ /**************************************************/ EXEC SQL COMMIT;

/*******************************************************************/ END DB2Samp; _______________________________________________________________________ ---------------------------------------------------------------------------------------------------------

IBM DB2 for i: Code example PL/I language programming example /* A sample program which updates the salaries for those employees */ /* whose current commission total is greater than or equal to the */ /* value of COMMISSION. The salaries of those who qualify are */ /* increased by the value of PERCENTAGE, retroactive to RAISE_DATE. */ /* A report is generated showing the projects which these employees */ /* have contributed to, ordered by project number and employee ID. */ /* A second report shows each project having an end date occurring */ /* after RAISE_DATE (i.e. is potentially affected by the retroactive */ /* raises) with its total salary expenses and a count of employees */ /* who contributed to the project. */ /*********************************************************************/


OPEN FILE(SYSPRINT); /* Update the selected employee's salaries by the new percentage. */ /* If an error occurs during the update, ROLLBACK the changes. */ EXEC SQL WHENEVER SQLERROR GO TO UPDATE_ERROR; EXEC SQL UPDATE CORPDATA/EMPLOYEE SET SALARY = SALARY * :PERCENTAGE WHERE COMM >= :COMMISSION ; /* Commit changes */ EXEC SQL COMMIT; EXEC SQL WHENEVER SQLERROR GO TO REPORT_ERROR; /* Report the updated statistics for each project supported by one */ /* of the selected employees. */ /* Write out the header for Report 1 */ put file(sysprint) edit('REPORT OF PROJECTS AFFECTED BY EMPLOYEE RAISES') (col(22),a); put file(sysprint) edit('PROJECT','EMPID','EMPLOYEE NAME','SALARY') (skip(2),col(1),a,col(10),a,col(20),a,col(55),a); exec sql declare c1 cursor for select DISTINCT projno, EMP_ACT.empno, lastname||', '||firstnme, salary from CORPDATA/EMP_ACT, CORPDATA/EMPLOYEE where EMP_ACT.empno = EMPLOYEE.empno and comm >= :COMMISSION order by projno, empno; EXEC SQL OPEN C1; /* Fetch and write the rows to SYSPRINT */ EXEC SQL WHENEVER NOT FOUND GO TO DONE1; DO UNTIL (SQLCODE ^= 0); EXEC SQL FETCH C1 INTO :RPT1.PROJNO, :RPT1.EMPNO, :RPT1.NAME, :RPT1.SALARY; PUT FILE(SYSPRINT) EDIT(RPT1.PROJNO,RPT1.EMPNO,RPT1.NAME,RPT1.SALARY)

(SKIP,COL(1),A,COL(10),A,COL(20),A,COL(54),F(8,2)); END; DONE1: EXEC SQL CLOSE C1; /* For all projects ending at a date later than 'raise_date' */ /* (i.e. those projects potentially affected by the salary raises) */ /* generate a report containing the project number, project name */ /* the count of employees participating in the project and the */ /* total salary cost of the project. */ /* Write out the header for Report 2 */ PUT FILE(SYSPRINT) EDIT('ACCUMULATED STATISTICS BY PROJECT') (SKIP(3),COL(22),A); PUT FILE(SYSPRINT) EDIT('PROJECT','NUMBER OF','TOTAL') (SKIP(2),COL(1),A,COL(48),A,COL(63),A); PUT FILE(SYSPRINT) EDIT('NUMBER','PROJECT NAME','EMPLOYEES','COST') (SKIP,COL(1),A,COL(10),A,COL(48),A,COL(63),A,SKIP); EXEC SQL DECLARE C2 CURSOR FOR SELECT EMP_ACT.PROJNO, PROJNAME, COUNT(*), SUM( (DAYS(EMENDATE) - DAYS(EMSTDATE)) * EMPTIME * DECIMAL(( SALARY / :WORK_DAYS ),8,2) ) FROM CORPDATA/EMP_ACT, CORPDATA/PROJECT, CORPDATA/EMPLOYEE WHERE EMP_ACT.PROJNO=PROJECT.PROJNO AND EMP_ACT.EMPNO =EMPLOYEE.EMPNO AND PRENDATE > :RAISE_DATE GROUP BY EMP_ACT.PROJNO, PROJNAME ORDER BY 1; EXEC SQL OPEN C2; /* Fetch and write the rows to SYSPRINT */ EXEC SQL WHENEVER NOT FOUND GO TO DONE2; DO UNTIL (SQLCODE ^= 0); EXEC SQL FETCH C2 INTO :RPT2; PUT FILE(SYSPRINT) EDIT(RPT2.PROJNO,RPT2.PROJECT_NAME,EMPLOYEE_COUNT,

TOTL_PROJ_COST) (SKIP,COL(1),A,COL(10),A,COL(50),F(4),COL(62),F(8,2)); END; DONE2: EXEC SQL CLOSE C2; GO TO FINISHED; /* Error occurred while updating table. Inform user and rollback */ /* changes. */ UPDATE_ERROR: EXEC SQL WHENEVER SQLERROR CONTINUE; PUT FILE(SYSPRINT) EDIT('*** ERROR Occurred while updating table.'|| ' SQLCODE=',SQLCODE)(A,F(5)); EXEC SQL ROLLBACK; GO TO FINISHED; /* Error occurred while generating reports. Inform user and exit. */ REPORT_ERROR: PUT FILE(SYSPRINT) EDIT('*** ERROR Occurred while generating '|| 'reports. SQLCODE=',SQLCODE)(A,F(5)); GO TO FINISHED; /* All done */ FINISHED: CLOSE FILE(SYSPRINT); RETURN; END PLIEX;

SQL statements in PL/I programs You can code SQL statements in a PL/I program wherever you can use executable statements. The first statement of the PL/I program must be the PROCEDURE statement with OPTIONS(MAIN), unless the program is a stored procedure. A stored procedure application can run as a subroutine. Each SQL statement in a PL/I program must begin with EXEC SQL and end with a semicolon (;). The EXEC and SQL keywords must appear must appear on one line, but the remainder of the statement can appear on subsequent lines. You might code an UPDATE statement in a PL/I program as follows: EXEC SQL UPDATE DSN8A10.DEPT SET MGRNO = :MGR_NUM

WHERE DEPTNO = :INT_DEPT ; Comments: You can include PL/I comments in embedded SQL statements wherever you can use a blank, except between the keywords EXEC and SQL. You can also include SQL comments in any SQL statement. To include DBCS characters in comments, you must delimit the characters by a shift-out and shift-in control character; the first shift-in character in the DBCS string signals the end of the DBCS string. Continuation for SQL statements: The line continuation rules for SQL statements are the same as those for other PL/I statements, except that you must specify EXEC SQL on one line. Declaring tables and views: Your PL/I program should include a DECLARE TABLE statement to describe each table and view the program accesses. You can use the DB2 declarations generator (DCLGEN) to generate the DECLARE TABLE statements. Including code: You can use SQL statements or PL/I host variable declarations from a member of a partitioned data set by using the following SQL statement in the source code where you want to include the statements: EXEC SQL INCLUDE member-name; You cannot nest SQL INCLUDE statements. Do not use the PL/I %INCLUDE statement to include SQL statements or host variable DCL statements. You must use the PL/I preprocessor to resolve any %INCLUDE statements before you use the DB2 precompiler. Do not use PL/I preprocessor directives within SQL statements. Margins: Code SQL statements in columns 2 through 72, unless you have specified other margins to the DB2 precompiler. If EXEC SQL starts before the specified left margin, the DB2 precompiler does not recognize the SQL statement. Names: You can use any valid PL/I name for a host variable. Do not use external entry names or access plan names that begin with 'DSN', and do not use host variable names that begin with 'SQL'. These names are reserved for DB2. Sequence numbers: The source statements that the DB2 precompiler generates do not include sequence numbers. IEL0378I messages from the PL/I compiler identify lines of code without sequence numbers. You can ignore these messages. Statement labels: You can specify a statement label for executable SQL statements. However, the INCLUDE text-file-name and END DECLARE SECTION statements cannot have statement labels. Whenever statement: The target for the GOTO clause in an SQL statement WHENEVER must be a label in the PL/I source code and must be within the scope of any SQL statements that WHENEVER affects. Using double-byte character set (DBCS) characters: The following considerations apply to using DBCS in PL/I programs with SQL statements: If you use DBCS in the PL/I source, DB2 rules for the following language elements apply: o Graphic strings o Graphic string constants o Host identifiers o Mixed data in character strings o MIXED DATA option

The PL/I preprocessor transforms the format of DBCS constants. If you do not want that transformation, run the DB2 precompiler before the preprocessor. If you use graphic string constants or mixed data in dynamically prepared SQL statements, and if your application requires the PL/I Version 2 (or later) compiler, the dynamically prepared statements must use the PL/I mixed constant format. o If you prepare the statement from a host variable, change the string assignment to a PL/I mixed string. o If you prepare the statement from a PL/I string, change that to a host variable, and then change the string assignment to a PL/I mixed string. Example: SQLSTMT = 'SELECT <dbdb> FROM table-name'M; EXEC SQL PREPARE STMT FROM :SQLSTMT; If you want a DBCS identifier to resemble a PL/I graphic string, you must use a delimited identifier. If you include DBCS characters in comments, you must delimit the characters with a shift-out and shift-in control character. The first shift-in character signals the end of the DBCS string. You can declare host variable names that use DBCS characters in PL/I application programs. The rules for using DBCS variable names in PL/I follow existing rules for DBCS SQL ordinary identifiers, except for length. The maximum length for a host variable is 128 Unicode bytes in DB2. For information about the rules for DBCS SQL ordinary identifiers, see the information about SQL identifiers. Restrictions: o DBCS variable names must contain DBCS characters only. Mixing singlebyte character set (SBCS) characters with DBCS characters in a DBCS variable name produces unpredictable results. o A DBCS variable name cannot continue to the next line. The PL/I preprocessor changes non-Kanji DBCS characters into extended binary coded decimal interchange code (EBCDIC) SBCS characters. To avoid this change, use Kanji DBCS characters for DBCS variable names, or run the PL/I compiler without the PL/I preprocessor. Special PL/I considerations: The following considerations apply to programs written in PL/I: When compiling a PL/I program that includes SQL statements, you must use the PL/I compiler option CHARSET (60 EBCDIC). In unusual cases, the generated comments in PL/I can contain a semicolon. The semicolon generates compiler message IEL0239I, which you can ignore. The generated code in a PL/I declaration can contain the ADDR function of a field defined as character varying. This produces either message IBM105l l or IBM1180l W, both of which you can ignore. The precompiler generated code in PL/I source can contain the NULL() function. This produces message IEL0533I, which you can ignore unless you also use NULL as a PL/I variable. If you use NULL as a PL/I variable in a DB2 application, you must also declare NULL as a built-in function (DCL NULL BUILTIN;) to avoid PL/I compiler errors.

The PL/I macro processor can generate SQL statements or host variable DCL statements if you run the macro processor before running the DB2 precompiler. If you use the PL/I macro processor, do not use the PL/I *PROCESS statement in the source to pass options to the PL/I compiler. You can specify the needed options on the COPTION parameter of the DSNH command or the option PARM.PLI=options of the EXEC statement in the DSNHPLI procedure. Using the PL/I multitasking facility, in which multiple tasks execute SQL statements, causes unpredictable results. PL/I WIDECHAR host data type is supported through the DB2 coprocessor only. When you use PL/I WX widechar constant, DB2 supports only bigendian format. Thus, when you assign a constant to the widechar type host variable in PL/I, ensure that bigendian format is used. For example: HVWC1 = '003100320033006100620063'WX; Equivalent to: HVWC1 = '123abc'; HVWC1 is defined as a WIDECHAR type host variable. PL/I SQL Preprocessor option, CCSID0 and NOCCSID0, usage consideration when used with the DB2 coprocessor. o When you use CCSID0 (default), it promotes compatibility with older PL/I programs, which used the DB2 precompiler. During program preparation, no CCSID value is associated with the host variable except for the WIDECHAR type host variable. For WIDECHAR type host variable, CCSID 1200 is always assigned by the PL/I SQL Preprocessor. During BIND and runtime, if no CCSID is associated with the host variable, the BIND option, ENCODING, which is meant for the application data, is used. If the ENCODING BIND option is not specified, then the default value for the ENCODING BIND option is used. o When you use NOCCSID0, a CCSID is associated with the host variable during program preparation. The CCSID is derived from the following items during program preparation: DECLARE :hv VARIABLE CCSID xxxx specified. Source CCSID, if no DECLARE VARIABLE ... CCSID xxxx is specified for the host variable. During BIND time, note the CCSID assigned to the host variable during program preparation is not known to the BIND process. For more information about BIND time CCSID resolution, see Determining the encoding scheme and CCSID of a string. For host variable used in static SQL, ensuring accurate and matching CCSID is assigned/derived through DECLARE VARIABLE ... CCSID xxxx, source CCSID or ENCODING BIND option or the installation default For parameter marker used in dynamic SQL, ensuring accurate CCSID for the corresponding host variable is assigned/derived through DECLARE VARIABLE ... CCSID xxxx, ENCODING BIND option or the installation default. The source CCSID has no influence on parameter marker.

You can use the subroutine DSNTIAR to convert an SQL return code into a text message. DSNTIAR takes data from the SQLCA, formats it into a message, and places the result in a message output area that you provide in your application program. For concepts and more information on the behavior of DSNTIAR, see Displaying SQLCA fields by calling DSNTIAR. You can also use the MESSAGE_TEXT condition item field of the GET DIAGNOSTICS statement to convert an SQL return code into a text message. Programs that require long token message support should code the GET DIAGNOSTICS statement instead of DSNTIAR. For more information about GET DIAGNOSTICS, see Checking the execution of SQL statements by using the GET DIAGNOSTICS statement. DSNTIAR syntax: CALL DSNTIAR ( sqlca, message, lrecl ); The DSNTIAR parameters have the following meanings: sqlca An SQL communication area. message An output area, in VARCHAR format, in which DSNTIAR places the message text. The first halfword contains the length of the remaining area; its minimum value is 240. The output lines of text, each line being the length specified in lrecl, are put into this area. For example, you could specify the format of the output area as: DCL DATA_LEN FIXED BIN(31) INIT(132); DCL DATA_DIM FIXED BIN(31) INIT(10); DCL 1 ERROR_MESSAGE AUTOMATIC, 3 ERROR_LEN FIXED BIN(15) UNAL INIT((DATA_LEN*DATA_DIM)), 3 ERROR_TEXT(DATA_DIM) CHAR(DATA_LEN); CALL DSNTIAR ( SQLCA, ERROR_MESSAGE, DATA_LEN ); where ERROR_MESSAGE is the name of the message output area, DATA_DIM is the number of lines in the message output area, and DATA_LEN is the length of each line. lrecl A fullword containing the logical record length of output messages, between 72 and 240. Because DSNTIAR is an assembler language program, you must include the following directives in your PL/I application: DCL DSNTIAR ENTRY OPTIONS (ASM,INTER,RETCODE); An example of calling DSNTIAR from an application appears in the DB2 sample assembler program DSN8BP3, contained in the library DSN8A10.SDSNSAMP. See DB2 sample applications for instructions on how to access and print the source code for the sample program. CICS: If your CICS application requires CICS storage handling, you must use the subroutine DSNTIAC instead of DSNTIAR. DSNTIAC has the following syntax: CALL DSNTIAC (eib, commarea, sqlca, msg, lrecl); DSNTIAC has extra parameters, which you must use for calls to routines that use CICS commands. eib EXEC interface block commarea

communication area For more information on these parameters, see the appropriate application programming guide for CICS. The remaining parameter descriptions are the same as those for DSNTIAR. Both DSNTIAC and DSNTIAR format the SQLCA in the same way. You must define DSNTIA1 in the CSD. If you load DSNTIAR or DSNTIAC, you must also define them in the CSD. For an example of CSD entry generation statements for use with DSNTIAC, see job DSNTEJ5A. The assembler source code for DSNTIAC and job DSNTEJ5A, which assembles and link-edits DSNTIAC, are in the data set prefix.SDSNSAMP. Delimiters in SQL statements in PL/I programs You must delimit SQL statements in your PL/I program so that DB2 knows when a particular SQL statement ends. Programming examples in PL/I You can write DB2 programs in PL/I. These programs can access a local or remote DB2 subsystem and can execute static or dynamic SQL statements. This information contains several such programming examples.

Open PL/I DB2 SQL Sample 1 Program filename: sample1.sqp sample1: proc options(main); /* */ /* This program shows the usage of host-variables, */ /* indicators, and some common SQL statements */ /* The database this program uses is the IBMSAMPL */ /* database that your DB2 product uses. You must be */ /* able to run the IBM DB2 demo sample program in */ /* order to be able to run this program. */ /* */ dcl idx fixed bin(15); dcl errmsg character(200); dcl msg_len fixed bin(15); exec sql include sqlca; exec sql begin declare section; dcl cnt fixed bin(15); dcl projno char(6); dcl projname char(24) varying; dcl deptno char(6); dcl respemp char(6);

dcl prstaff float bin(24); dcl prstaff_ind fixed bin(15); dcl prstdate char(10); dcl prstdate_ind fixed bin(15); dcl prendate char(10); dcl prendate_ind fixed bin(15); dcl majproj char(6); dcl majproj_ind fixed bin(15); exec sql end declare section; /* Set up error label for all SQL statements. */ exec sql whenever sqlerror goto err_label; /* Connect to the IBM DB2 sample demo data base */ exec sql connect to IBMSAMPL; /* Determine how many rows are in table project. */ exec SQL SELECT COUNT(*) INTO :cnt from project; put skip edit('Number of rows in table project:', cnt) (a(40),x,f(3,0)); put skip list('All the rows for project are:'); put skip; /* Declare and use a cursor to fetch each row. */ exec sql declare cl cursor for select projno, projname, deptno, respemp, prstaff, prstdate, prendate, majproj from project; exec sql open cl; do idx = 1 to cnt; prstaff = 0; /* re-init */ prstdate = ' '; /* re-init */ prendate = ' '; /* re-init */ majproj = ' '; /* re-init */ exec sql fetch cl into :projno, :projname, :deptno, :respemp, :prstaff :prstaff_ind, :prstdate :prstdate_ind, :prendate :prendate_ind, :majproj :majproj_ind;

put edit (projno, projname, deptno, respemp, prstaff, prstdate, prendate, majproj) (a(6),x,a(24),x,a(3),x,a(6),x,f(5,2),x,a(10),x,a(10),x,a(6)); put skip; end; return; err_label: msg_len = sqldb2err(200,0,sqlca,errmsg); put skip list(substr(errmsg,1,msg_len)); end sample1; Open PL/I DB2 SQL Sample 2 Program filename: sample2.sqp sample2: proc options(main); /* Sample program 2 /* Example of using a user defined SQLDA */ */

/* The database this program uses is the IBMSAMPL database that */ /* your DB2 product uses. You must be able to run the IBM DB2 */ /* demo sample program in order to be able to run this program */ /* Uses a table of the form: /* create table project /* (projno char(6) not null, /* projname varchar(24) not null, /* deptno char(3) not null, /* respemp char(6) not null, /* prstaff dec(5,2), /* prstdate date) dcl k fixed bin(15); exec sql include sqlca; exec sql include sqlda; exec sql begin declare section; dcl cnt fixed bin(15); exec sql end declare section; sqlsize 6; /* Lets only look at the 1st 6 columns */ allocate sqlda set(sqldapntr); /* sets sqln */ */ */ */ */ */ */ */ */

sqldaptr->sqld = 6; dcl projno char(6) based; sqldaptr->sqlda.sqlvar(1).sqltype = SQL_TYP_CHAR; allocate projno set(sqldaptr->sqlda.sqlvar(1).sqldata); sqldaptr->sqlda.sqlvar(1).sqllen = 6; dcl projname char(24) var based; saldaptr->sqlda.sqlvar(2).sqltype = SQL_TYP VARCHAR; allocate projname set(sqldaptr->sqlda.sqlvar(2).sqldata); sqldaptr->sqlda.sqlvar(2).sqllen = 24; dcl deptno char(3) based; sqldaptr->sqlda.sqlvar(3).sqltype = SQL_TYP_CHAR; allocate deptno set(sqldaptr->sqlda.sqlvar(3).sqldata); sqldaptr->sqlda.sqlvar(3).sqllen = 3; dcl respemp char(6) based; sqldaptr->sqlda.sqlvar(4).sqltype = SQL_TYP_CHAR; allocate respemp set(sqldaptr->sqlda.sqlvar(4).sqldata); sqldaptr->sqlda.sqlvar(4).sqllen = 6; dcl prstaff float(24) binary based; sqldaptr->sqlda.sqlvar(5).sqltype = SQL_TYP_FLOAT; allocate prstaff set(sqldaptr->sqlda.salvar(5).sqldata); sqldaptr->sqlda.sqlvar(5).sqllen = 8; dcl prstdate char(10) based; sqldaptr->sqlda.sqlvar(6).sqltype = SQL_TYP_CHAR; allocate prstdate set(sqldaptr->sqlda.sqlvar(6).sqldata); sqldaptr->sqlda.sqlvar(6).sqllen = 10; exec sql connect to IBMSAMPL; if SQLCA.SQLCODE < 0 THEN do; put skip list('Connect failed'); return; end; else put skip list('Connect OK'); put skip; exec sql whenever sqlerror goto err_label; put skip list('Projno Projname Dpt Respemp Prst Prstdate'); put skip; exec sql declare cl cursor for select * from project; exec sql open cl; exec sql whenever not found go to done;

do while ('1'b1); /* do till fetch raises not found error */ exec sql fetch c1 using descriptor :sqldaptr; put edit (sqldaptr->sqlda.sqlvar(1).sqldata->projno, sqldaptr->sqlda.sqlvar(2).sqldata->projname, sqldaptr->sqlda.sqlvar(3).sqldata->deptno, sqldaptr->sqlda.sqlvar(4).sqldata->respemp, sqldaptr->sqlda.sqlvar(5).sqldata->prstaff, sqldaptr->sqlda.sqlvar(6).sqldata->prstdate) (a(6),x,a(24),x,a(3),x,a(6),x,f(5,2),x,a(10)); put skip; end; done: exec sql whenever not found continue; /* turn off */ put skip; return; err_label: put skip list('Branched to err_label'); put skip list('sqlcode =', sqlcode); put skip list('sqlerrm =' , sqlerrm); put skip list('sqlstate =', sqlstate); return; end sample2; Output Connect OK Projno Projname Opt Respemp Prst Prstdate AD3100 ADMIN SERVICES D01 000010 6.50 01/01/1982 AD3110 GENERAL ADMIN SYSTEMS D21 000070 6.00 01/01/1982 AD3111 PAYROLL PROGRAMMING D21 000230 2.00 01/01/1982 AD3112 PERSONNEL PROGRAMMING D21 000250 1.00 01/01/1982 AD3113 ACCOUNT PROGRAMMING D21 000270 2.00 01/01/1982 1F1000 QUERY SERVICES CO1 000030 2.00 01/01/1982 1F2000 USER EDUCATION CO1 000030 1.00 01/01/1982 MA2100 WELD LINE AUTOMATION DO1 000010 12.00 01/01/1982 MA2110 W L PROGRAMMING D11 000060 9.00 01/01/1982 MA2111 W L PROGRAM DESIGN D11 000220 2.00 01/01/1982 MA2112 W L ROBOT DESIGN D11 000150 3.00 01/01/1982 MA2113 W L PROD CONT PROGS D11 000160 3.00 02/15/1982 OP1000 OPERATION SUPPORT E01 000050 6.00 01/01/1982 OP1010 OPERATION E11 000090 5.00 01/01/1982 OP2000 GEN SYSTEMS SERVICES E01 000050 5.00 01/01/1982 OP2010 SYSTEMS SUPPORT E21 000100 4.00 01/01/1982 OP2011 SCP SYSTEMS SUPPORT E21 000320 1.00 01/01/1982 0P2012 APPLICATIONS SUPPORT E21 000330 1.00 01/01/1982

0P2013 DB/DC SUPPORT E21 000340 1.00 01/01/1982 PL2100 WELD LINE PLANNING B01 000020 1.00 01/01/1982