There are a fair number of moving parts here. I hope that the following makes sense:

1) A SQL procedure can return any number of cursors (aka result sets). This is true regardless of the language used to code the procedure. That is, this is true even if the procedure is implemented in C or Cobol or SQL/PSM. The cursors are not declared in the SQL argument list of the procedure. Instead, the number of returned cursors is declared via a special DYNAMIC RESULT SETS clause on the CREATE PROCEDURE statement. The gory details of this are described in the SQL Standard, part 2, section 4.27.5 (Result-sets returned by SQL-invoked procedures) and part 2, section 11.51 (<SQL-invoked routine>). The Derby syntax for the CREATE PROCEDURE statement can be found here: http://db.apache.org/derby/docs/10.5/ref/ref-single.html#crefsqlj95081

So the answer to your question is that the returned result sets are not declared as parameters in the CREATE PROCEDURE statement. From the point of view of the SQL language, these cursors are not parameters. That's the fundamental reason that they are not retrieved as OUT parameters and why they don't appear in the argument list of the CALL statement itself.

2) The binding of that SQL language to Java is described in the SQL Standard part 13. The relevant portion is section 8.6 (Java routine signature determination), a very long, complicated set of rules. In matching a Java method to a SQL procedure, the database is supposed to look for methods whose trailing N arguments are of type ResultSet[] (where N is the number of cursors declared in the DYNAMIC RESULT SETS clause). Those trailing N arguments are visible in the Java method signature, but as noted above, not in the SQL signature of the procedure.

3) Note that JDBC won't even let you try to retrieve the cursors as OUT parameters. There is no java.sql.Types type code for ResultSet so you cannot use CallableStatement.registerOutParameter() to register an output parameter as a ResultSet. Similarly, there is no getXXX() method for retrieving a column or parameter of this type.

4) The following section in the Derby Reference Guide explains a little more about how the signatures of SQL procedures are mapped to the signatures of Java static methods: http://db.apache.org/derby/docs/10.5/ref/ref-single.html#rrefsqljargmatching

Hope this helps,
-Rick

jstrunk wrote:
I finally got the program to work, but I still dont understand something.

Here is the stored procedure:
public class SupplierProcs {
        public static void showSuppliers(ResultSet[] rs) throws SQLException {
                String query = "select SUPPLIERS.SUP_NAME, COFFEES.COF_NAME " +
                                       "from SUPPLIERS, COFFEES " +
                                       "where SUPPLIERS.SUP_ID = 
COFFEES.SUP_ID";

Connection con = DriverManager.getConnection("jdbc:default:connection"); Statement stmt = con.createStatement();
                rs[0] = stmt.executeQuery(query);
        }
}


Here is how it is called:
public class RunProcs {

        public static void main(String args[]) {
String url =
"jdbc:derby://localhost:1527/COFFEEBREAK;user=root;password=rootpw";
                Connection con;
        
                try {
                        con = DriverManager.getConnection(url);
CallableStatement cstmt = con.prepareCall("{call show_suppliers()}"); ResultSet rs = cstmt.executeQuery();
        
while (rs.next()) { String supName = rs.getString(1);
                           String cofName = rs.getString(2);
                           System.out.println(supName + " supplies " + cofName);
                        }
                        
                        cstmt.close();
                        con.close();
        
                } catch(SQLException ex) {
                        System.err.println("SQLException: " + ex.getMessage());
                        ex.printStackTrace();
                }
        }
}

This works but it doesn't seem like it should.
The stored procedure takes a parameter:    public static void
showSuppliers(ResultSet[] rs)

It is called without a parameter:                call show_suppliers()}");

Shouldnt it be called with an OUT parameter to return the ResultSet like? call show_suppliers(?)}");

jstrunk wrote:
I have been putting the jar file in RunProc's class path with the Eclipse
Build Path option.
Your reference in the DevGuide gives the clearest explanation of what's
going on that I have seen.
I will try to work through all of that.




Rick Hillegas-2 wrote:
One thing I notice is that the program stores the jar file in the database but does not wire the jar file into the database classpath. If you put the jar file on the VM's classpath, then you don't need this step. However, if the jar file is stored in the database, then you need to use SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY to wire the jar file into the database classpath property "derby.database.classpath". See http://db.apache.org/derby/docs/10.5/devguide/devguide-single.html#cdevdeploy30736

Hope this helps,
-Rick

jstrunk wrote:
OK, thanks.
1. I put the parens back in ran this program to store the procedure

import java.sql.*;
public class InstallProcs {

        public static void main(String args[]) {
String url =
"jdbc:derby://localhost:1527/COFFEEBREAK;user=root;password=rootpw";
                Connection con;
                String installJar;
                String createProc;
                
                installJar = "{call sqlj.install_jar(" +
                         "'file:/C:/Users/jim/DerbyWorkspace/SQLRoutines.jar',
'routines_jar', 0)}";
                createProc = "create procedure show_suppliers()\n" +
                             "reads sql data\n" +
                             "dynamic result sets 1\n" +
                             "external name 
'routines_jar:SuppliersProcs.showSuppliers'\n" +
                             "language java parameter style java";
        
                Statement stmt;
        
                try {
                        con = DriverManager.getConnection(url);
        
                        stmt = con.createStatement();   
                        stmt.executeUpdate(installJar);
                        stmt.executeUpdate(createProc);
        
                        stmt.close();
                        con.close();
        
                } catch(SQLException ex) {
                        System.err.println("SQLException: " + ex.getMessage());
                        ex.printStackTrace();
                }
        }
}

2. Then I ran this program to try to execute the stored procedure

import java.sql.*;
public class RunProcs {

        public static void main(String args[]) {
String url =
"jdbc:derby://localhost:1527/COFFEEBREAK;user=root;password=rootpw";
                Connection con;
        
                try {
                        con = DriverManager.getConnection(url);
                        CallableStatement cstmt =con.prepareCall("{call
root.show_suppliers()}"); ResultSet rs = cstmt.executeQuery();
        
                        String supName = rs.getString(1);
                        String cofName = rs.getString(2);
                        System.out.println(supName + " supplies " + cofName);
                        cstmt.close();
                        con.close();
        
                } catch(SQLException ex) {
                        System.err.println("SQLException: " + ex.getMessage());
                        ex.printStackTrace();
                }
        }
}

3.  RunProcs gets this error

SQLException: The class 'routines_jar:SuppliersProcs' does not exist or
is
inaccessible. This can happen if the class is not public.
java.sql.SQLSyntaxErrorException: The class
'routines_jar:SuppliersProcs'
does not exist or is inaccessible. This can happen if the class is not
public.
        at
org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown
Source)
        at org.apache.derby.client.am.SqlException.getSQLException(Unknown
Source)
        at org.apache.derby.client.am.Connection.prepareCall(Unknown Source)
        at RunProcs.main(RunProcs.java:17)
Caused by: org.apache.derby.client.am.SqlException: The class
'routines_jar:SuppliersProcs' does not exist or is inaccessible. This
can
happen if the class is not public.
        at org.apache.derby.client.am.Statement.completeSqlca(Unknown Source)
        at
org.apache.derby.client.net.NetStatementReply.parsePrepareError(Unknown
Source)
        at
org.apache.derby.client.net.NetStatementReply.parsePRPSQLSTTreply(Unknown
Source)
        at org.apache.derby.client.net.NetStatementReply.readPrepare(Unknown
Source)
        at org.apache.derby.client.net.StatementReply.readPrepare(Unknown
Source)
        at org.apache.derby.client.net.NetStatement.readPrepare_(Unknown
Source)
        at org.apache.derby.client.am.Statement.readPrepare(Unknown Source)
        at
org.apache.derby.client.am.PreparedStatement.readPrepareDescribeInput(Unknown
Source)
        at
org.apache.derby.client.am.PreparedStatement.flowPrepareDescribeInputOutput(Unknown
Source)
        at org.apache.derby.client.am.PreparedStatement.prepare(Unknown Source)
        at org.apache.derby.client.am.Connection.prepareCallX(Unknown Source)
        ... 2 more
Caused by: org.apache.derby.client.am.SqlException: Java exception:
'routines_jar:SuppliersProcs: java.lang.ClassNotFoundException'.
        ... 13 more




Rick Hillegas-2 wrote:
Note that the parentheses are required by the ANSI/ISO SQL Standard.
See part 2 of the standard, section 11.51 <SQL-invoked routine>. Derby enforces this standard syntax: http://db.apache.org/derby/docs/10.5/ref/ref-single.html#crefsqlj95081

Hope this helps,
-Rick

jstrunk wrote:
At my level, its too hard to understand the demo programs. I did find
several
places online that said you DO NOT code the parens on the procedure
name
if
there are no parameters. So I took that out. Here is my code now and
the
error I get now.

import java.sql.*;
public class InstallProcs {

     public static void main(String args[]) {
String url =
"jdbc:derby://localhost:1527/COFFEEBREAK;user=root;password=rootpw";
        Connection con;
        String installJar;
        String createProc;
                
        installJar = "{call sqlj.install_jar(" +
"'file:/C:/Users/jim/DerbyWorkspace/SQLRoutines.jar', 'routines_jar', 0)}";
        createProc = "create procedure show_suppliers " +
                     "reads sql data " +
                          "dynamic result sets 1 " +
                     "external name 'routines_jar:SuppliersProcs.showSuppliers' 
" +
                     "language java parameter style java";
        
        Statement stmt;
        
        try {
                con = DriverManager.getConnection(url);
                stmt = con.createStatement();   
                stmt.executeUpdate(installJar);
                stmt.executeUpdate(createProc);
                stmt.close();
                con.close();
                } catch(SQLException ex) {
                System.err.println("SQLException: " + ex.getMessage());
                ex.printStackTrace();
        }
     }
}



SQLException: Syntax error: Encountered "reads" at line 1, column 33.
java.sql.SQLSyntaxErrorException: Syntax error: Encountered "reads" at
line
1, column 33.
        at
org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown
Source)
        at org.apache.derby.client.am.SqlException.getSQLException(Unknown
Source)
        at org.apache.derby.client.am.Statement.executeUpdate(Unknown Source)
        at InstallProcs.main(InstallProcs.java:35)
Caused by: org.apache.derby.client.am.SqlException: Syntax error:
Encountered "reads" at line 1, column 33.
        at org.apache.derby.client.am.Statement.completeSqlca(Unknown Source)
        at
org.apache.derby.client.am.Statement.completeExecuteImmediate(Unknown
Source)
        at
org.apache.derby.client.net.NetStatementReply.parseEXCSQLIMMreply(Unknown
Source)
        at
org.apache.derby.client.net.NetStatementReply.readExecuteImmediate(Unknown
Source)
        at
org.apache.derby.client.net.StatementReply.readExecuteImmediate(Unknown
Source)
        at
org.apache.derby.client.net.NetStatement.readExecuteImmediate_(Unknown
Source)
        at org.apache.derby.client.am.Statement.readExecuteImmediate(Unknown
Source)
        at org.apache.derby.client.am.Statement.flowExecute(Unknown Source)
        at org.apache.derby.client.am.Statement.executeUpdateX(Unknown
Source)
        ... 2 more






jstrunk wrote:
I am using Eclipse 3.5.0 with Derby 10.5.3.0 (not the Derby Plugin).
I
created an SQLJ stored procedure and stored it. When I try to execute
it
I
get SQLException: Syntax error: Encountered "<EOF>" at line 1, column
19.
That is the only error information I get. How can I get a listing of
what
SQL thinks the procedure looks like up to the point where the error
occurs?




Reply via email to