这个操作失败并且显示 SQL4304 rc=1 错误消息。为什么呢?注意,EXTERNAL NAME 子句中的类名拼写错了(它应该是 SQL4304RC1!abend,缺少了 “L”)。要纠正这个错误,应该删除这个过程,并且在 EXTERNAL NAME 子句中采用正确的拼写来重新创建它。
清单 18. SQL4304 rc=1 示例:纠正 SQL4304 rc=1 错误$ db2 drop procedure SQL4304RC1
DB20000I The SQL command completed successfully.
$ db2 -tvf CreateSP.ddl
CREATE PROCEDURE SQL4304RC1 (IN INPUT int)
SPECIFIC SQL4304RC1
DYNAMIC RESULT SETS 1
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE DB2GENERAL
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'SQL4304RC1!abend'
DB20000I The SQL command completed successfully.
$ db2 "call SQL4304RC1(3)"
Result set 1
--------------
ID NAME DEPT JOB YEARS SALARY COMM
------ --------- ------ ----- ------ --------- ---------
180 Abrahams 38 Clerk 3 12009.75 236.50
230 Lundquist 51 Clerk 3 13369.80 189.65
2 record(s) selected.
Return Status = 0
SQL4304 RC=2
清单 19. SQL4304 rc=2 示例:AIX 上的 SQL4304RC2.java$ javac SQL4304RC2.java
$ cp SQL4304RC2.class ~/sqllib/function
$ db2 -tvf CreateSP_wrong.ddl
CREATE PROCEDURE SQL4304RC2 (IN INPUT int)
SPECIFIC SQL4304RC2
DYNAMIC RESULT SETS 1
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE DB2GENERAL
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'SQL4304RC2!abend'
DB20000I The SQL command completed successfully.
$ db2 "call SQL4304RC2(3)"
SQL4304N Java stored procedure or user-defined function "SHAKEBS.SQL4304RC2",
specific name "SQL4304RC2" could not load Java class "SQL4304RC2", reason code
"2". SQLSTATE=42724
这个操作失败并且显示 SQL4304 rc=2 错误消息。为什么呢?因为 PARAMETER STYLE 是 DB2GENERAL,所以需要确保 Java 源代码扩展 COM.ibm.db2.app.StoredProc。为了纠正这个问题,将 extends COM.ibm.db2.app.StoredProc 添加到存储过程类名的末尾。
清单 20. SQL4304 rc=2 示例:SQL4304RC2.java1 //The simplest JAVA SP
2 import java.sql.*;
3 import COM.ibm.db2.app.*;
4
5 public class SQL4304RC2 extends COM.ibm.db2.app.StoredProc
6 {
7 public void abend (int input) throws SQLException,Exception
8 {
9 int errorCode;
10
11 try
12 {
13 // get caller's connection to the database
14 Connection con = DriverManager.getConnection("jdbc:default:connection");
15
16 String query = "SELECT * FROM STAFF where YEARS = ?";
17
18 PreparedStatement pstmt = con.prepareStatement(query);
19 ResultSet rs = null;
20 pstmt.setInt(1, input);
21 rs = pstmt.executeQuery();
22
23 }
24 catch (SQLException sqle)
25 {
26 errorCode = sqle.getErrorCode();
27 throw new SQLException( errorCode + " FAILED - " + sqle.getMessage());
28 }
29 }
30 }
代码中的第 5 行现在正确地扩展类。重新对代码进行编译,然后替换 sqllib/function 中的 .class 文件,并且重新执行存储过程。
注意:导致 SQL4304 rc=2 错误消息的另一个常见错误是,存储过程的主方法被声明为 “public static” 方法。PARAMETER STYLE DB2GENERAL 过程不能声明为 “static” 方法,像以上代码的第 7 行那样进行声明才是正确的。
清单 21. SQL4304 rc=2 示例:纠正 SQL4304 rc=2 错误$ javac SQL4304RC2.java
$ cp SQL4304RC2.class ~/sqllib/function
$ db2 "call SQL4304RC2(3)"
Result set 1
--------------
ID NAME DEPT JOB YEARS SALARY COMM
------ --------- ------ ----- ------ --------- ---------
180 Abrahams 38 Clerk 3 12009.75 236.50
230 Lundquist 51 Clerk 3 13369.80 189.65
2 record(s) selected.
Return Status = 0
SQL4306
清单 22. SQL4306 示例:INSERT.sqljD:\>sqlj INSERT.sqlj
D:\>db2sqljcustomize -user cwylaw -password xxxxxxxxx -url
jdbc:db2://claw.torolab.ibm.com:50000/sample INSERT_SJProfile0
[ibm][db2][jcc][sqlj]
[ibm][db2][jcc][sqlj] Begin Customization
[ibm][db2][jcc][sqlj] Loading profile: INSERT_SJProfile0
[ibm][db2][jcc][sqlj] Customization complete for profile
INSERT_SJProfile0.ser
[ibm][db2][jcc][sqlj] Begin Bind
[ibm][db2][jcc][sqlj] Loading profile: INSERT_SJProfile0
[ibm][db2][jcc][sqlj] Driver defaults(user may override): BLOCKING ALL
VALIDATE BIND STATICREADONLY YES
[ibm][db2][jcc][sqlj] Fixed driver options: DATETIME ISO DYNAMICRULES BIND
[ibm][db2][jcc][sqlj] Binding package INSERT01 at isolation level UR
[ibm][db2][jcc][sqlj] Binding package INSERT02 at isolation level CS
[ibm][db2][jcc][sqlj] Binding package INSERT03 at isolation level RS
[ibm][db2][jcc][sqlj] Binding package INSERT04 at isolation level RR
[ibm][db2][jcc][sqlj] Bind complete for INSERT_SJProfile0
D:\>jar -cvf INSERT.jar *.class *.ser
added manifest
adding: INSERT.class(in = 1192) (out= 684)(deflated 42%)
D:\>db2 call sqlj.install_jar("file:///D:\INSERT.jar",
'INSERTJAR')
DB20000I The CALL command completed successfully.
D:\>db2 -tvf Create.ddl
CREATE PROCEDURE INSERT (IN INPUT CHAR(3))
SPECIFIC INSERT
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
NO DBINFO
FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'INSERT.INSERT'
DB20000I The SQL command completed successfully.
D:\>db2 call INSERT('abc')
SQL4306N Java stored procedure or user-defined function "CWYLAW.INSERT",
specific name "INSERT" could not call Java method "INSERT",
signature "(Ljava/lang/String;)V". SQLSTATE=42724
为什么会产生这个 SQL4306 错误?请看看源代码和 CREATE PROCEDURE 语句。注意,在 Java 代码中,方法被声明为:public static void iNSERT (String input)
注意小写字母‘i’。
清单 23. SQL4306 示例:Windows 上的 INSERT.sqlj//The simplest SQLJ SP
import java.sql.*;
import sqlj.runtime.*;
import sqlj.runtime.ref.*;
public class INSERT
{
public static void iNSERT (String input) throws SQLException, Exception
{
#sql { INSERT INTO CWYLAW.StoreData (c) VALUES (:input) };
}
}
清单 24. SQL4306 示例:INSERT 过程所需的 StoreData 表的 CREATE TABLE 语句CREATE TABLE StoreData (c char(3));
但是,在 CREATE PROCEDURE 语句中,EXTERNAL NAME 被声明为 EXTERNAL NAME 'INSERT.INSERT'。注意大写字母‘I’。所以,出现 SQL4306 错误的原因是源代码中的 Java 方法名与 CREATE PROCEDURE 语句中的 EXTERNAL NAME 不匹配。要纠正这个问题,就要确保 Java 方法与 CREATE PROCEDURE 语句中的 EXTERNAL NAME 子句精确匹配。在这个例子中,我们选择修改 CREATE PROCEDURE 语句而不是修改源代码。
清单 25. SQL4306 示例:INSERT 存储过程的正确的 CREATE PROCEDURE 语句CREATE PROCEDURE INSE