// Source File Name: Spclient.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 Spclient - Client Application for Stored Procedure // To run this sample, perform the following steps: // (1) create and populate the SAMPLE database (db2sampl) // (2) compile Spserver (javac Spserver.java) // (3) copy Spserver.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 Spclient (javac Spclient.java) // (4) run Spclient (java Spclient) // 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. // Spclient 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 class Spclient { static double outMedian = 0; 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"; 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 Spclient " + "[username password [database]]\n"); System.exit(0); } // turn off autocommit con.setAutoCommit(false); /* :rk.3:erk. */ language = callOutLanguage(con); callOutParameter(con); callInParameters(con); callInoutParameter(con, outMedian); callInoutParameter(con, 99999.99); callOneResultSet(con); callTwoResultSets(con); // 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")) { 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); 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) { String outLang = ""; try { // prepare the CALL statement for OUT_LANGUAGE String procName = "OUT_LANGUAGE"; String sql = "CALL " + procName + "(?)"; CallableStatement callStmt = con.prepareCall(sql); // register the output parameter callStmt.registerOutParameter (1, Types.CHAR); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve output parameters outLang = callStmt.getString(1); System.out.println ("Stored procedures are implemented in language " + outLang); } catch (SQLException e) { System.out.println(e); } return(outLang); } public static void callOutParameter(Connection con) { try { // prepare the CALL statement for OUT_PARAM String procName = "OUT_PARAM"; String sql = "CALL " + procName + "(?, ?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // register the output parameter /* :rk.4:erk. */ callStmt.registerOutParameter (1, Types.DOUBLE); callStmt.registerOutParameter (2, Types.INTEGER); callStmt.registerOutParameter (3, Types.CHAR); // call the stored procedure /* :rk.5:erk. */ System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve output parameters /* :rk.6:erk. */ outMedian = callStmt.getDouble(1); int outErrorCode = callStmt.getInt(2); String outErrorLabel = callStmt.getString(3); if (outErrorCode == 0) /* :rk.7:erk. */ { System.out.println(procName + " completed successfully"); System.out.println ("Median salary returned from " + procName + " = " + outMedian); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println(procName + " failed at " + outErrorLabel); } } catch (SQLException e) { System.out.println(e); } } public static void callInParameters(Connection con) throws SQLException { try { // prepare the CALL statement for IN_PARAMS String procName = "IN_PARAMS"; String sql = "CALL " + procName + "(?, ?, ?, ?, ?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // Display total salary before calling IN_PARAMS String query = "SELECT SUM(salary) FROM employee WHERE workdept = ?"; PreparedStatement queryStmt = con.prepareStatement(query); queryStmt.setString(1, "E11"); ResultSet queryRS = queryStmt.executeQuery(); queryRS.next(); double sumSalary = queryRS.getDouble(1); queryRS.close(); System.out.println("\nSum of salaries for dept. E11 = " + sumSalary + " before " + procName); // register the output parameters callStmt.registerOutParameter (5, Types.INTEGER); callStmt.registerOutParameter (6, Types.CHAR); // set input parameters callStmt.setDouble (1, 15000); callStmt.setDouble (2, 20000); callStmt.setDouble (3, 25000); callStmt.setString (4, "E11"); // initialize output parameters callStmt.setInt (5, 0); callStmt.setString (6, ""); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve output parameters int outErrorCode = callStmt.getInt(5); String outErrorLabel = callStmt.getString(6); if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); // Display total salary after calling IN_PARAMS queryRS = queryStmt.executeQuery(); queryRS.next(); sumSalary = queryRS.getDouble(1); queryRS.close(); System.out.println("Sum of salaries for dept. E11 = " + sumSalary + " after " + procName); queryStmt.close(); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println(procName + " failed at " + outErrorLabel.trim()); } } catch (SQLException e) { /* Roll back any UPDATE statements issued before the SQLException */ con.rollback(); System.out.println(e); } } public static void callInoutParameter(Connection con, double median) { try { // prepare the CALL statement for INOUT_PARAM String procName = "INOUT_PARAM"; String sql = "CALL " + procName + "(?, ?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // set input parameter to median value passed back by OUT_PARAM callStmt.setDouble (1, median); // register the output parameters callStmt.registerOutParameter (1, Types.DOUBLE); callStmt.registerOutParameter (2, Types.INTEGER); callStmt.registerOutParameter (3, Types.CHAR); // 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"); } callStmt.execute(); // retrieve output parameters double inoutMedian = callStmt.getDouble(1); int outErrorCode = callStmt.getInt(2); String outErrorLabel = callStmt.getString(3); 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 e) { System.out.println(e); } } public static void callOneResultSet(Connection con) { try { // prepare the CALL statement for ONE_RESULT_SET String procName = "ONE_RESULT_SET"; String sql = "CALL " + procName + "(?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // set input parameter to median value passed back by OUT_PARAM callStmt.setDouble (1, outMedian); // register the output parameter callStmt.registerOutParameter (2, Types.INTEGER); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve output parameter int outErrorCode = callStmt.getInt(2); if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); ResultSet rs = callStmt.getResultSet(); while (rs.next()) { fetchAll(rs); } // close ResultSet rs.close(); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); } } catch (SQLException e) { System.out.println(e); } } public static void callTwoResultSets(Connection con) { try { // prepare the CALL statement for TWO_RESULT_SETS String procName = "TWO_RESULT_SETS"; String sql = "CALL " + procName + "(?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // set input parameter to median value passed back by OUT_PARAM callStmt.setDouble (1, outMedian); // register the output parameter callStmt.registerOutParameter (2, Types.INTEGER); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve output parameter int outErrorCode = callStmt.getInt(2); if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println("Result set 1: Employees who make more than " + outMedian); // get first result set ResultSet rs = callStmt.getResultSet(); while (rs.next()) { fetchAll(rs); } System.out.println("\nResult set 2: Employees who make less than " + outMedian); // get second result set callStmt.getMoreResults(); rs = callStmt.getResultSet(); while (rs.next()) { fetchAll(rs); } // close ResultSet rs.close(); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); } } catch (SQLException e) { System.out.println(e); } } public static void callClobExtract(String empNo, Connection con) { String outInterests; try { // prepare the CALL statement for CLOB_EXTRACT String procName = "CLOB_EXTRACT"; String sql = "CALL " + procName + "(?, ?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // set input parameter to median value passed back by OUT_PARAM callStmt.setString (1, empNo); // register the output parameters callStmt.registerOutParameter (2, Types.VARCHAR); callStmt.registerOutParameter (3, Types.INTEGER); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve output parameters outInterests = callStmt.getString(2); int outErrorCode = callStmt.getInt(3); if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println ("Resume section returned for employee " + empNo + "=\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) { try { // prepare the CALL statement for ALL_DATA_TYPES String procName = "DECIMAL_TYPE"; String sql = "CALL " + procName + "(?, ?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // declare and initialize input variable BigDecimal inoutDecimal = new BigDecimal("400000.00"); // set input parameter callStmt.setBigDecimal (1, inoutDecimal); // register the output parameters callStmt.registerOutParameter (1, Types.DECIMAL, 2); callStmt.registerOutParameter (2, Types.INTEGER); callStmt.registerOutParameter (3, Types.CHAR); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve SQLCODE output parameter int outErrorCode = callStmt.getInt(2); if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); // retrieve output parameters inoutDecimal = callStmt.getBigDecimal(1,2); System.out.println("Value of DECIMAL = " + inoutDecimal); } else { // stored procedure failed String outErrorLabel = callStmt.getString(3); System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println(" from procedure section labelled " + outErrorLabel); } callStmt.close (); } catch (SQLException e) { System.out.println(e); } } public static void callAllDataTypes(Connection con) { try { // prepare the CALL statement for ALL_DATA_TYPES String procName = "ALL_DATA_TYPES"; String sql = "CALL " + procName + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // declare and initialize input variables short inoutSmallint = 32000; int inoutInteger = 2147483000; long inoutBigint = 2147483000; float inoutReal = 100000; double inoutDouble = 2500000; // declare output variables String outChar, outChars, outVarchar; Date outDate; Time outTime; // set input parameters callStmt.setShort (1, inoutSmallint); callStmt.setInt (2, inoutInteger); callStmt.setLong (3, inoutBigint); callStmt.setFloat (4, inoutReal); callStmt.setDouble (5, inoutDouble); // register the output parameters callStmt.registerOutParameter (1, Types.SMALLINT); callStmt.registerOutParameter (2, Types.INTEGER); callStmt.registerOutParameter (3, Types.BIGINT); callStmt.registerOutParameter (4, Types.REAL); callStmt.registerOutParameter (5, Types.DOUBLE); callStmt.registerOutParameter (6, Types.CHAR); callStmt.registerOutParameter (7, Types.CHAR); callStmt.registerOutParameter (8, Types.VARCHAR); callStmt.registerOutParameter (9, Types.DATE); callStmt.registerOutParameter (10, Types.TIME); callStmt.registerOutParameter (11, Types.INTEGER); callStmt.registerOutParameter (12, Types.CHAR); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve SQLCODE output parameter int outErrorCode = callStmt.getInt(11); if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); // retrieve output parameters inoutSmallint = callStmt.getShort(1); inoutInteger = callStmt.getInt(2); inoutBigint = callStmt.getLong(3); inoutReal = callStmt.getFloat(4); inoutDouble = callStmt.getDouble(5); outChar = callStmt.getString(6); outChars = callStmt.getString(7); outVarchar = callStmt.getString(8); outDate = callStmt.getDate(9); outTime = callStmt.getTime(10); 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 String outErrorLabel = callStmt.getString(12); System.out.println(procName + " failed with SQLCODE " + outErrorCode); System.out.println(" from procedure section labelled " + outErrorLabel); } callStmt.close (); } catch (SQLException e) { System.out.println(e); } } public static void callDB2SQL(String job, Connection con) { try { // prepare the CALL statement for DB2SQL_EXAMPLE String procName = "DB2SQL_EXAMPLE"; String sql = "CALL " + procName + "(?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // set the input parameter callStmt.setString (1, job); // register the output parameter callStmt.registerOutParameter (2, Types.DOUBLE); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve output parameters outMedian = callStmt.getDouble(2); System.out.println(procName + " completed successfully"); System.out.println ("Median salary returned from " + procName + " = " + outMedian); } 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) { try { String databaseName, databaseVersion; // prepare the CALL statement for DBINFO_EXAMPLE String procName = "DBINFO_EXAMPLE"; String sql = "CALL " + procName + "(?, ?, ?, ?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // set the input parameter callStmt.setString (1, job); // register the output parameters callStmt.registerOutParameter (2, Types.DOUBLE); callStmt.registerOutParameter (3, Types.CHAR); callStmt.registerOutParameter (4, Types.CHAR); callStmt.registerOutParameter (5, Types.INTEGER); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve output parameters outMedian = callStmt.getDouble(2); databaseName = callStmt.getString(3); databaseVersion = callStmt.getString(4); int outErrorCode = callStmt.getInt(5); if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println ("Average salary for job " + job + " = " + outMedian); 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); } } catch (SQLException e) { System.out.println(e); } } public static void callProgramTypeMain(String job, Connection con) { try { // prepare the CALL statement for MAIN_EXAMPLE String procName = "MAIN_EXAMPLE"; String sql = "CALL " + procName + "(?, ?, ?)"; CallableStatement callStmt = con.prepareCall(sql); // set the input parameter callStmt.setString (1, job); // register the output parameter callStmt.registerOutParameter (2, Types.DOUBLE); callStmt.registerOutParameter (3, Types.INTEGER); // call the stored procedure System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); // retrieve output parameters outMedian = callStmt.getDouble(2); int outErrorCode = callStmt.getInt(3); if (outErrorCode == 0) { System.out.println(procName + " completed successfully"); System.out.println ("Average salary for job " + job + " = " + outMedian); } else { // stored procedure failed System.out.println(procName + " failed with SQLCODE " + outErrorCode); } } catch (SQLException e) { System.out.println(e); } } // ====================================================== // 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); } } }