// Source File Name: Stclient.java % // // Licensed Materials -- Property of IBM // // (c) Copyright International Business Machines Corporation, 1998, 2000. // All Rights Reserved. // // US Government Users Restricted Rights - // Use, duplication or disclosure restricted by // GSA ADP Schedule Contract with IBM Corp. // Sample Program Stclient - Client Application for Stored Procedure // To run this sample, perform the following steps: // (1) create and populate the SAMPLE database (db2sampl) // (2) compile Stserver (javac Stserver.java) // (3) copy Stserver.class to the sqllib/function directory // (4) register the stored procedures using the Spcreate.db2 CLP script: // (i) db2 connect to sample // (ii) db2 -td@ -vf Spcreate.db2 // (3) compile Stclient (javac Stclient.java) // (4) run Stclient (java Stclient) // NOTES: (1) The jdk11_path database manager configuration parameter must // be set on the server // (2) The CLASSPATH and shared library path environment variables // must be set, as for any JDBC application // (3) Visit http://www.software.ibm.com/data/db2/java // for current DB2 Java information // For more information about this sample, refer to the README file. // For more information on Programming in Java, refer to the // "Programming in Java" section of the Application Development Guide. // For more information on creating stored procedures, refer to the // "Writing Stored Procedures" section of the Application Development Guide. // For more information on building and running Java programs for DB2, // refer to the "Building Java Applets and Applications" section of the // Application Building Guide. // For more information on the SQL language, refer to the SQL Reference. // Stclient calls twelve methods that call stored procedures: // (1) callOutLanguage: returns language of the stored procedure library // Parameter types used: OUT CHAR(8) // (2) callOutParameter: return median salary of EMPLOYEE table // Parameter types used: OUT DOUBLE // OUT INTEGER // OUT CHAR(32) // (3) callInParameters: accept 3 values and update salaries in EMPLOYEE table // accordingly // Parameter types used: IN DOUBLE // IN CHAR(3) // OUT INTEGER // OUT CHAR(32) // (4) callIncallOutParameter: accept an input value and return the median // salary of the EMPLOYEE table for employees who make more // than the input value. Demonstrates how to use null indicators // in a client application. // Parameter style (C): GENERAL WITH NULLS // Parameter style (Java): JAVA // Parameter style (SQL): SQL // Parameter types used: INOUT DOUBLE // OUT INTEGER // OUT CHAR(32) // (5) callOneResultSet: return a result set to the client application // Parameter types used: IN DOUBLE // OUT INTEGER // (6) callTwoResultSets: return two result sets to the client application // Parameter types used: IN DOUBLE // OUT INTEGER // (7) callClobExtract: return a sub-section of a CLOB data type // Parameter types used: IN CHAR(6) // OUT VARCHAR(1000) // OUT INTEGER // (8) callDecimalType: pass and receive a DECIMAL data type from a // stored procedure // Parameter types used: INOUT DECIMAL // (9) callAllDataTypes: use all of the common data types in a stored procedure // Parameter types used: INOUT SMALLINT // INOUT INTEGER // INOUT BIGINT // INOUT REAL // INOUT DOUBLE // OUT CHAR(1) // OUT CHAR(15) // OUT VARCHAR(12) // OUT DATE // OUT TIME // (10) callDB2SQL: calls a DB2SQL parameter style stored procedure // Parameter style: DB2SQL // Parameter types used: IN CHAR(8) // OUT DOUBLE // (11) callDBINFO: calls a stored procedure that receives a DBINFO // structure and returns elements of the structure to the client // Parameter types used: IN CHAR(8) // OUT DOUBLE // OUT CHAR(128) // OUT CHAR(8) // OUT INTEGER // (12) callProgramTypeMain: calls a stored procedure implemented with // PROGRAM TYPE MAIN parameter passing style // Parameter types used: IN CHAR(8) // OUT DOUBLE import java.sql.*; // JDBC classes /* :rk.1:erk. */ import java.math.BigDecimal; // BigDecimal support for packed decimal type import sqlj.runtime.*; import sqlj.runtime.ref.*; class Stclient { static { try { System.out.println(); System.out.println("Java Stored Procedure Sample"); Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance(); } catch (Exception e) { System.out.println("\nError loading DB2 Driver...\n"); e.printStackTrace(); } } public static void main(String argv[]) { Connection con = null; // URL is jdbc:db2:dbname String url = "jdbc:db2:sample"; double outMedian = 0; String language = ""; try { if (argv.length == 0) { // connect to sample database // connect with default id/password con = DriverManager.getConnection(url); /* :rk.2:erk. */ } else if (argv.length == 2) { // connect to sample database // connect with user-provided username and password String userid = argv[0]; String passwd = argv[1]; con = DriverManager.getConnection(url, userid, passwd); } else if (argv.length == 3) { // connect to user-provided database url = "jdbc:db2:" + argv[2]; String userid = argv[0]; String passwd = argv[1]; // connect with user-provided username and password con = DriverManager.getConnection(url, userid, passwd); } else { System.out.println("\nUsage: java Stclient " + "[username password [database]]\n"); System.exit(0); } // Set the default context DefaultContext ctx = new DefaultContext(con); DefaultContext.setDefaultContext(ctx); // turn off autocommit con.setAutoCommit(false); /* :rk.3:erk. */ language = callOutLanguage(con); outMedian = callOutParameter(con); callInParameters(con); callInoutParameter(con, outMedian); // Cause the stored procedure to return a NOT FOUND error callInoutParameter(con, 99999.99); callOneResultSet(con, outMedian, ctx); callTwoResultSets(con, outMedian, ctx); // SQL procedures cannot handle LOB data types if (language.trim().equals("SQL")) { System.out.println("\nStored procedures are implemented in SQL,\n" + "which cannot handle LOB datatypes.\n" + "Skipping the call to CLOB_EXTRACT.\n"); } else if (language.trim().equals("C")) { /* Warn the user that the CLI stored procedure * requires a change to the UDF_MEM_SZ variable */ System.out.println( "\n\n If the CLOB EXTRACT stored procedure is implemented\n" + " using CLI, you must increase the value of the UDF_MEM_SZ\n" + " database manager configuration variable to at least two\n" + " pages larger than the size of the input arguments and\n" + " the result of the stored procedure. To do this, issue\n" + " the following command from the CLP:\n" + " db2 UPDATE DBM CFG USING UDF_MEM_SZ 2048\n" + " For the change to take effect, you must then stop and\n" + " restart the DB2 server by issuing the following\n" + " commands from the CLP:\n" + " db2stop\n" + " db2start"); callClobExtract("000140", con); } else if (language.trim().equals("JAVA")) { callClobExtract("000140", con); } // Java and SQL procedures can handle DECIMAL data types if (language.trim().equals("SQL") || language.trim().equals("JAVA")) { callDecimalType(con); } else if (language.trim().equals("C")) { // C does not provide a native data type for decimal // values, so neither a C client application nor a // C stored procedure can pass DECIMAL SQL data types. // // Do not call the DECIMAL_TYPE stored procedure, // because the stored procedure is written in C. } callAllDataTypes(con); // the following stored procedures can only be implemented in C/C++ if (language.trim().equals("C")) { callDB2SQL("CLERK", con); callDB2SQL("", con); callDBINFO("MANAGER", con); callProgramTypeMain("DESIGNER", con); } // roll back any changes to the database con.rollback(); /* :rk.8:erk. */ con.close(); } catch (Exception e) { try { con.rollback(); con.close(); } catch (Exception x) { } e.printStackTrace (); } } // end main public static String callOutLanguage(Connection con) throws SQLException { String out_lang = ""; try { String procName = "OUT_LANGUAGE"; System.out.println ("\nCall stored procedure named " + procName); #sql { CALL OUT_LANGUAGE (:out out_lang) }; System.out.println ("Stored procedures are implemented in language " + out_lang); } catch (SQLException sqle) { System.out.println(sqle); } return(out_lang); } public static double callOutParameter(Connection con) throws SQLException { double median = 0; try { int outErrorCode = 0; String outErrorLabel = ""; String procName = "OUT_PARAM"; // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); #sql { CALL OUT_PARAM(:out median, :out outErrorCode, :out outErrorLabel) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println ("Median salary returned from " + procName + " = " + median); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println(procName + " failed at " + outErrorLabel); } } catch (SQLException sqle) { System.out.println(sqle); } return(median); } public static void callInParameters(Connection con) throws SQLException { double sumSalary, inSalary1, inSalary2, inSalary3; int outErrorCode = 0; String outErrorLabel = ""; String inDept; try { // prepare the CALL statement for IN_PARAMS String procName = "IN_PARAMS"; inDept = "E11"; // Display total salary before calling IN_PARAMS #sql { SELECT SUM(salary) INTO :sumSalary FROM employee WHERE workdept = :inDept }; System.out.println("\nSum of salaries for dept. E11 = " + sumSalary + " before " + procName); // call the stored procedure inSalary1 = 15000; inSalary2 = 20000; inSalary3 = 25000; System.out.println ("\nCall stored procedure named " + procName); #sql { CALL IN_PARAMS (:in inSalary1, :in inSalary2, :in inSalary3, :in inDept, :outErrorCode, :out outErrorLabel) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); // Display total salary after calling IN_PARAMS #sql { SELECT SUM(salary) INTO :sumSalary FROM employee WHERE workdept = :inDept }; System.out.println("\nSum of salaries for dept. E11 = " + sumSalary + " after " + procName); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println(procName + " failed at " + outErrorLabel.trim()); } } catch (SQLException sqle) { System.out.println(sqle); } } public static void callInoutParameter(Connection con, double median) throws SQLException { double inoutMedian; int outErrorCode = 0; String outErrorLabel = ""; try { String procName = "INOUT_PARAM"; inoutMedian = median; // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); if (median == 99999.99) { System.out.println("with an input value that causes a NOT FOUND error"); } #sql { CALL INOUT_PARAM(:inout inoutMedian, :out outErrorCode, :out outErrorLabel) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println("Median salary returned from " + procName + " = " + inoutMedian); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println(procName + " failed at " + outErrorLabel.trim()); } } catch (SQLException sqle) { System.out.println(sqle); } } public static void callOneResultSet(Connection con, double median, DefaultContext ctx) throws SQLException { int outErrorCode = 0; ResultSet rs; ExecutionContext execCtx = ctx.getExecutionContext(); // prepare the CALL statement for ONE_RESULT_SET String procName = "ONE_RESULT_SET"; // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); #sql { CALL ONE_RESULT_SET (:in median, :out outErrorCode) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); if ((rs = execCtx.getNextResultSet()) != null) { fetchAll(rs); // close ResultSet rs.close(); } } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); } } public static void callTwoResultSets(Connection con, double median, DefaultContext ctx) throws SQLException { int outErrorCode = 0; ResultSet rs; ExecutionContext execCtx = ctx.getExecutionContext(); // prepare the CALL statement for TWO_RESULT_SETS String procName = "TWO_RESULT_SETS"; // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); #sql { CALL TWO_RESULT_SETS (:in median, :out outErrorCode) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); if ((rs = execCtx.getNextResultSet()) != null) { System.out.println("Result set 1: Employees who make more than " + median); fetchAll(rs); } if ((rs = execCtx.getNextResultSet()) != null) { System.out.println("\nResult set 2: Employees who make less than " + median); fetchAll(rs); // close ResultSet rs.close(); } } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); } } public static void callClobExtract(String empNo, Connection con) { String inEmpNo, outInterests; int outErrorCode = 0; inEmpNo = empNo; try { String procName = "CLOB_EXTRACT"; // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); #sql { CALL CLOB_EXTRACT (:in inEmpNo, :out outInterests, :out outErrorCode) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println ("Resume section returned for employee " + inEmpNo + " =\n" + outInterests); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println("from procedure section labelled " + outInterests); } } catch (SQLException e) { System.out.println(e); } } public static void callDecimalType(Connection con) { int outErrorCode = 0; String outErrorLabel = ""; try { String procName = "DECIMAL_TYPE"; // declare and initialize input variable BigDecimal inoutDecimal = new BigDecimal("400000.00"); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); #sql { CALL DECIMAL_TYPE (:inout inoutDecimal, :out outErrorCode, :out outErrorLabel) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println("Value of DECIMAL = " + inoutDecimal); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println(" from procedure section labelled " + outErrorLabel); } } catch (SQLException e) { System.out.println(e); } } public static void callAllDataTypes(Connection con) { int outErrorCode = 0; String outErrorLabel = ""; try { String procName = "ALL_DATA_TYPES"; // declare and initialize input variables short inoutSmallint = 32000; int inoutInteger = 2147483000; long inoutBigint = 2147480000; float inoutReal = 100000; double inoutDouble = 2500000; // declare output variables String outChar, outChars, outVarchar; Date outDate; Time outTime; // CALL stored procedure ALL_DATA_TYPES System.out.println ("\nCall stored procedure named " + procName); #sql { CALL ALL_DATA_TYPES (:inout inoutSmallint, :inout inoutInteger, :inout inoutBigint, :inout inoutReal, :inout inoutDouble, :out outChar, :out outChars, :out outVarchar, :out outDate, :out outTime, :out outErrorCode, :out outErrorLabel) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println("Value of SMALLINT = " + inoutSmallint); System.out.println("Value of INTEGER = " + inoutInteger); System.out.println("Value of BIGINT = " + inoutBigint); System.out.println("Value of REAL = " + inoutReal); System.out.println("Value of DOUBLE = " + inoutDouble); System.out.println("Value of CHAR(1) = " + outChar); System.out.println("Value of CHAR(15) = " + outChars.trim()); System.out.println("Value of VARCHAR(12) = " + outVarchar.trim()); System.out.println("Value of DATE = " + outDate); System.out.println("Value of TIME = " + outTime); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println(" from procedure section labelled " + outErrorLabel); } } catch (SQLException e) { System.out.println(e); } } public static void callDB2SQL(String job, Connection con) { try { double median = 0; String inJob; inJob = job; String procName = "DB2SQL_EXAMPLE"; // CALL stored procedure DB2SQL_EXAMPLE System.out.println ("\nCall stored procedure named " + procName); #sql { CALL DB2SQL_EXAMPLE (:in inJob, :out median) }; System.out.println(procName + " completed successfully"); System.out.println ("Median salary returned from " + procName + " = " + median); } catch (SQLException e) { // Note that the JDBC specification only allows us to // get the SQLSTATE as a method called on an instance of // an SQLException. If you call DB2SQL_EXAMPLE with // null input, so that the stored procedure returns the // custom SQLSTATE ('38100') and message, the Java client // considers it a successful call because the returned SQLCODE = 0 // and an SQLException is not raised. System.out.println(e); } } public static void callDBINFO(String job, Connection con) throws SQLException { double averageSalary = 0; int outErrorCode = 0; String inJob, databaseName, databaseVersion; String procName = "DBINFO_EXAMPLE"; inJob = job; // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); #sql {CALL DBINFO_EXAMPLE (:in inJob, :out averageSalary, :out databaseName, :out databaseVersion, :out outErrorCode) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println ("Average salary for job " + inJob + " = " + averageSalary); System.out.println("Database name from DBINFO structure = " + databaseName.trim()); System.out.println("Database version from DBINFO structure = " + databaseVersion.trim()); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); } } public static void callProgramTypeMain(String job, Connection con) throws SQLException { String inJob; double averageSalary = 0; int outErrorCode = 0; inJob = job; String procName = "MAIN_EXAMPLE"; // call stored procedure MAIN_EXAMPLE System.out.println ("\nCall stored procedure named " + procName); #sql { CALL MAIN_EXAMPLE (:in inJob, :out averageSalary, :out outErrorCode) }; if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println ("Average salary for job " + inJob + " = " + averageSalary); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); } } // ====================================================== // Method: fetchAll -- returns all rows from a result set // ====================================================== public static void fetchAll( ResultSet rs ) { try { System.out.println("================================================================="); ResultSetMetaData stmtInfo = rs.getMetaData(); int numOfColumns = stmtInfo.getColumnCount(); int r = 0; while( rs.next() ) { r++; System.out.print("Row: " + r + ": "); for( int i=1; i <= numOfColumns; i++ ) { System.out.print(rs.getString(i)); if( i != numOfColumns ) System.out.print(" , "); } System.out.println(""); } } catch (SQLException e) { System.out.println("Error: fetchALL: exception"); System.out.println (e); } } }