Examples for the SQLJ feature of ASE 12.5 |
Yiwen Huang | huangy@sybase.com | (510) 922-5344 |
Phil Shaw | pshaw@sybase.com | (510) 922-5174 |
The Java features of ASE 12.5 extend the Java capabilities introduced in ASE 12.0.
With the ASE 12.0 Java feature you can:
With the ASE 12.5 SQLJ feature you can:
SQL result sets and output parameter values are common techniques with SQL stored procedures. These capabilities are now fully supported with the Java feature.
The following sections show the example code from the user documentation of the ASE12.5 SQLJ feature.
For guidelines on setting up the Java facilities of Adaptive Server, see the Setup section of $SYBASE/ASE-12_5/XML-examples/index.htm.
TopThe files in this directory are as follows:
Here's a simple select that references a built-in Java method. This select references the Java method using its Java name, as with ASE 12.0:
select java.lang.Math.sqrt(16) |
With the SQLJ feature of ASE 12.5, we can define an SQL name for any Java method that we want to call in SQL:
create function squareroot (inputnumber double precision) returns double precision language java parameter style java external name 'java.lang.Math.sqrt' |
Given such an SQLJ create, we can reference the Java method with its SQL name:
1> select squareroot(16) -------------------- 4.000000 (1 row affected) |
The SQLJ examples below reference the following SQL table:
create table salesemps (name varchar(50), id char(5), state char(20), sales decimal (6,2), jobcode integer null) insert into salesemps values("Adams", "00001", "MN", 123.01, 1) insert into salesemps values("Baker", "00003", "VT", 323.01, 2) insert into salesemps values("Carter", "00005", "NH", 523.01, 3) insert into salesemps values("Davis", "00007", "FL", 723.01, 2) insert into salesemps values("Earl", "00009", "GA", 923.01, 1) insert into salesemps values("Foster", "00011", "Cal", 1123.01, 2) insert into salesemps values("George", "00013", "AZ", 3123.01, 3) insert into salesemps values("Harris", "00015", "NV", 5123.01, 2) insert into salesemps values("Jackson", "00017", "MN", 7123.01, 1) insert into salesemps values("Kramer", "00019", "VT", 9123.01, 2) |
The Java classes used in the following examples are in the jar file "sqlj-examples.jar".
You can install that jar file with a client command such as the following:
installjava -fsqlj-examples.jar -update -j"sqlj_examples_jar" -S "server_name" -Usa -P"" |
The "server_name" is the name that you specify for ISQL.
This directory also contains a "makefile" with commands to compile the Java classes for the SQLJ examples, make a jar file ("sqlj-examples.jar") with them, and install the jar file.
make compile make jar make install make javadoc |
Before you execute those "make" commands, you will need to set environment variables as follows:
The example methods for SQLJ are contained in the class SQLJExamples.java. That class contains the following methods (described below).
The following examples use two Java methods:
public static int region(String s) throws SQLException { s = s.trim(); if (s.equals("MN") || s.equals("VT") || s.equals("NH") ) return 1; if (s.equals("FL") || s.equals("GA") || s.equals("AL") ) return 2; if (s.equals("CA") || s.equals("AZ") || s.equals("NV") ) return 3; else throw new SQLException ("Invalid state code", "X2001"); } public static void correctStates (String oldSpelling, String newSpelling) throws SQLException { Connection conn = null; PreparedStatement pstmt = null; try { Class.forName ("sybase.asejdbc.ASEDriver"); conn = DriverManager.getConnection("jdbc:default:connection"); } catch (Exception e) { System.err.println(e.getMessage() + ":error in connection"); } try { pstmt = conn.prepareStatement ("UPDATE salesemps SET state = ? " + " WHERE state = ?"); pstmt.setString(1, newSpelling); pstmt.setString(2, oldSpelling); pstmt.executeUpdate(); } catch (SQLException e) { System.err.println("SQLException: " + e.getErrorCode() + e.getMessage()); } return; } } |
With ASE 12.0 facilities, you can call "SQLJExamples.region" and "SQLJExamples.correctStates" in SQL by referencing the Java names:
1> select state, SQLJExamples.region(state) as region 2> from salesemps 3> where SQLJExamples.region(state)=3 4> go state region -------------------- ----------- CA 3 AZ 3 NV 3 (3 rows affected) 1> -- Introduce a mis-spelling: 2> update salesemps set state="Cal" where state="CA" (1 row affected) 1> -- The following now raises an exception due to the mis-spelling: 2> select name, state, SQLJExamples.region(state) as region 3> from salesemps 4> where SQLJExamples.region(state)=3 5> go Msg 10707, Level 16, State 1: Line 4: Unhandled Java Exception: java.sql.SQLException: Invalid state code at java.lang.Throwable.fillInStackTrace(Throwable.java) at java.lang.Throwable. |
The following SQLJ create function defines an SQL name for the Java method "SQLJExamples.region".
create function regionof(state char(20)) returns integer language java parameter style java external name 'SQLJExamples.region(java.lang.String)' |
The following SQL select statement calls the SQLJ function "regionof" that we created above.
1> select name, state, regionof(state) as region 2> from salesemps 3> where regionof(state)=3 name state region -------------------------------------------------- -------------------- ----------- Foster CA 3 George AZ 3 Harris NV 3 (3 rows affected) |
The above example showed an SQLJ function, "regionof" defined on a Java method "SQLJExamples.region". The example below shows an SQLJ procedure, "correctstates", defined on the Java method "SQLJExamples.correctStates".
create procedure correctstates(old char(20), notold char(20)) modifies sql data language java parameter style java external name 'SQLJExamples.correctStates(java.lang.String, java.lang.String)' |
Given this SQLJ definition of the "correctstates" procedure, we can call "correctstates" as we would a normal SQL stored procedure.
1> -- Introduce a mis-spelling 2> update salesemps set state="Geo" where state="GA" 3> 4> -- Correct the mis-spelling 5> execute correctstates 'Geo', 'GA' 6> go (1 row affected) (return status = 0) |
The following Java method, "SQLJExamples.job" maps an integer job code to a character string.
public static String job(int jc) throws SQLException { if (jc==1) return ("Admin"); else if (jc==2) return ("Sales"); else if (jc==3) return ("Clerk"); else return ("unknown jobcode"); } } |
You can call the "SQLJExamples.job" method directly, using its Java name as with ASE 12.0:
1> select name, SQLJExamples.job(jobcode) 2> from salesemps 3> where SQLJExamples.job(jobcode) <> "Admin" 4> go name -------------------------------------------------- -------------------------------------------------- Baker Sales Carter Clerk Davis Sales Foster Sales George Clerk Harris Sales Kramer Sales (7 rows affected) |
However, note that the parameter of "SQLJExamples.job" is a Java int, which cannot accept SQL nulls as argument value. For example, suppose that some "jobcode" value is null:
1> -- Change a 'jobcode' value to null: 2> update salesemps set jobcode=null where name = "Baker" (1 row affected) 1> -- The following will now raise an exception when the null value 2> -- is passed as a parameter to "SQLJExamples.job". 3> select name, SQLJExamples.job(jobcode) 4> from salesemps 5> where SQLJExamples.job(jobcode) <> "Admin" Msg 10794, Level 16, State 1: Line 6: Cannot pass NULL as the value for parameter number 1 to the method 'job' in class 'SQLJExamples'. The parameter is of a Java primitive datatype, and is non-nullable. |
Thus, when you call "SQLJExamples.job" directly from SQL, you have to guard against passing an SQL null value to it, with code such as the following:
select name, case when jobcode is not null then SQLJExamples.job(jobcode) else null end from salesemps where case when jobcode is not null then SQLJExamples.job(jobcode) else null end <> "Admin" |
We can simplify the treatment of null parameter values by defining an SQLJ function for "SQLJExamples.job", specifying the null on null input clause:
create function jobof(jc integer) returns varchar(20) returns null on null input language java parameter style java external name 'SQLJExamples.job(int)' |
The null on null input clause makes the guard code to check for nulls implicit. When we call the SQLJ "jobof" function, Any call of "jobof" whose parameter value is null will be treated as null without ever calling the underlying Java method "SQLJExamples.job".
1> select name, jobof(jobcode) 2> from salesemps 3> where jobof(jobcode) <> "Admin" 4> name -------------------------------------------------- -------------------- Carter Clerk Davis Sales Foster Sales George Clerk Harris Sales Kramer Sales (6 rows affected) |
The class "SQLJExamples" contains a method "bestTwoEmps" that is designed to be called as an SQLJ procedure with output parameters. The "bestTwoEmps" method has one input parameter, "regionParm". The other parameters are output parameters in which the method returns the column values of the two employees in "salesemps" with the highest sales.
The SQLJ convention for Java methods that are called as SQLJ procedures with output parameters is to represent output parameters as single-element arrays that act as "holders" for the output values.
public static void bestTwoEmps (String[] n1, String[] id1, BigDecimal[] s1, int[] r1, String[] n2, String[] id2, BigDecimal[] s2, int[] r2, int regionParm) throws SQLException { n1[0] = "****"; n2[0] = "****"; id1[0] = ""; id2[0] = ""; r1[0] = 0; r2[0] = 0; s1[0] = new BigDecimal(0); s1[0] = new BigDecimal(0); try { Class.forName("sybase.asejdbc.ASEDriver"); Connection conn = DriverManager.getConnection("jdbc:default:connection"); java.sql.PreparedStatement stmt = conn.prepareStatement("SELECT name, id, " + "regionof(state) as region, sales " + " FROM salesemps WHERE regionof(state)>? " + " AND sales IS NOT NULL ORDER BY sales DESC"); stmt.setInt(1, regionParm); ResultSet r = stmt.executeQuery(); if(r.next()) { n1[0] = r.getString("name"); id1[0] = r.getString("id"); r1[0] = r.getInt("region"); s1[0] = r.getBigDecimal("sales", 2); } else return; if(r.next()) { n2[0] = r.getString("name"); id2[0] = r.getString("id"); r2[0] = r.getInt("region"); s2[0] = r.getBigDecimal("sales", 2); } else return; } catch (SQLException e) { System.err.println(" SQLException:" + e.getErrorCode() + e.getMessage()); }catch (Exception e) { System.err.println(" Exception:" + e.getMessage()); } } } |
The following SQLJ create procedure creates an SQL stored procedure named "best2" for the Java method "SQLJExamples.bestTwoEmps".
create procedure best2 (out n1 varchar(50), out id1 varchar(5), out s1 decimal(6,2), out r1 integer, out n2 varchar(50), out id2 varchar(50), out r2 integer, out s2 decimal(6,2), in region integer) language java parameter style java external name 'SQLJExamples.bestTwoEmps(java.lang.String[], java.lang.String[], int[], java.math.BigDecimal[], java.lang.String[], java.lang.String[], int[], java.math.BigDecimal[], int)' |
The following shows a call of the SQLJ procedure "best2". Note that this is the same call that you would write if the "best2" procedure were a TSQL procedure.
1> declare @n1 varchar(50), @id1 varchar(5), @s1 decimal (6,2), @r1 integer, 2> @n2 varchar(50), @id2 varchar(50), @r2 integer, @s2 decimal(6,2), 3> @region integer 4> select @region = 0 5> execute best2 @n1 out, @id1 out, @s1 out, @r1 out, @n2 out, @id2 out, @s2 out, @r2 out, @region 6> (1 row affected) (return status = 0) Return parameters: -------------------------------------------------- ----- --------- ----------- -------------------------------------------------- -------------------------------------------------- --------- ----------- Adams 00001 123.01 1 Baker 00003 323.01 1 (1 row affected) |
You can get descriptive information about SQLJ procedures and functions in the same manner as for TSQL.
1> sphelp best2 Name Owner Type ------------------------------ ------------------------------ ---------------------- best2 dbo SQLJ procedure (1 row affected) Datalocatedonsegment Whencreated ------------------------------ -------------------------- not applicable Mar 8 2001 4:09PM Parametername Type Length Prec Scale Paramorder --------------- --------------- ----------- ---- ----- ----------- @n1 varchar 50 NULL NULL 1 @id1 varchar 5 NULL NULL 2 @s1 decimal 4 6 2 3 @r1 int 4 NULL NULL 4 @n2 varchar 50 NULL NULL 5 @id2 varchar 50 NULL NULL 6 @s2 decimal 4 6 2 7 @r2 int 4 NULL NULL 8 @region int 4 NULL NULL 9 (return status = 0) |
The Java class "SQLJExamples" has a method "orderedEmps" that is intended to be called as an SQLJ procedure that returns an SQL result set.
The SQLJ convention for Java methods that are called as SQLJ procedures returning result sets is to include one or more additional parameters in the Java method for the result sets.
public static void orderedEmps (int regionParm, ResultSet[] rs) throws SQLException { Connection conn = null; PreparedStatement pstmt = null; try { Class.forName("sybase.asejdbc.ASEDriver"); conn = DriverManager.getConnection("jdbc:default:connection"); } catch (Exception e) { System.err.println(e.getMessage() + ": error in connection" ); } try { java.sql.PreparedStatement stmt = conn.prepareStatement ("SELECT name, regionof(state) as region, " + "sales FROM salesemps " + "WHERE regionof(state) > ? " + " AND sales IS NOT NULL ORDER BY sales DESC"); stmt.setInt(1, regionParm); rs[0] = stmt.executeQuery(); return; } catch (SQLException e) { System.err.println("SQLException: " + e.getErrorCode() + e.getMessage()); } return; } } |
The following is an SQLJ create procedure to define an SQLJ procedure named "rankedemps" for the Java method "SQLJExamples.orderedEmps".
1> create procedure rankedemps(region integer) 2> dynamic result sets 1 3> language java parameter style java 4> external name 'SQLJExamples.orderedEmps(int, java.sql.ResultSet[])' 5> 1> 2> exec rankedemps 0 name region sales -------------------------------------------------- ----------- --------- Adams 1 123.01 Baker 1 323.01 Carter 1 523.01 Davis 2 723.01 Earl 2 923.01 Foster 3 1123.01 George 3 3123.01 Harris 3 5123.01 Jackson 1 7123.01 Kramer 1 9123.01 (10 rows affected) (return status = 0) |
The following is the Java statements you would execute in a Java client to call the SQLJ procedure "rankedemps" and retrieve the result set that it returns.
Note that this code is exactly the same as the code you would use if the "rankedemps" procedure were written in TSQL.
java.sql.CallableStatement stmt = conn.prepareCall({call rankedemps(?)}); stmt.setInt(1,3); ResultSet rs = stmt.executeQuery(); while (rs.next()) { String name = rs.getString(1); int.region = rs.getInt(2); BigDecimal sales = rs.get.BigDecimal(3); System.out.print(Name = + name); System.out.print(Region = + region); System.out.print(Sales = + sales); System.out.printIn(): } |
This code is contained in the "main" method of "CallRankedEmps". That method takes two parameters:
For example:
java CallRankedEmps "yourserver:11111" 2 java CallRankedEmps "yourserver:11111?user=smith&password=xxx" 2 |
When you create a SQLJ function or stored procedure, you typically specify a SQL signature and a Java method signature. For example, in the create procedure statement for the correctStates stored procedure, the SQL stored procedure signature is old char(20), notold char(20):
create procedure correctstates(old char(20), notold char(20)) modifies sql data language java parameter style java external name 'SQLJExamples.correctStates(java.lang.String, java.lang.String)' |
You can also omit the Java method signature from the create statement and allow Adaptive Server to infer it from the routine's SQL signature according to standard JDBC datatype correspondence rules
create procedure correctstates(old char(20), notold char(20)) modifies sql data language java parameter style java external name 'SQLJExamples.correctStates' |
If you specify an explicit Java method signature, you must include the trailing result sets in the signature.
create procedure rankedemps (region integer) dynamic result sets 1 language java parameter style java external name 'SQLJExamples.orderedEmps (int, java.sql.ResultSet[])' |
You drop an SQLJ function or procedure with a normal SQL drop command.
drop function squareroot drop table salesemps drop procedure correctstates drop function regionof drop function jobof22 drop procedure best2 drop procedure rankedemps |