Skip to main content

 
IBM Power Systems software  >  IBM i  > Software  > 

Net.Data for i5/OS

  
Overview News Library Education Support
Calling Stored Procedures via Net.Data

Net.Data for i5/OS now supports stored procedure calls. And the support has been made available in V3R2, V3R7 and subsequent releases.

A stored procedure is a programming construct that can be called to perform a set of operations. The operations can contain host language statements (e.g. C, RPG, COBOL, CL, etc.) and SQL statements.

Stored procedures are typically classified as either SQL stored procedures or external stored procedures. SQL stored procedures contain only SQL statements. External stored procedures reference a host language program which may or may not contain SQL statements. Support for external stored procedures has been available since V3R1, while support for SQL stored procedures was added in V4R2.

Advantages of Stored Procedures
Net.Data now supports direct two way passing of macro variables as parameters to stored procedures. This enables you to call any of your existing stored procedures, without modification, via Net.Data. The datatypes of stored procedure parameters can be any of the datatypes supported by SQL for i5/OS. If an INOUT or OUT type parameter is updated by the stored procedure, the Net.Data macro variable that represents that parameter will reflect that change when the DTW_SQL LE function ends.

The main advantage derived by using a stored procedure is performance. Particularly if it is used to perform complex SQL operations. Here is a list of a few of the benefits:

  • Access Plans required by i5/OS to access records in a physical file (rows in an SQL table) must be built each time a normal DTW_SQL LE function is called. This is due to the dynamic nature of Net.Data. Because of the nature of stored procedures, access plans are built when the program is compiled and then saved with the program object. You pay the onetime cost of building the access plan when the program is compiled, and then reuse it whenever the program is called. This can result in substantial performance benefits.
  • Assuming that your stored procedures do contain embedded SQL statements, a single Net.Data DTW_SQL LE function call can now execute many SQL statements. This has several ramifications. You can use the program logic of your high level language to determine what should be done; which file(s) need to be updated, which and how many records to alter, when to commit or rollback a change, produce multiple result sets that will be placed in INOUT or OUT type Net.Data Table variables that were passed to the DTW_SQL LE function.
  • Connecting to a remote system on which the stored procedure exists and is identified to SQL for i5/OS, you can now dramatically decrease the communications line usage by issuing a single request to execute that stored procedure rather than multiple individual requests to accomplish the same amount of work.

Example 1
Here is a macro that calls a stored procedure written in PL1 which produces multiple result sets:

  %{***********************************************************
  /*   DEFINE BLOCK
  /************************************************************%}
 %DEFINE  {
   MACRO_NAME         = "TEST 5 TABLES RETURNED"
   DTW_HTML_TABLE     = "YES"
   DTW_DEFAULT_REPORT = "NO"
   NUM_TABLES         = ""
   Procedure          = "SILBER.RSMLTCS"
   TABLE01            = %TABLE(0)
   TABLE02            = %TABLE(0)
   TABLE03            = %TABLE(0)
   TABLE04            = %TABLE(0)
   TABLE05            = %TABLE(0)
   TABLE06            = %TABLE(0)
 %}

 %FUNCTION(DTW_SYSTEM) CRTSQLPLI(){
  %EXEC{/QSYS.lib/CRTSQLPLI.CMD PGM(SILBER/RSMLTCS)
                                SRCFILE(SILBER/PLISRC)
                                SRCMBR(RSMLTCS)
                                CLOSQLCSR(*ENDJOB)
  %}
  %MESSAGE{
     default : "$(DTW_DEFAULT_MESSAGE) : continuing.
": continue %} %} %FUNCTION(DTW_SQL) CRTPROC(){ CREATE PROCEDURE $(Procedure) () EXTERNAL NAME $(Procedure) LANGUAGE PLI SIMPLE CALL %MESSAGE{ default : "$(DTW_DEFAULT_MESSAGE) : continuing.
": continue %} %} %{ This stored procedure actally only builds 6 tables... table06 test the LE's ability to ignore excess table parms %} %FUNCTION(DTW_SQL) myProc (OUT table01,table02,table03,table04,table05,table06){ CALL $(Procedure) %} %FUNCTION(DTW_SQL) DROP_PROC(){ DROP PROCEDURE $(Procedure) %} %{ Display a table with the default report format %} %MACRO_FUNCTION showTable(INOUT table){ %} %HTML(drop) { @DROP_PROC() %} %HTML(create) { Net.Data : Stored Procedure: Example '$(MACRO_NAME)'. </HEAD> <BODY BGCOLOR="#BBFFFF" TEXT="#000000" LINK="#000000"> <p><p> Calling the system function to create the stored procedure PL1 program. <p><p> @CRTSQLPLI() <p><p> Calling the function to create the stored procedure. <p><p> @CRTPROC() <hr> %} %HTML(report) { <HEAD> <TITLE>Net.Data : Stored Procedure: Example '$(MACRO_NAME)'. </HEAD> <BODY BGCOLOR="#BBFFFF" TEXT="#000000" LINK="#000000"> <h2> Calling the function that will execute the stored procedure. </h2> <p><p> @myProc(TABLE01,TABLE02,TABLE03,TABLE04,TABLE05,TABLE06) <hr> <h2> Values of the all tables produced by this stored procedure call. </h2> @DTW_ASSIGN(DTW_DEFAULT_REPORT,"YES") @showTable(TABLE01) <hr> @showTable(TABLE02) <hr> @showTable(TABLE03) <hr> @showTable(TABLE04) <hr> @showTable(TABLE05) <hr> @showTable(TABLE06) <hr> $(NUM_TABLES) tables were returned by the DTW_SQL function myProc(). </body> %} ****************** End of data **************************************** </pre> <p>Here is the PL1 source code for the stored procedure "SILBER.RSMLTCS":</p> <pre > *************** Beginning of data ************************************* RSMLTCS:PROC; EXEC SQL INCLUDE SQLCA; dcl stmt char(100); dcl col2 fixed bin(31); dcl col3 char(17); dcl col1 char (17); EXEC SQL DECLARE C00 CURSOR FOR select * from SILBER/RSMLTCS00; EXEC SQL DECLARE C01 CURSOR FOR select * from SILBER/RSMLTCS01; EXEC SQL DECLARE C02 CURSOR FOR select * from SILBER/RSMLTCS02; EXEC SQL DECLARE C03 CURSOR FOR select * from SILBER/RSMLTCS03; EXEC SQL DECLARE C04 CURSOR FOR select * from SILBER/RSMLTCS04; EXEC SQL DECLARE C05 CURSOR FOR select * from SILBER/RSMLTCS05; EXEC SQL OPEN C00; EXEC SQL OPEN C01; EXEC SQL OPEN C02; EXEC SQL OPEN C03; EXEC SQL OPEN C04; EXEC SQL OPEN C05; EXEC SQL SET RESULT SETS CURSOR C00, CURSOR C01, CURSOR C02, CURSOR C03, CURSOR C04, CURSOR C05; END RSMLTCS; ****************** End of data **************************************** </pre> <hr/> <p> <b>Example 2</b> <br clear="none"/> Here is a macro that calls a stored procedure written in C which contains no embedded SQL, but demonstates passing parameters of various datatypes: </p> <pre > *************** Beginning of data ************************************* %{*********************************************************** /* DEFINE BLOCK /************************************************************%} %DEFINE { MACRO_NAME = "TEST ALL TYPES" DTW_HTML_TABLE = "YES" Procedure = "SILBER.TESTTYPE" parm1 = "1" %{SMALLINT %} parm2 = "11" %{INT %} parm3 = "1.1" %{DECIMAL (2,1) %} parm4 = "1" %{REAL %} parm5 = "1" %{DOUBLE PRECISION %} parm6 = "1" %{CHAR(2) %} parm7 = "this is varchar*19" %{VARCHAR(20) %} parm8 = "1993-12-31" %{DATE %} parm9 = "11.59.59" %{TIME %} parm10 = "1993-12-31-11.59.59.000000" %{TIMESTAMP %} %} %FUNCTION(DTW_SQL) CRTPROC(){ CREATE PROCEDURE $(Procedure) (INOUT SMALLINT, INOUT INT, INOUT DECIMAL(2,1), INOUT REAL, INOUT DOUBLE PRECISION, INOUT CHAR(2), INOUT VARCHAR(20), INOUT DATE, INOUT TIME, INOUT TIMESTAMP) EXTERNAL NAME $(Procedure) LANGUAGE C SIMPLE CALL %MESSAGE{ default : "$(DTW_DEFAULT_MESSAGE) : continuing.<br>": continue %} %} %FUNCTION(DTW_SQL) myProc (INOUT SMALLINT parm1, INOUT INT parm2, INOUT DECIMAL(2,1) parm3, INOUT REAL parm4, INOUT DOUBLEPRECISION parm5, INOUT CHAR(2) parm6, INOUT VARCHAR(20) parm7, INOUT DATE parm8, INOUT TIME parm9, INOUT TIMESTAMP parm10){ CALL $(Procedure) %} %FUNCTION(DTW_SQL) DROP_PROC(){ DROP PROCEDURE $(Procedure) %} %HTML(create) { <HEAD> <TITLE>Net.Data : Stored Procedure: Example '$(MACRO_NAME)'. </HEAD> <BODY BGCOLOR="#BBFFFF" TEXT="#000000" LINK="#000000"> <p><p> Calling the function to create the stored procedure. <p><p> @CRTPROC() <hr> %} %HTML(drop) { @DROP_PROC() %} %HTML(REPORT) { <HEAD> <TITLE>Net.Data : Stored Procedure: Example '$(MACRO_NAME)'. </HEAD> <BODY BGCOLOR="#BBFFFF" TEXT="#000000" LINK="#000000"> <h2> Values of the INOUT parameters prior to calling the stored procedure: </h2> <b>parm1 (SMALLINT)</b><br> $(parm1)<p> <b>parm2 (INT)</b><br> $(parm2)<p> <b>parm3 (DECIMAL)</b><br> $(parm3)<p> <b>parm4 (REAL)</b><br> $(parm4)<p> <b>parm5 (DOUBLE PRECISION)</b><br> $(parm5)<p> <b>parm6 (CHAR(2))</b><br> $(parm6)<p> <b>parm7 (VARCHAR(20))</b><br> $(parm7)<p> <b>parm8 (DATE)</b><br> $(parm8)<p> <b>parm9 (TIME)</b><br> $(parm9)<p> <b>parm10 (TIMESTAMP)</b><br> $(parm10)<p> <p> <hr> <h2> Calling the function that will execute the stored procedure. </h2> <p><p> @myProc(parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) <hr> <h2> Values of the INOUT parameters after to calling the stored procedure: </h2> <b>parm1 (SMALLINT)</b><br> $(parm1)<p> <b>parm2 (INT)</b><br> $(parm2)<p> <b>parm3 (DECIMAL)</b><br> $(parm3)<p> <b>parm4 (REAL)</b><br> $(parm4)<p> <b>parm5 (DOUBLE PRECISION)</b><br> $(parm5)<p> <b>parm6 (CHAR(2))</b><br> $(parm6)<p> <b>parm7 (VARCHAR(20))</b><br> $(parm7)<p> <b>parm8 (DATE)</b><br> $(parm8)<p> <b>parm9 (TIME)</b><br> $(parm9)<p> <b>parm10 (TIMESTAMP)</b><br> $(parm10)<p> </body> %} ****************** End of data **************************************** </pre> <p>Here is the C source code for the stored procedure "SILBER.TESTTYPE":</p> <pre > /**** START OF SPECIFICATIONS **************************************/ /* ------------------------------------------------------------------*/ /* This external procedure is invoked by the SQL CALL statement. */ /* Data received is verified,changed, and passed back to be */ /* verified by the calling pgm. verified */ /*-------------------------------------------------------------------*/ /**** END OF SPECIFICATIONS ****************************************/ #include <stdio.h> /* standard I/O functions */ #include <stdlib.h> /* standard library */ #include <string.h> /* incl. strg fnctns. */ #include <wcstr.h> #include <decimal.h> char varname [11] = "**********"; /* variation name */ char passfail [2] = "F"; /* pass or fail of variation */ char errmsg [81] = " "; /* error message for fail */ char testname [11] = "CLL104C "; /* test case name */ char sqlstmt [41] = "????????? ";/* sql commamd descrpt'n/ID */ char lib [11] = "SQTEST "; /* collection for report */ char file [11] = "CALLRESULT"; int liblen = 8; /* length of library name */ int filelen = 10; /* length of file name */ char expcode [6] = "****"; /* expected sqlcode */ char expstate [6] = "*****"; /* expected sqlstate */ /* */ /*-------------------------------------------------------------------*/ main(int argc, char *argv[]) /* */ { /* data type: */ short hvsmlint; /*SMALLINT */ long hvint; /*INTEGER */ _Decimal(2,1) hvdec; /*DECIMAL */ float hvreal; /*REAL */ double hvdblpre; /*DOUBLE PRECISION */ char hvchar[2]; /*CHARACTER */ char varchar??(20??); char hvdate[11]; /*DATE */ char hvtime[9]; /*TIME */ char hvtmstmp[27]; /*TIMESTAMP */ /* assign incoming arguments */ hvsmlint = *(short *) argv[1]; hvint = *(long *) argv[2]; hvdec = *(_Decimal(2,1) *) argv[3]; hvreal = *(float *) argv[4]; hvdblpre = *(double *) argv[5]; strcpy(hvchar,argv[6]); strcpy(varchar,argv??(7??)); strcpy(hvdate,argv[8]); strcpy(hvtime,argv[9]); strcpy(hvtmstmp,argv[10]); /* Verify values of incoming arguments */ printf("<H3>values received in stored procedure TestType.c:</H3>"); /*** SHORT INT ***/ printf("<hr>"); printf("<p>"); printf("hvsmlint is %d<p>",hvsmlint); if (hvsmlint != 1) printf("failed 1nd param<p>"); else printf("passed param 1<p>"); /*** LONG INT ***/ printf("<hr>"); printf("hvint is %d<p>",hvint); if (hvint != 11) printf("failed 2nd param<p>"); else printf("passed 2nd param<p>"); /*** DECIMAL ***/ printf("<hr>"); if (hvdec != 1.1) { printf("hvdec is incorrect<p>"); printf("failed 3rd param<p>"); } else { printf("hvdec is 1.1<p>"); printf("passed 3rd param<p>"); } /*** REAL ***/ printf("<hr>"); printf("hvreal is %f<p>",hvreal); if (hvreal != 1) printf("failed 4th param<p>"); else printf("passed 4th param<p>"); /*** DOUBLE PRECISION ***/ printf("<hr>"); printf("hvdblpre is %e<p>",hvdblpre); if (hvdblpre != 1) printf("failed 5th param<p>"); else printf("passed 5th param<p>"); /*** CHARACTER ***/ printf("<hr>"); printf("hvchar is %s<p>",hvchar); if strncmp(hvchar,"1",1) printf("failed 6th param<p>"); else printf("passed 6th param<p>"); /*** VARCHAR data ***/ printf("<hr>"); printf("varchar data is: %s<p>",varchar); if strncmp(varchar,"this is varchar*19",18) printf("failed 7th param<p>"); else printf("passed 7th param<p>"); /*** DATE ***/ printf("<hr>"); printf("hvdate is %s<p>",hvdate); if (!strcmp(hvdate,"1993-12-31") == 0) printf("failed 8th param<p>"); else printf("passed 8th param<p>"); /*** TIME ***/ printf("<hr>"); printf("hvtime is %s<p>",hvtime); if (!strcmp(hvtime,"11.59.59") == 0) printf("failed 9th param<p>"); else printf("passed 9th param<p>"); /*** TIMESTAMP ***/ printf("<hr>"); printf("hvtmstmp is %s<p>",hvtmstmp); if (!strcmp(hvtmstmp,"1993-12-31-11.59.59.000000") == 0) printf("failed 10th param<p>"); else printf("passed 10th param<p>"); /* change the values of the parameters. */ hvsmlint = 2; hvint = 22; hvdec = 2.2; hvreal = 2; hvdblpre = 2; strcpy(hvchar,"2\0"); strcpy (varchar,"this is varchar*20\0"); strcpy(hvdate,"1994-01-01"); strcpy(hvtime,"12.00.00"); strcpy(hvtmstmp,"1994-01-01-12.00.00.999999"); /* assign outgoing arguments */ *(short *) argv[1] = hvsmlint; *(long *) argv[2] = hvint; *(_Decimal(2,1) *) argv[3] = hvdec; *(float *) argv[4] = hvreal; *(double *) argv[5] = hvdblpre; strncpy(argv[6],hvchar,1); strncpy(argv??(7??),varchar,20); strcpy(argv[8],hvdate); strcpy(argv[9],hvtime); strcpy(argv[10],hvtmstmp); } ****************** End of data **************************************** </pre> <p> </p> </td> </tr> </table> <!-- END BODY CONTENT --> <!-- BEGIN RATE THIS PAGE IN BODY --> <!-- END RATE THIS PAGE IN BODY --> <br /> <!-- BEGIN FOOTNOTES--> <!-- BEGIN FOOTNOTES --> <!-- END FOOTNOTES--> <!-- END FOOTNOTES--> </td><td width="7"> </td> <td width="150" id="right-nav"> <!-- BEGIN CONTACT INFO CALLOUT --> <!-- END CONTACT INFO CALLOUT --> <!-- BEGIN RATE THIS PAGE CALLOUT --> <!-- END RATE THIS PAGE CALLOUT --> <!-- BEGIN RIGHT HAND CALLOUTS --> <br> <!-- END RIGHT HAND CALLOUTS --> </td> </tr> </table> </td></tr> </table> </td></tr> </table> <!-- BEGIN WEB LISTENING POST SURVEY --> <!-- END WEB LISTENING POST SURVEY --> <!-- BEGIN FOOTER --> <div id="ibm-page-tools"> <!-- IBM page tools --> </div> <div id="ibm-footer"> <ul> <li class="ibm-first"><a href="http://www.ibm.com/ibm/us/en/" >About IBM</a></li> <li><a href="http://www.ibm.com/privacy/us/en/" >Privacy</a></li> <li><a href="http://www.ibm.com/contact/us/en/" >Contact</a></li> <li><a href="http://www.ibm.com/legal/us/en/" >Terms of use</a></li> </ul> </div> </div> <!-- END FOOTER --> <!-- BEGIN SURFAID--> <script language="JavaScript1.2" src="//www.ibm.com/common/stats/stats.js" type="text/javascript"></script> <noscript></noscript> <!-- END SURFAID --> </body> </html>