Java Stored Procedures, Triggers, and UDFs

The FairCom DB SQL implementation of stored procedures allows use of standard Java programming constructs instead of requiring proprietary flow-control language. To do this, the FairCom DB SQL interacts with Java in the following ways:

  • When you create a stored procedure, FairCom DB SQL processes the Java code, submits it to the Java compiler, and receives the compiled results to store in the database.
  • When applications call a stored procedure, FairCom DB SQL interacts with the Java virtual machine (JRE) to execute the stored procedure and receive any results.

 

Creating Stored Procedures

The Java source code that makes up the body of a stored procedure is not a complete program. It is a snippet that FairCom DB SQL converts into a Java class when it processes a CREATE PROCEDURE statement.

Creating a stored procedure involves the following steps:

  1. Some application or tool (FairCom DB SQL Explorer, Interactive SQL utility, or an application) issues a CREATE PROCEDURE statement containing the Java snippet.
  2. FairCom DB SQL adds additional supporting code to the Java snippet to create a complete Java class and submits the combined code to the Java compiler (javac).
  3. Presuming there are no Java compilation errors, the Java compiler sends compiled bytecode back to FairCom DB SQL. If there are compilation errors, FairCom DB SQL passes the first error generated back to the application or tool that issued the CREATE PROCEDURE statement.
  4. FairCom DB SQL stores both the Java source code and the bytecode form of the procedure in the database.

The following figure illustrates the steps in creating a stored procedure:

 

Calling Stored Procedures

Once a stored procedure is created and stored in the database, any application (or other stored procedure) can execute it by calling it. You can call stored procedures from ODBC, JDBC, or .NET applications, or directly from the Interactive SQL utility, isql.

For example, the following example shows an excerpt from an ODBC application that calls a stored procedure (order_parts) using the ODBC syntax:

{ call procedure_name ( param ) }.

Executing a Stored Procedure Through ODBC


SQLUINTEGER Part_num;
SQLINTEGER  Part_numInd = 0;

// Bind the parameter.
SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0,
                 &Part_num, 0, Part_numInd);

// Place the department number in Part_num.
Part_num = 318;

// Execute the statement.
SQLExecDirect(hstmt, "{call order_parts(?)}", SQL_NTS);

Executing a stored procedure involves the following steps:

  1. The application calls the stored procedure through its native calling mechanism (for example, using the ODBC call escape sequence).
  2. FairCom DB SQL retrieves the compiled bytecode-form of the procedure and submits it to the Java virtual machine for execution.
  3. For every FairCom DB SQL statement in the procedure, the Java virtual machine calls FairCom DB SQL.
  4. FairCom DB SQL manages interaction with the underlying database system and execution of the SQL statements, and returns any results to the Java virtual machine.
  5. The Java virtual machine returns results (output parameters and result sets) of the procedure to FairCom DB SQL, which in turn passes them to the calling application.

The following figure illustrates the steps in executing a stored procedure.

 

LVARCHAR Fields Allowed in Stored Procedure Code

Within a Java stored procedure, it is now possible to retrieve, insert, and update the content of an LVARCHAR field. the following changes have been made:

SQLIStatement and SQLPStatement methods have been enhanced such that the SetParam method can be used to specify the content of an LVARCHAR field.

The SQLCursor GetValue method has been enhanced to retrieve the entire content of an LVARCHAR field.

The SQLCursor class has a new member getLongValue to retrieve a chunk of a LVARCHAR field (in case the field content is too large).

Function

public Object getLongValue(int field, int offset, int len)

where:

  • field - the field number
  • offset - the starting point (0 based) where the portion you want to retrieve starts.
  • len - the length of the portion to retrieve.

Return

The function return NULL if there is no more to retrieve.

 

Java Stored Procedures and Triggers Require JDK V1.7 or Newer

Note: The FairCom DB SQL Java Stored Procedure and Trigger support requires a Java Development Kit (JDK) be installed on your computer. A Java Runtime Environment (JRE) is not sufficient. FairCom DB V11.5 (FairCom RTG and FairCom Edge V2.5) and later require JDK V1.7 or newer.

Note: For the tutorials to work correctly, the three Java-related “SETENV” lines in your <faircom>/config/ctsrvr.cfg file need to be active (the lines are not commented out with leading semicolons), the lines are all set to paths that are valid on your computer, and there is no whitespace before or after the "=" sign. Here are some typical examples, which will need to be adjusted for your machine:

Microsoft Windows

; JDK environment settings - Be sure to set the JDK to your version.
SETENV    CLASSPATH=C:\Program Files\Java\jdk1.7.0_75\jre\lib\rt.jar;.\classes\ctreeSQLSP.jar
SETENV    JVM_LIB=C:\Program Files\Java\jdk1.7.0_75\jre\bin\server\jvm.dll
SETENV    JAVA_COMPILER=C:\Program Files\Java\jdk1.7.0_75\bin\javac.exe

Linux

; JDK environment settings - Be sure to set the JDK to your version.
SETENV CLASSPATH=/usr/java/jdk1.7.0_75/jre/lib/rt.jar:./classes/ctreeSQLSP.jar
SETENV JAVA_COMPILER=/usr/java/jdk1.7.0_75/bin/javac
SETENV JVM_LIB=/usr/java/jdk1.7.0_75/jre/lib/amd64/server/libjvm.so

The lines above all need to correctly point to your JDK installation folder before you start the c-tree server, because changes to ctsrvr.cfg take effect only when you launch the c-tree server.

All of these Java-related lines should point at files which are in the same JDK folder (“jdk1.7.0_75” in this example), and not from a JRE installation. Violating these rules can result in problems that can be difficult to track down.

In the CLASSPATH line, the path to ctreeSQLSP.jar is relative to the “server” folder. On Linux, the entries in the CLASSPATH line should be separated with colons instead of semicolons.

The purpose of these three lines is to give the c-tree server the information it needs to compile and run Java source code. This is because the stored procedures demonstrated by this tutorial are written in Java.

If you are using FairCom RTG or FairCom Edge, adjust the path to match your product.

 

SQL Stored Procedures - Close cursors that were left open

In a rare situation involving a complex set of stored procedures, cursors could leak. In c-tree stored procedures, cursors need to be closed explicitly; if this is not done, the cursor is leaked.

Logic has been added to the function that starts stored procedures to identify cursors that are opened and not closed within a stored procedure and close any that are found. When Java debugging is turned on in TPESQLDBG, a message is logged in sqlserver.log to help in identifying the stored procedure and the statement that leaked the cursors.

 

Java Quick Tour

This QuickStart is composed of four simple tutorials designed to guide you through the basic use of the FairCom DB SQL Stored Procedures technology.

Tutorials for Java Stored Procedures can be found in the ReadMe titled FairCom Java Stored Procedures.

As with all other tutorials in the c-tree series, each of these database programming tutorials is implemented with four simple code procedures: Initialize(), Define(), Manage(), and Done().

No matter which FairCom interface language you use, FairCom follows this same high-level flow in all tutorials. This makes it easy for developers to "cross-over" from one language interface to another as these basic concepts apply to all.

 

Initialize()

Every language requires some form of initial "logon" or "connection" procedure to establish a session with the database. This is done in the Initialize() stage of the program.

 

Define()

Database definitions (DDL), Table/File schema definitions, Index definitions, Table/File creation, and Table/File open operations are all addressed in the Define() stage of the program.

Manage()

This stage of the program is where the database is operated on, as in managing your data. Adding/Reading/Updating/Deleting records/rows are handled in this stage of the program.

Done()

When the program ends, the database session should be closed. This stage handles the necessities to "de-init", by closing Tables/Files and issuing any required "logoff" or "disconnect" type procedures.

Presented here are tutorials that follow the "Initialize(), Define(), Manage(), and Done()" approach.

You can also view similar tutorials for all supported languages online.

Four SQL scripts have been included in the SQL Stored Procedures Tutorial directory, located in:

C:\<faircom>\win32\sdk\sql.stored.procs\tutorials (where C:\<faircom> is your installation directory. The default installation directory was C:\<faircom>).

The following is a conceptual overview of these tutorials:

Tutorial #1: Introductory - Simple Single Table

We wanted to keep this program as simple as possible. This program does the following:

  • Initialize() - Connects to the FairCom DB database engine.
  • Define() - Defines and creates a "customer master" (custmast) file/table.
  • Manage() - Adds a few records/rows; Reads the records/rows back from the database and displays their content; and then deletes the records/rows.
  • Done() - Disconnects from FairCom DB Database Engine.

Tutorial #2: Relational Model and Indexing

Here we now add a bit more complexity, introducing multiple tables, with related indices in order to form a simple "relational" database simulating an Order Entry system. Here is an overview of what will be created:

  • Initialize() - Connects to the FairCom DB database engine.
  • Define() - Defines and creates the "custmast", "custordr", "ordritem" and the "itemmast" files/tables with related indices.
  • Manage() - Adds some related records/rows to all files/tables. Then queries this order database.
  • Done() - Disconnects from FairCom DB Database Engine.

Tutorial #3: Locking

Here we demonstrate the enforcement of data integrity by introducing record/row "locking".

  • Initialize() - Connects to the FairCom DB database engine.
  • Define() - Defines and creates a "customer master" (custmast) file/table.
  • Manage() - Adds a few records/rows; Reads the records/rows back from the database and displays their content. Then demonstrates an update operation under locking control, and a scenario that shows a locking conflict.
  • Done() - Disconnects from FairCom DB database engine.

Tutorial #4: Transaction Processing

Here we demonstrate transaction control.

  • Initialize() - Connects to the FairCom DB database engine.
  • Define() - Defines and creates our four file/tables.
  • Manage() - Adds records/rows to multiple tables under transaction control.
  • Done() - Disconnects from FairCom DB Database Engine.

Learn More...

Try the tutorials in in the ReadMe titled FairCom Java Stored Procedures.

 

Throw Custom Error Message on Stored Procedure or UDF Exception

This modification provides the capability to return an error message from a stored procedure or user-defined function (UDF).

Before this modification, the only way for a stored procedure to set the return code to a value different than 0 was to throw a DhSQLException() either directly (only when using the NetBeans plugin to generate the stored procedure) by:

throw new DhSQLException(678,"my error message"); 

or through the DhSQLThrow class:

DhSQLThrow.throwSQLException(678,"my error message"); 

In both cases the error code returned was interpreted as a known SQL error code and the error message was set to the one for the specific error code returned, ignoring the message.

This modification adds a preferred way of returning an error message by calling the new fail(String message) method. This method causes the stored procedure to terminate with error -26015 and sets the error message to the string passed in. The message will be truncated if it is larger than 510 characters. For example:

 
ISQL> CREATE PROCEDURE  excp()
BEGIN
fail("my error message");
END
ISQL> call excp();
ISQL> error(-26015): my error message

 

Java Class Reference

 

Introduction

This chapter provides reference material on the FairCom DB SQL Java classes and methods. The following table lists all the methods in the FairCom DB SQL Java classes and shows which classes declare them. Following sections are arranged alphabetically and describe each class and its methods in more detail. Some methods are common to more than one class.

Methods in the FairCom DB SQL Java Classes

Method SQLI-Statement SQLP-Statement SQLCursor DhSQL-ResultSet DhSQL-Exception Purpose
setParam X X X     Sets the value of an SQL statement’s input parameter to the specified value (a literal, procedure variable, or procedure input parameter)
makeNULL X X X     Sets the value of an SQL statement’s input parameter to null
execute X X       Executes the SQL statement
rowCount X X X     Returns the number of rows affected (selected, inserted, updated, or deleted) by the SQL statement
open     X     Opens the result set specified by the SELECT or CALL statement
close     X     Closes the result set specified by the SELECT or CALL statement
fetch     X     Fetches the next record in a result set
found     X     Checks whether a fetch operation returned a record
wasNULL     X     Checks if the value in a fetched field is null
getValue     X     Returns the value of the specified field from the fetched row as an Object.
getParam X X X     Returns the value of the specified OUT/INOUT parameter as an Object. (This method is called after executing a CALL statement).
registerOutParam X X X     Registers the return type of the OUT and INOUT parameters.
set       X   Sets the field in the currently-active row of a procedure’s result set to the specified value (a literal, procedure variable, or procedure input parameter)
makeNULL       X   Sets a field of the currently-active row in a procedure’s result set to null
insert       X   Inserts the currently-active row into a procedure’s result set
getDiagnostics         X Returns the specified detail of an error message
log X X X X X Writes a message to the file sql_server.log. Inherited by all the FairCom DB SQLFairCom DB SQL classes. See Debugging Stored Procedures.
err X X X X X Writes a message to the file sql_server.log. Inherited by all the FairCom DB SQLFairCom DB SQL classes. See Debugging Stored Procedures.

 

DhSQLException

Description

The DhSQLException class extends the general java.lang.Exception class to provide detail about errors in FairCom DB SQL statement execution. Any such errors raise an exception with an argument that is an SQLException class object. The getDiagnostics() method retrieves details of the error.

Constructors

public DhSQLException(int ecode, String errMsg)

Parameters

ecode

The error number associated with the exception condition.

errMsg

The error message associated with the exception condition.

The following example illustrates the DhSQLException() constructor to create an exception object called excep. It then throws the excep object under all conditions.

Example


CREATE PROCEDURE sp1_02()
BEGIN
     // raising exception
     DhSQLException excep = new DhSQLException(666,new String
                            ("Entered the sp1_02 procedure"));
     if (true)
     throw excep;
END

 

DhSQLException.getDiagnostics

Returns the requested detail about an exception.

Format

public String getDiagnostics(int diagType)

Returns

A string containing the information specified by the diagType parameter, as shown in the table below.

Parameters

diagType

One of the values shown in the following table.

Argument Values for DhSQLException.getDiagnostics

Argument Value Returns
RETURNED_SQLSTATE The SQLSTATE returned by execution of the previous SQL statement.
MESSAGE_TEXT The condition indicated by RETURNED_SQLSTATE.
CLASS_ORIGIN Not currently used. Always returns null.
SUBCLASS_ORIGIN Not currently used. Always returns null.

Throws

DhSQLException

Example


CREATE PROCEDURE test_proc()
BEGIN
   String errstate;
   String errmesg;
   try
   {
      SQLIStatement insert_cust = new SQLIStatement ( "INSERT
      INTO customer VALUES (1,2) ");
      insert_cust.execute();
   }
   catch (DhSQLException e)
   {
      errstate = e.getDiagnostics (
      DhSQLException.RETURNED_SQLSTATE) ;
      errmesg = e.getDiagnostics (
      DhSQLException.MESSAGE_TEXT) ;
   }
END

 

DhSQLException.getMessageText

Returns a textual description of the exception error.

Format

public String getMessageText()

Returns

A string containing the textual description of the exception.

Parameters

Throws

Example


CREATE PROCEDURE test_proc()
BEGIN
  Integer errstate;
  String errmesg;
  try
  {
     SQLIStatement insert_cust = new SQLIStatement ( "INSERT
     INTO customer VALUES (1,2) ");
     insert_cust.execute();
  }
  catch (DhSQLException e)
  {
     
     errstate = e.getSqlState();
     errmesg = e.getMessageText();
  }
END   

 

DhSQLException.getSqlState

Returns the SQL state as an integer error code.

Format

public Integer getSqlState()

Returns

An integer containing the SQL state (error code) of the exception.

Parameters

Throws

Example


CCREATE PROCEDURE test_proc()
BEGIN
  Integer errstate;
  String errmesg;
  try
  {
     SQLIStatement insert_cust = new SQLIStatement ( "INSERT
     INTO customer VALUES (1,2) ");
     insert_cust.execute();
  }
  catch (DhSQLException e)
  {
     errstate = e.getSqlState();
     errmesg = e.getMessageText() ;
  }
END  

 

DhSQLResultSet

Description

Methods of the DhSQLResultSet class populate a result set that the stored procedure returns to the application that called the procedure.

The Java code in a stored procedure does not explicitly create DhSQLResultSet objects. Instead, when FairCom DB SQL creates a Java class from a CREATE PROCEDURE statement that contains a RESULT clause, it implicitly instantiates an object of type DhSQLResultSet, and calls it SQLResultSet.

Procedures invoke methods of the SQLResultSet() instance to populate fields and rows of the result set.

Limit: DhSQLResultSet is limited to 50 columns.

Constructors

No explicit constructor

Parameters

None

Throws

DhSQLException

 

DhSQLResultSet.set

Sets the field in the currently-active row of a procedure’s result set to the specified value (a literal, procedure variable, or procedure input parameter).

Format

public void set(int field, Object val)

Returns

None

Parameters

field

An integer that specifies which field of the result-set row to set to the value specified by val (1 denotes the first field in the row, 2 denotes the second, and so on).

val

A literal or the name of a variable or input parameter that contains the value to be assigned to the field.

Throws

DhSQLException

Example


CREATE PROCEDURE get_sal2 ()
RESULT (
    empname CHAR(20),
    empsal   NUMERIC,
)
BEGIN
    StringBuffer ename = new StringBuffer (20) ;
    BigDecimal esal = new BigDecimal () ;
    SQLCursor empcursor = new SQLCursor (
        "SELECT name, sal FROM emp " ) ;
   
    empcursor.open () ;
    do
    {
        empcursor.fetch ();
        if (empcursor.found ())
        {
            ename = (StringBuffer)empcursor.getValue (1, CHAR);
            esal = (BigDecimal)empcursor.getValue (2, NUMERIC);

            SQLResultSet.set (1, ename);
            SQLResultSet.set (2, esal);
            SQLResultSet.insert ();
        }
    } while (empcursor.found ()) ;
    empcursor.close () ;
END

Note: The resultset parameter empname in the procedure above should be of type CHAR in ANSI versions of FairCom DB SQL.

 

DhSQLResultSet.makeNULL

Sets a field of the currently-active row in a procedure's result set to null. This method is redundant with using the DhSQLResultSet.set() method to set a procedure result-set field to null.

Format

public void makeNULL(int field)

Returns

None

Parameters

field

An integer that specifies which field of the result-set row to set to null (1 denotes the first field in the row, 2 denotes the second, and so on).

Throws

DhSQLException

Example


CREATE PROCEDURE test_makeNULL2(
    IN char_in CHAR(20))
RESULT ( res_char CHAR(20) , res_vchar VARCHAR(30))
BEGIN
    SQLResultSet.set(1,char_in);
    SQLResultSet.makeNULL(2);
END

Note: The input parameter char_in in the procedure above should be of type CHAR in ANSI versions of FairCom DB SQL.

 

DhSQLResultSet.insert

Inserts the currently-active row into a procedure’s result set.

Format

public void insert()

Returns

None

Parameters

None

Throws

DhSQLException

Example


CREATE PROCEDURE get_sal2 ()
RESULT (
    empname CHAR(20),
    empsal   NUMERIC,
)
IMPORT
import java.math.BigDecimal;
BEGIN
    StringBuffer ename = new StringBuffer (20) ;
    BigDecimal esal = new BigDecimal () ;
    SQLCursor empcursor = new SQLCursor (
        "SELECT name, sal FROM emp " ) ;
   
    empcursor.open () ;
    do
    {
        empcursor.fetch ();
        if (empcursor.found ())
        {
           ename = (String)empcursor.getValue (1, CHAR);
           esal = (BigDecimal)empcursor.getValue (2, NUMERIC);

            SQLResultSet.set (1, ename);
            SQLResultSet.set (2, esal);
            SQLResultSet.insert ();
        }
    } while (empcursor.found ()) ;
    empcursor.close () ;
END

 Note: The resultset parameter empname in the procedure above should be of type CHAR in ANSI versions of FairCom DB SQL.

 

SQLCursor

Description

Methods of the SQLCursor class retrieve rows of data from a database or another stored procedure’s result set.

Constructors

SQLCursor (String statement)

Parameters

statement

A FairCom DB SQL statement that generates a result set. Enclose the statement in double quotes. The FairCom DB SQL statement is either a SELECT or CALL statement:

  • A SELECT statement queries the database and returns data that meets the criteria specified by the query expression in the SELECT statement.
  • A CALL statement invokes another stored procedure that returns a result set specified by the RESULT clause of the CREATE PROCEDURE statement.

Throws

DhSQLException

The following excerpt from a stored procedure instantiates an SQLCursor object called cust_cursor that retrieves data from a database table.

Example


SQLCursor empcursor = new SQLCursor ("SELECT name, sal FROM emp " ) ;

The following excerpt from a stored procedure instantiates an SQLCursor object called cust_cursor that calls another stored procedure.

Example with Nested Stored Procedure


SQLCursor cust_cursor = new SQLCursor ("CALL get_customers (?) ") ;

 

SQLCursor.close

Closes the result set specified by the SELECT or CALL statement.

Format

public void close()

Returns

None

Parameters

None

Throws

DhSQLException

Example


.
.
.
        if (cust_cursor.Found ())
        {
                cust_cursor.getValue (1, INTEGER);
                cust_cursor.getValue (2, CHAR) ;
        }
        else
                break;
    }

    cust_cursor.close () ;

 

SQLCursor.fetch

Fetches the next record in a result set, if there is one.

Format

public void fetch()

Returns

None

Parameters

None

Throws

DhSQLException

Example


for (;;)
{
    cust_cursor.fetch ();
    if (cust_cursor.found ())
    {
            cust_cursor.getValue (1, INTEGER);
            cust_cursor.getValue (2, CHAR) ;
    }
    else
            break;
}

 

SQLCursor.found

Checks whether a fetch operation returned a record.

Format

public boolean found ()

Returns

True if the previous call to fetch() returned a record, false otherwise.

Parameters

None

Throws

DhSQLException

Example


for (;;)
{
    cust_cursor.fetch ();
    if (cust_cursor.found ())
    {
            cust_cursor.getValue (1, INTEGER);
            cust_cursor.getValue (2, CHAR) ;
    }
    else
            break;
}

 

SQLCursor.getLongValue

Retrieves a chunk of a LONG VARCHAR field (in case the field content is too large).

Format

public Object getLongValue(int field, int offset, int len)

Parameters

  • field the field number
  • offset the starting point (0 based) where the portion you want to retrieve starts.
  • len the length of the portion to retrieve.

Returns

Returns NULL if there is no more to retrieve.

Throws

DhSQLException

 

SQLCursor.getParam

When a procedure is called from another procedure, this method returns the value of the specified OUT/INOUT parameter of the called procedure as a Java object. This returned object must be typecasted to the appropriate type. This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public Object getParam(int field, short dType)

Returns

Returns the Object specified by the field value.

Parameters

field

An integer that specifies which argument value of the called procedure is to be returned (1 denotes the first parameter, 2 denotes the second, and so on).

If the specified parameter does not exist, FairCom DB SQL returns an error:

(error(-20145): Invalid field reference.)

dType

The expected data type of the returning parameter.

Throws

DhSQLException

Example


CREATE PROCEDURE swap_proc(IN param1 INTEGER,
                           OUT param2 INTEGER,
                           INOUT param3 INTEGER
                          )
BEGIN
    param2 = param3;
    param3 = param1;
END

CREATE PROCEDURE call_swap_proc()
BEGIN
    Integer val1 = new Integer(10);
    Integer val2;
    Integer val3 = new Integer(20);
    SQLCursor tmp_cur = new SQLCursor("CALL swap_proc(?,?,?)");
    tmp_cur.registerOutParam(2, INTEGER);
    tmp_cur.registerOutParam(3, INTEGER);
    tmp_cur.setParam(1, val1);
    tmp_cur.setParam(3, val3);
    tmp_cur.open();
    val2 = (Integer)tmp_cur.getParam(2, INTEGER);
    val3 = (Integer)tmp_cur.getParam(3, INTEGER);
    // process the val2 and val3
- - -
tmp_cur.close();
END

 

SQLCursor.getValue

Returns the value of the specified field of the fetched row of a cursor or result set as a Java object. This returned object must be typecasted to an appropriate SQL type.

Format

public Object getValue(int field, short dType)

Returns

Returns the Object specified by the field value.

Parameters

field

An integer that specifies which field of the fetched record is of interest. getValue() retrieves the value in the currently-fetched record of the column denoted by field (1 denotes the first column of the result set, 2 denotes the second, and so on).

The value in the column denoted by field cannot be null, or FairCom DB SQL returns an error:

(error(-20144): Null value fetched.)

This means you must always check whether a value is null before attempting to assign a value in an SQL result set to a procedure variable or output parameter. The SQLCursor class provides the wasNULL() method for this purpose. See Section "SQLCursor.wasNULL" for details.

dType

The expected data type of the return Object being returned.

Throws

DhSQLException

Example


CREATE PROCEDURE test_nulls2()
RESULT (col1 INTEGER,
        col2 INTEGER,
        col3 INTEGER)
BEGIN
     Integer pvar_int1      = new Integer(0);
     Integer pvar_int2      = new Integer(0);
     Integer pvar_int3      = new Integer(0);
     SQLCursor select_t1 = new SQLCursor
     ( "SELECT c1, c2, c3 from t1" );
    
     select_t1.open();
     select_t1.fetch();
     while ( select_t1.found() )
     {
         // Assign values from the current row of the SQL result set
         // to the pvar_intx procedure variables. Must first check
         // whether the values fetched are null: if they are, must set
         // pvars explicitly to null.
      if ((select_t1.wasNULL(1)) == true)
            pvar_int1 = null;
      else
            pvar_int1 = (Integer)select_t1.getValue(1,INTEGER);
      if ((select_t1.wasNULL(2)) == true)
            pvar_int2 = null;
      else
            pvar_int2 = (Integer)select_t1.getValue(2,INTEGER);
      if ((select_t1.wasNULL(3)) == true)
            pvar_int3 = null;
      else
            pSQLResultSet.set(1,pvar_int1);
            SQLResultSet.set(2,pvar_int2);
            SQLResultSet.set(3,pvar_int3);
            SQLResultSet.insert();
            select_t1.fetch();
      }
      select_t1.close();
END

 

SQLCursor.makeNULL

Sets the value of a FairCom DB SQL statement’s input parameter to null. This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes. This method is redundant with using the setParam() method to set a statement’s input parameter to null.

Format

public void makeNULL(int f)

Returns

None

Parameters

f

An integer that specifies which input parameter of the FairCom DB SQL statement string to set to null (1 denotes the first input parameter in the statement, 2 denotes the second, and so on).

Throws

DhSQLException

Example


CREATE PROCEDURE sc_makeNULL()
BEGIN
     SQLCursor select_btypes = new SQLCursor (
         "SELECT small_fld from sfns where small_fld = ? ");

     select_btypes.makeNULL(1);
     select_btypes.open();
     select_btypes.fetch();
     select_btypes.close();

END

 

SQLCursor.open

Opens the result set specified by the SELECT or CALL statement.

Format

public void open()

Returns

None

Parameters

None

Throws

DhSQLException

Example


SQLCursor empcursor = new SQLCursor (
    "SELECT name, sal FROM emp " ) ;
    empcursor.open () ;

 

SQLCursor.registerOutParam

Registers the expected type of OUT and INOUT parameters. This method is common for SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public void registerOutParam(int pIndex, short dType)

Returns

None

Parameters

pindex

An integer that specifies which OUT/INOUT parameter is to be registered (1 denotes the first parameter, 2 denotes the second, and so on).

dtype

The expected type of the OUT/INOUT parameter.

Note: SQLCursor class has another form of registerOutParam(), which takes three arguments. The syntax of this method is:

public void registerOutParam(int pIndex, short dType, short scale)

pIndex and dType are the same as the two arguments in SQLCursor.registerOutParam() method. The scale specifies the number of digits after the decimal point.
This method is not implemented in FairCom DB SQL and invocation of this method results in error:

“Scale for registerOutParam not implemented”.

Throws

DhSQLException

Example


   CREATE PROCEDURE register_proc()
BEGIN
    // cust_proc is a procedure with an IN, OUT and an INOUT arguments of type
    // integer, string and numeric respectively.
    SQLCursor cust_cur = new SQLCursor("call cust_proc(?,?,?)");
    cust_cur.registerOutParam(2, CHAR);
    cust_cur.registerOutParam(3, NUMERIC);
    cust_cur.open();
    // Process results
cust_cur.close();
END

 

SQLCursor.rowCount

Returns the number of rows affected (selected, inserted, updated, or deleted) by the FairCom DB SQL statement. This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public int rowCount()

Returns

An integer indicating the number of rows.

Parameters

None

Throws

DhSQLException

The following example uses the rowCount() method of the SQLIStatement class. It nests the method invocation within SQLResultSet.set() to store the number of rows affected (1, in this case) in the procedure’s result set.

Example


CREATE PROCEDURE sis_rowCount()
RESULT ( ins_recs BIGINT )
BEGIN
     SQLIStatement insert_test103 = new SQLIStatement (
     "INSERT INTO test103 (fld1) values (17)");

     insert_test103.execute();
     SQLResultSet.set(1,new Long(insert_test103.rowCount()));
     SQLResultSet.insert();
END

 

SQLCursor.setParam

Sets the value of a FairCom DB SQL statement’s input parameter to the specified value (a literal, procedure variable, or procedure input parameter). This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public void setParam(int f, Object val)

Returns

None

Parameters

f

An integer that specifies which parameter marker in the FairCom DB SQL statement is to receive the value (1 denotes the first parameter marker, 2 denotes the second, and so on).

val

A literal or the name of a variable or input parameter that contains the value to be assigned to the parameter marker.

Throws

DhSQLException

Example


CREATE PROCEDURE sps_setParam()
BEGIN
     // Assign local variables to be used as SQL input parameter references
     Integer ins_fld_ref   = new Integer(1);
     Integer ins_small_fld = new Integer(3200);
     Integer ins_int_fld   = new Integer(21474);
     Double  ins_doub_fld  = new Double(1.797E+30);
     StringBuffer  ins_char_fld  = new StringBuffer("Athula");
     StringBuffer  ins_vchar_fld = new StringBuffer("Scientist");
     Float   ins_real_fld  = new Float(17);

     SQLPStatement insert_sfns1 = new SQLPStatement ("INSERT INTO sfns"
              + "(fld_ref,small_fld,int_fld,doub_fld,char_fld,vchar_fld)"
              + "values (?,?,?,?,?,?)" );

     insert_sfns1.setParam(1,ins_fld_ref);
     insert_sfns1.setParam(2,ins_small_fld);
     insert_sfns1.setParam(3,ins_int_fld);
     insert_sfns1.setParam(4,ins_doub_fld);
     insert_sfns1.setParam(5,ins_char_fld);
     insert_sfns1.setParam(6,ins_vchar_fld);
     insert_sfns1.execute();
END

 

SQLCursor.wasNULL

Checks if the value in a fetched field is null.

Format

public boolean wasNULL(int field)

Returns

True if the field is null, false otherwise.

Parameters

field

An integer that specifies which field of the fetched record is of interest (1 denotes the first column of the result set, 2 denotes the second, and so on). wasNULL() checks whether the value in the currently-fetched record of the column denoted by field is null.

Throws

DhSQLException

Example


CREATE PROCEDURE test_wasNULL()
BEGIN
     int small_sp = new Integer(0);
     SQLCursor select_btypes = new SQLCursor ("SELECT small_fld from sfns");
     select_btypes.open();
     select_btypes.fetch();
     if ((select_btypes.wasNULL(1)) == true)
            small_sp = null;
     else
            select_btypes.getValue(1,INTEGER);
     select_btypes.close();
END

 

SQLIStatement

Description

Methods of the SQLIStatement class provide for immediate (one-time) execution of FairCom DB SQL statements that do not generate a result set.

Note: SQLIStatement can be used to call stored procedures that do not have result sets.

Constructors

SQLIStatement (String statement)

Parameters

statement

A FairCom DB SQL statement that does not generate a result set. Enclose the statement in double quotes.

Throws

DhSQLException

Example


CREATE PROCEDURE insert_customer (
   IN  cust_number INTEGER,
   IN  cust_name   CHAR(20)
)
BEGIN
    SQLIStatement insert_cust = new SQLIStatement
           ("INSERT INTO customer VALUES (?,?) ");
    insert_cust.execute();
END

 Note: The input parameter cust_name in the procedure above should be of type CHAR in ANSI versions of FairCom DB SQL.

 

SQLIStatement.execute

Executes the FairCom DB SQL statement. This method is common to the SQLIStatement and SQLPStatement classes.

Format

public void execute()

Returns

None

Parameters

None

Throws

DhSQLException

Example


CREATE PROCEDURE insert_customer (
   IN  cust_number INTEGER,
   IN  cust_name   CHAR(20)
)
BEGIN
    SQLIStatement insert_cust = new SQLIStatement (
       "INSERT INTO customer VALUES (?,?) ");
    insert_cust.setParam (1, cust_number);
    insert_cust.setParam (2, cust_name);
    insert_cust.execute ();
END

 

SQLIStatement.getParam

When a procedure is called from another procedure, this method returns the value of the specified OUT/INOUT parameter of called procedure as a Java object. This returned object must be typecasted to the appropriate type.

Format

public Object getParam(int field, short dType)

Returns

Returns the Object specified by the field value.

Parameters

field

An integer that specifies which argument value of the called procedure is to be returned (1 denotes the first parameter, 2 denotes the second, and so on).

If the specified parameter does not exists, FairCom DB SQL returns an error:

(error(-20145): Invalid field reference.)

dType

The expected data type of the returning parameter.

Throws

DhSQLException

Example


CREATE PROCEDURE swap_proc(IN param1 INTEGER,
                           OUT param2 INTEGER,
                           INOUT param3 INTEGER
                          )
BEGIN
    param2 = param3;
    param3 = param1;
END

CREATE PROCEDURE call_swap_proc()
BEGIN
    Integer val1 = new Integer(10);
    Integer val2;
    Integer val3 = new Integer(20);
    SQLIStatement istmt = new SQLIStatement("CALL swap_proc(?,?,?)");
    istmt.registerOutParam(2, INTEGER);
    istmt.registerOutParam(3, INTEGER);
    istmt.setParam(1, val1);
    istmt.setParam(3, val3);
    istmt.execute();
    val2 = (Integer)istmt.getParam(2, INTEGER);
    val3 = (Integer)istmt.getParam(3, INTEGER);
    // process the val2 and val3
END

 

SQLIStatement.makeNULL

Sets the value of a FairCom DB SQL statement’s input parameter to null. This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes. This method is redundant with using the setParam() method to set a statement’s input parameter to null.

Format

public void makeNULL(int f)

Returns

None

Parameters

f

An integer that specifies which input parameter of the FairCom DB SQL statement string to set to null (1 denotes the first input parameter in the statement, 2 denotes the second, and so on).

Throws

DhSQLException

Example


CREATE PROCEDURE sis_makeNULL()
BEGIN
     SQLIStatement insert_sfns1 = new SQLIStatement ("INSERT INTO sfns"
     + "(fld_ref,small_fld,int_fld,doub_fld,char_fld,vchar_fld)"
     + "values (?,?,?,?,?,?)");
     insert_sfns1.setParam(1,new Integer(66));
     insert_sfns1.makeNULL(2);
     insert_sfns1.makeNULL(3);
     insert_sfns1.makeNULL(4);
     insert_sfns1.makeNULL(5);
     insert_sfns1.makeNULL(6);
     insert_sfns1.execute();
END

 

SQLIStatement.registerOutParam

This method registers the expected type of OUT and INOUT parameters. This method is common for SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public void registerOutParam(int pIndex, short dType)

Returns

None

Parameters

pIndex

An integer that specifies which OUT/INOUT parameter is to be registered (1 denotes the first parameter, 2 denotes the second, and so on).

dType

The expected type of the OUT/INOUT parameter.

Throws

DhSQLException

Example


CREATE PROCEDURE register_proc()
BEGIN
    // cust_proc is a procedure with an IN, OUT and an INOUT arguments of type
    // integer, string and numeric respectively.
    SQLIStatement istmt = new SQLIStatement("call cust_proc(?,?,?)");
    istmt.registerOutParam(2, CHAR);
    istmt.registerOutParam(3, NUMERIC);
    istmt.execute();
    // Process results
END

 

SQLIStatement.rowCount

Returns the number of rows affected (selected, inserted, updated, or deleted) by the FairCom DB SQL statement. This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public int rowCount()

Returns

An integer indicating the number of rows.

Parameters

None

Throws

DhSQLException

The following example uses the rowCount() method of the SQLIStatement class. It nests the method invocation within SQLResultSet.set() to store the number of rows affected (1, in this case) in the procedure’s result set.

Example


CREATE PROCEDURE sis_rowCount()
RESULT ( ins_recs BIGINT )
BEGIN
     SQLIStatement insert_test103 = new SQLIStatement (
     "INSERT INTO test103 (fld1) values (17)");

     insert_test103.execute();
     SQLResultSet.set(1,new Long(insert_test103.rowCount()));
     SQLResultSet.insert();
END

 

SQLIStatement.setParam

Sets the value of a FairCom DB SQL statement’s input parameter to the specified value (a literal, procedure variable, or procedure input parameter). This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public void setParam(int f, Object val)

Returns

None

Parameters

  • f An integer that specifies which parameter marker in the FairCom DB SQL statement is to receive the value (1 denotes the first parameter marker, 2 denotes the second, and so on).
  • val A literal or the name of a variable or input parameter that contains the value to be assigned to the parameter marker.

Throws

DhSQLException

Example


CREATE PROCEDURE sps_setParam()
BEGIN
     // Assign local variables to be used as SQL input parameter references
     Integer ins_fld_ref   = new Integer(1);
     Integer ins_small_fld = new Integer(3200);
     Integer ins_int_fld   = new Integer(21474);
     Double  ins_doub_fld  = new Double(1.797E+30);
     StringBuffer  ins_char_fld  = new StringBuffer("Athula");
     StringBuffer  ins_vchar_fld = new StringBuffer("Scientist");
     Float   ins_real_fld  = new Float(17);

     SQLPStatement insert_sfns1 = new SQLPStatement ("INSERT INTO sfns"
     + "(fld_ref,small_fld,int_fld,doub_fld,char_fld,vchar_fld)"
     + "values (?,?,?,?,?,?)" );

     insert_sfns1.setParam(1,ins_fld_ref);
     insert_sfns1.setParam(2,ins_small_fld);
     insert_sfns1.setParam(3,ins_int_fld);
     insert_sfns1.setParam(4,ins_doub_fld);
     insert_sfns1.setParam(5,ins_char_fld);
     insert_sfns1.setParam(6,ins_vchar_fld);
     insert_sfns1.execute();
END

 

SQLPStatement

Description

Methods of the SQLPStatement class provide for prepared (repeated) execution of c-treeSQL statements that do not generate a result set.

Note: SQLPStatement can be used to call stored procedures that do not have result sets.

Constructors

SQLPStatement (String statement)

Parameters

statement

A c-treeSQL statement that does not generate a result set. Enclose the statement in double quotes.

Throws

DhSQLException

Example


SQLPStatement pstmt = new SQLPStatement (
    "INSERT INTO T1 VALUES (?, ?) ") ;
.
.
.

 

SQLPStatement.execute

Executes the FairCom DB SQL statement. This method is common to the SQLIStatement and SQLPStatement classes.

Format

public void execute()

Returns

None

Parameters

None

Throws

DhSQLException

Example


CREATE PROCEDURE test_pstmt()
BEGIN
   SQLPStatement pstmt = new SQLPStatement ( "INSERT INTO T1 VALUES (?, ?) ") ;
   pstmt.setParam (1, new Integer(10));
   pstmt.setParam (2, new Integer(10));
   pstmt.execute ();
   pstmt.setParam (1, new Integer(20));
   pstmt.setParam (2, new Integer(20));
   pstmt.execute ();
END

 

SQLPStatement.getParam

When a procedure is called from another procedure, this method returns the value of the specified OUT/INOUT parameter of the called procedure as a Java object. This returned object must be typecasted to the appropriate type.

Format

public Object getParam(int field, short dType)

Returns

Returns the Object specified by the field value.

Parameters

field

An integer that specifies which argument value of the called procedure is to be returned (1 denotes the first parameter, 2 denotes the second, and so on).

If the specified parameter does not exists, FairCom DB SQL returns an error:

(error(-20145): Invalid field reference.)

dType

The expected data type of the returning parameter.

Throws

DhSQLException

Example


CREATE PROCEDURE swap_proc(IN param1 INTEGER,
                           OUT param2 INTEGER,
                           INOUT param3 INTEGER)
BEGIN
    param2 = param3;
    param3 = param1;
END

CREATE PROCEDURE call_swap_proc()
BEGIN
    Integer val1 = new Integer(10);
    Integer val2;
    Integer val3 = new Integer(20);
    SQLPStatement pstmt = new SQLPStatement("CALL swap_proc(?,?,?)");
    pstmt.registerOutParam(2, INTEGER);
    pstmt.registerOutParam(3, INTEGER);
    pstmt.setParam(1, val1);
    pstmt.setParam(3, val3);
    pstmt.execute();
    val2 = (Integer)pstmt.getParam(2, INTEGER);
    val3 = (Integer)pstmt.getParam(3, INTEGER);
    // process the val2 and val3
END

 

SQLPStatement.makeNULL

Sets the value of a FairCom DB SQL statement’s input parameter to null. This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes. This method is redundant with using the setParam() method to set a statement’s input parameter to null.

Format

public void makeNULL(int f)

Returns

None

Parameters

f

An integer that specifies which input parameter of the FairCom DB SQL statement string to set to null (1 denotes the first input parameter in the statement, 2 denotes the second, and so on).

Throws

DhSQLException

Example


CREATE PROCEDURE sps_makeNULL()
BEGIN
     SQLPStatement insert_sfns1 = new SQLPStatement ("INSERT INTO sfns"
      + "(fld_ref,small_fld,int_fld,doub_fld,char_fld,vchar_fld)"
      + "values (?,?,?,?,?,?)" );
     insert_sfns1.setParam(1,new Integer(666));
     insert_sfns1.makeNULL(2);
     insert_sfns1.makeNULL(3);
     insert_sfns1.makeNULL(4);
     insert_sfns1.makeNULL(5);
     insert_sfns1.makeNULL(6);
     insert_sfns1.execute();
END

 

SQLPStatement.registerOutParam

This method registers the expected Type of OUT and INOUT parameters. This method is common for SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public void registerOutParam(int pIndex, short dType)

Returns

None

Parameters

pIndex

An integer that specifies which OUT/INOUT parameter is to be registered (1 denotes the first parameter, 2 denotes the second, and so on).

dType

The expected type of the OUT/INOUT parameter.

Throws

DhSQLException

Example


CREATE PROCEDURE register_proc()
BEGIN
    // cust_proc is a procedure with an IN, OUT and an INOUT arguments of types
    // integer, string and numeric respectively.
    SQLPStatement pstmt = new SQLPStatement("call cust_proc(?,?,?)");
    pstmt.registerOutParam(2, CHAR);
    pstmt.registerOutParam(3, NUMERIC);
    pstmt.execute();
    // Process results
END

 

SQLPStatement.rowCount

Returns the number of rows affected (selected, inserted, updated, or deleted) by the SQL statement. This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public int rowCount()

Returns

An integer indicating the number of rows.

Parameters

None

Throws

DhSQLException

This example uses the rowCount() method of the SQLIStatement class. It nests the method invocation within SQLResultSet.set() to store the number of rows affected (1, in this case) in the procedure’s result set.

Example


CREATE PROCEDURE sis_rowCount()
RESULT ( ins_recs BIGINT )
BEGIN
     SQLIStatement insert_test103 = new SQLIStatement (
     "INSERT INTO test103 (fld1) values (17)");

     insert_test103.execute();
     SQLResultSet.set(1,new Long(insert_test103.rowCount()));
     SQLResultSet.insert();
END

 

SQLPStatement.setParam

Sets the value of a FairCom DB SQL statement’s input parameter to the specified value (a literal, procedure variable, or procedure input parameter). This method is common to the SQLCursor, SQLIStatement, and SQLPStatement classes.

Format

public void setParam(int f, Object val)

Returns

None

Parameters

f

An integer that specifies which parameter marker in the FairCom DB SQL statement is to receive the value (1 denotes the first parameter marker, 2 denotes the second, and so on).

val

A literal or the name of a variable or input parameter that contains the value to be assigned to the parameter marker.

Throws

DhSQLException

Example


CREATE PROCEDURE sps_setParam()
BEGIN
     // Assign local variables to be used as SQL input parameter references
     Integer ins_fld_ref   = new Integer(1);
     Integer ins_small_fld = new Integer(3200);
     Integer ins_int_fld   = new Integer(21474);
     Double  ins_doub_fld  = new Double(1.797E+30);
     StringBuffer  ins_char_fld  = new StringBuffer("Athula");
     StringBuffer  ins_vchar_fld = new StringBuffer("Scientist");
     Float   ins_real_fld  = new Float(17);

     SQLPStatement insert_sfns1 = new SQLPStatement ("INSERT INTO sfns"
      + "(fld_ref,small_fld,int_fld,doub_fld,char_fld,vchar_fld)"
      + "values (?,?,?,?,?,?)" );

     insert_sfns1.setParam(1,ins_fld_ref);
     insert_sfns1.setParam(2,ins_small_fld);
     insert_sfns1.setParam(3,ins_int_fld);
     insert_sfns1.setParam(4,ins_doub_fld);
     insert_sfns1.setParam(5,ins_char_fld);
     insert_sfns1.setParam(6,ins_vchar_fld);
     insert_sfns1.execute();
END

 

Using FairCom DB SQL Java Classes

This section describes how to use included FairCom DB SQL Java classes to issue and process FairCom DB SQL statements in Java stored procedures. FairCom DB SQL Java classes are found in the ctreeSQLSP.jar file located in the <faircom>\server\classes directory of your FairCom DB installation.

To process FairCom DB SQL statements in a stored procedure, you need to know whether the SQL statement generates results (in other words, if the statement is a query) or not. SELECT statements, for example, generate results: they retrieve data from one or more database tables and return the results as rows in a table.

Whether a statement generates such an SQL result set dictates which FairCom DB SQL Java classes you use to issue it:

  • To issue FairCom DB SQL statements that do not generate results (such as INSERT, GRANT, or CREATE), use either the SQLIStatement class (for one-time execution) or the SQLPStatement class (for repeated execution).
  • To issue FairCom DB SQL statements that generate results (SELECT and, in some cases, CALL), use the SQLCursor class to retrieve rows from a database or another procedure’s result set.

In either case, if you want to return a result set to the application, use the DhSQLResultSet class to store rows of data in a procedure result set. You must use DhSQLResultSet() methods to transfer data from an SQL result set to the procedure result set for the calling application to process it. You can also use DhSQLResultSet() methods to store rows of data generated internally by the procedure.

In addition, FairCom DB SQL provides the DhSQLException class so procedures can process and generate Java exceptions through the standard Java try { }, catch { }, and throw { } constructs.

 

Passing Values to SQL Statements

Stored procedures need to be able to pass and receive values from FairCom DB SQL statements they execute. They do this through the setParam() and getValue() methods.

 

The setParam Method: Pass Input Values to SQL Statements

The setParam() method sets the value of a FairCom DB SQL statement’s parameter marker to the specified value (a literal, a procedure variable, or a procedure input parameter).

The setParam() method takes two arguments:

setParam ( marker_num , value ) ;

  • marker_num is an integer that specifies which parameter marker in the SQL statement is to receive the value (1 denotes the first parameter marker, 2 denotes the second, and so on).
  • value is a literal or the name of a variable or input parameter that contains the value to be assigned to the parameter marker.

The following example shows an excerpt from a stored procedure that uses setParam() to assign values from two procedure variables to the parameter markers in an SQL INSERT statement. When the procedure executes, it substitutes the value of the cust_number procedure variable for the first parameter marker and the value of the cust_name variable for the second parameter marker.

setParam() and FairCom DB SQL Statement Input Parameters


        SQLIStatement insert_cust = new SQLIStatement (
            "INSERT INTO customer VALUES (?,?) ");

        insert_cust.setParam (1, cust_number);
        insert_cust.setParam (2, cust_name);
.
.
.

 

The getValue Method: Pass Values from SQL Result Sets to Variables

The getValue() method of the SQLCursor class assigns a single value from an SQL result set (returned by an SQL query or another stored procedure) to a procedure variable or output parameter.

The format and arguments for getValue() are as follows:

getValue ( col_num , data_type ) ;

The getValue() interface returns an object, it should be explicitly typecasted to appropriate type.

  • col_num is an integer that specifies which column of the result set is of interest. getValue() retrieves the value in the currently-fetched record of the column denoted by col_num. (1 denotes the first column of the result set, 2 denotes the second, and so on).
  • data_type specifies the expected FairCom DB SQL type of the returned parameter (see Implicit Data Type Conversion Between SQL and Java Types for details on how FairCom DB SQL data types map to Java data types).

The following example shows an excerpt from a stored procedure that uses getValue() to assign values from two result-set columns to procedure variables. In this example, the result set is generated by a FairCom DB SQL SELECT statement.

Using getValue() to Pass Values from Result Sets


    StringBuffer ename = new StringBuffer (20) ;
    java.math.BigDecimal esal = new java.math.BigDecimal () ;

    SQLCursor empcursor = new SQLCursor (
        "SELECT name, sal FROM emp " ) ;
   
    empcursor.open () ;
        empcursor.fetch ();
        if (empcursor.found ())
        {
            ename = (StringBuffer)empcursor.getValue (1, CHAR);
            esal = (BigDecimal)empcursor.getValue (2, DECIMAL);
.
.
.

In the SELECT statement in previous example, it was clear that the result set had two columns, name and sal. If the SELECT statement had used a wildcard in its select list (SELECT * FROM EMP) you have to know the structure of the EMP table in order to correctly specify the column numbers in the getValue() method.

 

Passing Values to and From Stored Procedures: Input and Output Parameters

Applications need to pass and receive values from the stored procedures they call. They do this through input and output parameters declared in the procedure specification.

Applications can pass and receive values from stored procedures using input and output parameters declared in the stored procedure specification. When it processes the CREATE PROCEDURE statement, FairCom DB SQLFairCom DB SQL declares Java variables of the same name. This means the body of the stored procedure can refer to input and output parameters as if they were Java variables declared in the body of the stored procedure.

Note: Procedure result sets are another way for applications to receive output values from a stored procedure. Procedure result sets provide output in a row-oriented tabular format. See Returning a Procedure Result Set: the RESULT Clause and DhSQLResultSet.

Parameter declarations include the parameter type (IN, OUT, or INOUT), the parameter name, and c-treeSQL data type (see Implicit Data Type Conversion Between SQL and Java Types for details of how FairCom DB SQL data types map to Java data types).

Declare input and output parameters in the specification section of a stored procedure, as shown in the following example.

Example Input, Output, and Input-Output Parameters


CREATE PROCEDURE order_entry (
    IN  cust_name    CHAR(20),
    IN  item_num     INTEGER,
    IN  quantity     INTEGER,
    OUT status_code  INTEGER,
    INOUT order_num  INTEGER
)
.
.
.

 Note: The input parameter cust_name in the procedure above should be of type CHAR in ANSI versions of FairCom DB SQL.

When the order_entry stored procedure executes, the calling application passes values for the cust_name, item_num, quantity, and order_num input parameters. The body of the procedure refers to them as Java variables. Similarly, Java code in the body of order_entry processes and returns values in the status_code and order_num output parameters. The variable order_num can be used for both passing input and receiving output value from the procedure.

Note: Procedure parameter names should always be lower case as parameter names are treated as identifiers in the FairCom DB SQL statement and are converted to lowercase by FairCom DB SQL. Parameter names used within the procedure body are not converted to lower case. Hence declaring parameters with upper case may lead to compilation errors.

 

Implicit Data Type Conversion Between SQL and Java Types

When FairCom DB SQL creates a stored procedure, it converts the type of any input and output parameters (see The setParam Method: Pass Input Values to SQL Statements) from the FairCom DB SQL data types in the procedure specification to Java wrapper types.

The Java.lang package defines classes for all the primitive Java types that “wrap” values of the corresponding primitive type in an object. FairCom DB SQL converts the FairCom DB SQL data types declared for input and output parameters to one of these wrapper types, described in the table below.

You must be sure to use wrapper types when declaring procedure variables to use as arguments to the getValue(), setParam(), and set methods. These methods take objects as arguments and will generate compilation errors if you pass a primitive type to them.

The following example shows two stored procedures. The first tries to use a variable declared as the Java int primitive type as an argument to the SQLResultSet.set() method, and will generate a compilation error. The second correctly declares the variable using the integer wrapper class.

Using Wrapper Types as Arguments to FairCom DB SQL Classes


CREATE PROCEDURE type_mismatch( )
RESULT (res_int INTEGER )
BEGIN
     // Create a variable as (primitive) type int
     // to test the working of set method of SQLResultSet
     int pvar_int = 4;

     // Transfer the value from the procedure variable to the result set.
     SQLResultSet.set(1,pvar_int); //Error!

     // Insert the row into the procedure result set.
     SQLResultSet.insert();
END
CREATE PROCEDURE type_okmatch( )
RESULT (res_int INTEGER )
BEGIN
     // Create a variable as (wrapper) type Integer
     Integer pvar_int = new Integer(4);

     // Transfer the value from the procedure variable to the result set.
     SQLResultSet.set(1,pvar_int); //Success!

     // Insert the row into the procedure result set.
     SQLResultSet.insert();
END

 When the SQL engine submits the Java class it creates from the stored procedure to the Java compiler, the compiler checks for data-type consistency between the converted parameters and variables you declare in the body of the stored procedure.

To avoid type mismatch errors, use the data-type mappings shown in the following table for declaring parameters and result-set fields in the procedure specification and the Java variables in the procedure body.
 

SQL Type Java Wrapper Type Enumeration Type
CHAR String CHAR
NCHAR String NCHAR
VARCHAR String VARCHAR
LONGVARCHAR String LONGVARCHAR
NVARCHAR String NVARCHAR
NUMERIC java.math.BigDecimal NUMERIC
DECIMAL java.math.BigDecimal DECIMAL
MONEY java.math.BigDecimal MONEY
BIT Boolean BIT
TINYINT byte[1] TINYINT
SMALLINT Integer SMALLINT
INTEGER Integer INTEGER
BIGINT Long BIGINT
REAL Float REAL
FLOAT Double FLOAT
DOUBLE PRECISION Double DOUBLE
BINARY byte[ ] BINARY
VARBINARY byte[ ] VARBINARY
LONGVARBINARY byte[ ] LONGVARBINARY
DATE java.sql.Date DATE
TIME java.sql.Time TIME
TIMESTAMP java.sql.Timestamp TIMESTAMP

 

Executing an SQL Statement

If a FairCom DB SQL statement does not generate a result set, stored procedures can execute it in one of two ways:

  • Immediate execution, using methods of the SQLIStatement class, executes a statement once.
  • Prepared execution, using methods of the SQLPStatement class, prepares a statement so you can execute it multiple times in a procedure loop.

Both SQLIStatement and SQLPStatement classes can be used to call stored procedures that do not have a RESULT clause (that is, the JSPs that do not return any resultset). Note that values of OUT and INOUT arguments can be retrieved using the getParam() method of SQLIStatement, SQLPStatement, and SQLCursor.

The following table shows the SQL statements that do not generate result sets. You can execute these statements in a stored procedure using either the SQLIStatement or SQLPStatement class.

Executable SQL Statements

ALTER TABLE DROP PROCEDURE
CALL (if no result set) DROP TABLE
CREATE INDEX DROP TRIGGER
CREATE SYNONYM DROP VIEW
CREATE PROCEDURE GRANT
CREATE TABLE INSERT
CREATE TRIGGER RENAME
CREATE VIEW REVOKE
DELETE UPDATE
DROP INDEX UPDATE STATISTICS
DROP SYNONYM  

 

Immediate Execution

Use immediate execution when a procedure needs to execute an SQL statement only once. The following example shows an instance of immediate execution.

Immediate Execution Example


CREATE PROCEDURE insert_customer (
   IN  cust_number INTEGER,
   IN  cust_name   CHAR(20)
)
BEGIN
    SQLIStatement insert_cust = new SQLIStatement (
       "INSERT INTO customer VALUES (?,?) ");
    insert_cust.setParam (1, cust_number);
    insert_cust.setParam (2, cust_name);
    insert_cust.execute ();
END

 Note: The input parameter cust_name in the procedure above should be of type CHAR in ANSI versions of FairCom DB SQL.

This example inserts a row in a table. The constructor for SQLIStatement() takes the FairCom DB SQL INSERT statement as its only argument. In this example, the statement includes two parameter markers.

 

Prepared Execution

Use prepared execution when you need to execute the same SQL statement repeatedly. Prepared execution avoids the overhead of creating multiple SQLIStatement objects for a single statement.

The advantage of prepared execution comes when you have the same FairCom DB SQL statement executed from within a loop. Instead of creating an object during each pass through the loop, prepared execution creates an object once and only passes input parameters for each execution of the statement.

Once a stored procedure creates a SQLPStatement object, it can execute it multiple times, supplying different values for each execution.

The following example extends the previous example to use prepared execution.

Prepared Execution Example


CREATE PROCEDURE prepared_insert_customer ()
IMPORT
import java.math.*;
BEGIN
    SQLPStatement p_insert_cust = new SQLPStatement (
       "INSERT INTO customer VALUES (?,?) ");
    int i;
    String [] [] new_custs ={
       {"01","ABC"},
       {"02","PQR"},
       {"03","XYZ"}
    };
    for (i=0; i<new_custs.length; i++)
       {
        p_insert_cust.setParam (1, Integer.valueOf (new_custs[i] [0]));
        p_insert_cust.setParam (2, new_custs[i] [1]);
        p_insert_cust.execute ();
       }
END

 

Retrieving Data: the SQLCursor Class

Methods of the SQLCursor class let stored procedures retrieve rows of data.

When stored procedures create an object from the SQLCursor class, they pass as an argument a FairCom DB SQL statement that generates a result set. The FairCom DB SQL statement is either a SELECT or CALL statement:

  • A SELECT statement queries the database and returns data that meets the criteria specified by the query expression in the SELECT statement.
  • A CALL statement invokes another stored procedure that returns a result set specified by the RESULT clause of the CREATE PROCEDURE statement.

Either way, once the procedure creates an object from the SQLCursor class, the processing of results sets follows the same steps:

  1. Open the cursor with the SQLCursor.open() method
  2. Check whether there are any records in the result set with the SQLCursor.found() method
  3. If there are records in the result set, loop through the result set:
    • Try to fetch a record with the SQLCursor.fetch() method
    • Check whether the fetch returned a record with the SQLCursor.found() method
    • If the fetch operation returned a record, assign values from the result-set record’s fields to procedure variables or procedure output parameters with the SQLCursor.getValue() method
    • Process the data in some manner
    • If the fetch operation did not return a record, exit the loop
  4. Close the cursor with the SQLCursor.close() method

The following example shows an example that uses SQLCursor() to process the result set returned by a FairCom DB SQL SELECT statement.

Processing a Result Set from a SELECT Statement


CREATE PROCEDURE get_sal ()
IMPORT
import java.math.BigDecimal;
BEGIN
    StringBuffer ename = new StringBuffer (20) ;
    BigDecimal esal = new BigDecimal () ;

    SQLCursor empcursor = new SQLCursor (
        "SELECT name, sal FROM emp " ) ;
   
    empcursor.open () ;
    empcursor.fetch ();
        while (empcursor.found ())
        {
            ename = (StringBuffer)empcursor.getValue (1, CHAR);
            esal = (BigDecimal)empcursor.getValue (2, DECIMAL);
            empcursor.fetch();
        }
    empcursor.close () ;
END

 Stored procedures also use SQLCursor objects to process a result set returned by another stored procedure. Instead of a SELECT statement, the SQLCursor() constructor includes a CALL statement that invokes the desired procedure.

The following example shows an excerpt from a stored procedure that processes the result set returned by another procedure, get_customers() customers which takes dept_no as input and returns two columns cust_number and cust_name as its result set.

Processing a Result Set from a CALL Statement


CREATE PROCEDURE get_customer()
IMPORT
import java.math.BigDecimal;
BEGIN
   SQLCursor cust_cursor = new SQLCursor ("CALL get_customers (?) ") ;
   Integer cust_number;
   StringBuffer cust_name;
   cust_cursor.setParam (1, new Integer(10));
   cust_cursor.open ();
   cust_cursor.fetch();
   while (cust_cursor.found())
      {
         cust_number = (Integer)cust_cursor.getValue (1, INTEGER);
         cust_name = (Stringz)cust_cursor.getValue (2, CHAR);
         cust_cursor.fetch ();
      }
   cust_cursor.close () ;
END

 

registerOutParam Method: registering the Type of OUT and INOUT Variables

Before executing a stored procedure call, you must explicitly call registerOutParam() to register the type of each OUT and INOUT parameter.

The registerOutParam() method of the SQLCursor class registers the type of OUT and INOUT parameters.

Syntax

The format and arguments for the registerOutParam() method are as follows:

registerOutParam( param_num , data_type ) ;

  • param_num - An integer that specifies which parameter of the called procedure is to be registered. (1 denotes the first parameter, 2 denotes the second, and so on).
  • data_type - Specifies the required SQL type of the returned parameter (see "Implicit Data Type Conversion Between SQL and Java Types" details of how SQL data types map to Java data types).

Limit: The number of arguments is limited to 50.

The following example shows an excerpt from a stored procedure that uses registerOutParam() interface to register the OUT and INOUT parameters.

registerOutParam() Interface Example


CREATE PROCEDURE get_sal (IN cust_num INTEGER,
                          OUT dept_num INTEGER,
                          INOUT salary DOUBLE PRECISION
                         )
BEGIN
    Integer dept = new Integer(40);
    Double incr = 0.25;

// select department number into dept using cust_num.
    dept_num = dept;
    salary = new Double(salary.doubleValue() + (salary.doubleValue) *
                        incr.double_Value());
END

CREATE PROCEDURE call_get_sal()
BEGIN
    Integer num = new Integer(54);
    Double sal = new Double(25000.00);
SQLCursor cust_cur = new SQLCursor("call get_sal(?,?,?)");
    cust_cur.setParam(1,num);
    cust_cur.registerOutParam(2,INTEGER);
    cust_cur.registerOutParam(3,DOUBLE);
    cust_cur.setParam(3,sal);
    cust_cur.open();

// process the data
    cust_cur.close();
END

If all the OUT and INOUT parameters are not registered, then sql engine returns an error: error(-20161): Not all OUT/INOUT parameters are registered.

 

Returning a Procedure Result Set with SQLResultSet

The get_sal() procedure in the previous example used the SQLCursor.getValue() method to store the values of a database record in individual variables. But the procedure did not do anything with those values, and they would be overwritten in the next iteration of the loop that fetches records. The RESULT section defines the columns

SQLResultSet derives from a lower DhSQLResultSet class and provides a way for a procedure to store rows of data in a procedure result set to be returned to the calling application. There can only be one procedure result set in a stored procedure.

A stored procedure must explicitly process a result set to return it to the calling application:

  • Declare the procedure result set through the RESULT clause of the procedure specification
  • Populate the procedure result set in the body of the procedure using the methods of SQLResultSet

When FairCom DB SQL creates a Java class from a CREATE PROCEDURE statement that contains the RESULT clause, it implicitly instantiates a SQLResultSet() object. Invoke methods of SQLResultSet() to populate fields and rows of the procedure result set.

SQLResultSet provides three methods:

  • SQLResultSet.set(col, val) - Set column col with value val in a result set row. Column positions are referred by numerical value with 1 as the first column
  • SQLResultSet.makeNULL(col) - Set column col as null
  • SQLResultSet.insert() - Insert a populated row into the result set

Limit: SQLResultSet is limited to 50 columns.

The following example processes a result set from a SELECT statement to return a procedure result set. For each row of the FairCom DB SQL result set assigned to procedure variables, the procedure:

  • Assigns the current values in the procedure variables to corresponding fields in the procedure result set with the SQLResultSet.set() method
  • Inserts a row into the procedure result set with the SQLResultSet.insert() method

Example Returning a Procedure Result Set From a Stored Procedure


CREATE PROCEDURE get_sal2 ()
RESULT (
    empname  CHAR(20),
    empsal   NUMERIC
)
IMPORT
import java.math.BigDecimal;
BEGIN
    StringBuffer ename = new StringBuffer (20) ;
    BigDecimal esal = new BigDecimal () ;
    SQLCursor empcursor = new SQLCursor (
        "SELECT name, sal FROM emp " ) ;
   
    empcursor.open () ;
    do
    {
        empcursor.fetch ();
        if (empcursor.found ())
        {
            ename = (StringBuffer)empcursor.getValue (1, CHAR);
            esal = (BigDecimal)empcursor.getValue (2, DECIMAL);
            SQLResultSet.set (1, ename);
            SQLResultSet.set (2, esal);
            SQLResultSet.insert ();
        }
    } while (empcursor.found ()) ;
    empcursor.close () ;
END

 Note: The resultset parameter empname in the procedure above should be of type CHAR in ANSI versions of FairCom DB SQL.

 

Handling Null Values

Stored procedures need to routinely set and detect null values:

  • Stored procedures may need to set the values of a FairCom DB SQL statement input parameters or procedure result fields to null.
  • Stored procedures must check if the value of a field in a FairCom DB SQL result set is null before assigning it through the SQLCursor.getValue() method. (FairCom DB SQL generates a runtime error if the result-set field specified in getValue() is null.)

 

Setting SQL Statement Input Params & Procedure Result SetFields to Null

Both the setParam() method (see “The setParam Method: Pass Input Values to SQL Statements”) and set() method (see “Returning a Procedure Result Set: the RESULT Clause and DhSQLResultSet”) take objects as their value arguments. You can pass a null reference directly to the method or pass a variable which has been assigned the null value. The following example shows using both techniques to set a FairCom DB SQL input parameter to null.

Example Passing Null Values to setParam()


CREATE PROCEDURE test_nulls( )
BEGIN
     Integer pvar_int1      = new Integer(0);
     Integer pvar_int2      = new Integer(0);
     Integer pvar_int3;
     pvar_int3 = null;
     SQLIStatement insert_t1 = new SQLIStatement
     ( "INSERT INTO ADMIN.t1 (c1,c2, c3) values (?,?,?) ");
     insert_t1.setParam(1, new Integer(1)); // Set to non-null value
     insert_t1.setParam(2, null);           // Set directly to null
     insert_t1.setParam(3, pvar_int3);      // Set indirectly to null
     insert_t1.execute();
END

 

Assigning Null Values from Result Sets:SQLCursor.wasNULL Method

If the value of the field argument to the SQLCursor.getValue() method is null, FairCom DB SQL returns a runtime error:

(error(-20144): Null value fetched.)

This means you must always check whether a value is null before attempting to assign a value in a FairCom DB SQL result set to a procedure variable or output parameter. The SQLCursor class provides the wasNULL() method for this purpose.

The SQLCuror.wasNULL() method returns TRUE if a field in the result set is null. It takes a single integer argument that specifies which field of the current row of the result set to check.

The following example illustrates using wasNULL().

Example Result Sets for Null Values with wasNULL()


CREATE PROCEDURE test_nulls2( )
RESULT ( res_int1 INTEGER ,
         res_int2 INTEGER ,
         res_int3 INTEGER )
BEGIN
     Integer pvar_int1      = new Integer(0);
     Integer pvar_int2      = new Integer(0);
     Integer pvar_int3      = new Integer(0);
     SQLCursor select_t1 = new SQLCursor
     ( "SELECT c1, c2, c3 from t1" );
    
     select_t1.open();
     select_t1.fetch();
     while ( select_t1.found() )
     {
         // Assign values from the current row of the SQL result set
         // to the pvar_intx procedure variables. Must first check
         // whether the values fetched are null: if they are, must set
         // pvars explicitly to null.
         if ((select_t1.wasNULL(1)) == true)
            pvar_int1 = null;
         else
            pvar_int1 = (Integer)select_t1.getValue(1, INTEGER);
         if ((select_t1.wasNULL(2)) == true)
            pvar_int2 = null;
         else
            pvar_int2 = (Integer)select_t2.getValue(2, INTEGER);
         if ((select_t1.wasNULL(3)) == true)
            pvar_int3 = null;
         else
            pvar_int3 = (Integer)select_t13getValue(3, INTEGER);
      // Transfer the value from the procedure variables to the
      // columns of the current row of the procedure result set.
         SQLResultSet.set(1,pvar_int1);
         SQLResultSet.set(2,pvar_int2);
         SQLResultSet.set(3,pvar_int3);
         // Insert the row into the procedure result set.
         SQLResultSet.insert();
        
         select_t1.fetch();
     }
     // Close the SQL result set.
     select_t1.close();
END

 

Handling Errors

FairCom DB SQL stored procedures use standard Java try/catch constructs to process exceptions.

Any errors in a FairCom DB SQL statement execution result in the creation of an DhSQLException class object. When FairCom DB SQL detects an error in an SQL statement, it throws an exception. The stored procedure should use try/catch constructs to process such exceptions. The getDiagnostics() method of the DhSQLException class object provides a mechanism to retrieve different details of the error.

The getDiagnostics() method takes a single argument whose value specifies which error message detail it returns:

getDiagnostics Method Arguments

Argument Value Returns
RETURNED_SQLSTATE The SQLSTATE returned by execution of the previous SQL statement.
MESSAGE_TEXT The condition indicated by RETURNED_SQLSTATE.
CLASS_ORIGIN Not currently used. Always returns null.
SUBCLASS_ORIGIN Not currently used. Always returns null.

The error messages and the associated SQLSTATE and FairCom DB SQL error code values are documented in the FairCom DB SQL Reference Manual, Table B-2.

The following example shows an excerpt from a stored procedure that uses DhSQLException.getDiagnostics().

Example Exception Handling with DhSQLException.getDiagnostics()


CREATE PROCEDURE test_proc()
BEGIN
   try
   {
      SQLIStatement insert_cust = new SQLIStatement (
      "INSERT INTO customer VALUES (1,2) ");
   }
   catch (DhSQLException e)
   {
      String errstate = e.getDiagnostics (DhSQLException.RETURNED_SQLSTATE) ;
      String errmesg = e.getDiagnostics (DhSQLException.MESSAGE_TEXT) ;
   }
END

 Stored procedures can also throw their own exceptions by instantiating a DhSQLException object and throwing the object when the procedure detects an error in execution. The conditions under which the procedure throws the exception object are completely dependent on the procedure.

The following example illustrates using the DhSQLException() constructor to create an exception object called excep. It then throws the excep object under all conditions.

Example Throwing Procedure-Specific Exceptions


CREATE PROCEDURE sp1_02()
BEGIN
     // raising exception
     DhSQLException excep = new DhSQLException(666,new String("Entered the tst02 procedure"));
     if (true)
     throw excep;
END

 

Calling Stored Procedures from Stored Procedures

Stored procedures and triggers can call other stored procedures. Nesting procedures lets you take advantage of existing procedures. Instead of rewriting the code, procedures can simply issue CALL statements to the existing procedures.

Another use for nesting procedures is to assemble result sets generated by queries on different databases into a single result set. With this technique, the stored procedure processes multiple SELECT statements through multiple instances of the SQLCursor class. For each of the instances, the procedure uses the DhSQLResultSet class to add rows to the result set returned by the procedure.

 

Debugging Java Stored Procedures

FairCom DB SQL allows Java debugging tools, such as JSwat, to connect and directly debug stored procedure routines. JSwat is an open-source GUI Java debugger, which can be downloaded from https://github.com/nlfiedler/jswat.

This section includes information about configuring your environment to enable debugging with JSwat and provides an example of how to use JSwat.

 

Enabling Java Debugging Tools

FairCom DB SQL allows Java debugging tools to connect and directly debug stored procedure routines. To enable this feature, follow the following steps.

  1. Add the following keywords to ctsrvr.cfg:
    1. SETENV DEBUG_JVM=S
      
      SETENV DEBUG_JVM_PORT=45987
      
    2. The first keyword enables the FairCom DB SQL JVM debug feature by creating a TCP/IP socket at the port specified with the DEBUG_JVM_PORT keyword for a Java debugger to attach. In addition, the DEBUG_JVM keyword instruct the server to compile stored procedures with debugging information and to not remove the stored procedure source file from disk.
  2. Start the FairCom DB SQL server.
  3. Create a stored procedure (for example, “test”).
  4. Examine the database directory (i.e. ctreeSQL.dbs) for a .java file. This is the Java file source. Pay particular attention to the class name (i.e. public final class admin_test_SP extends JavaBaseSP).
  5. Start a Java debugger and attach it to localhost on the port specified by DEBUG_JVM_PORT.
    1. For example, using the Java debugger included with the JDK, run:
    2. jdb -attach 45987
    3. (run on the same machine running the server to access the Java source files).
  6. Set a breakpoint on the method dhSPwrap of the stored procedure calls (i.e. admin_test_SP.dhSPwrap).
  7. Call the stored procedure from any client side SQL tool such as ISQL.
  8. The debugger should break at the start of the stored procedure.

 

JSWAT Example

 

JSwat is an open-source GUI Java debugger. It can be downloaded from https://github.com/nlfiedler/jswat.

  1. Add the following keywords to ctsrvr.cfg:
    1. SETENV DEBUG_JVM=S
      SETENV DEBUG_JVM_PORT=45987
  2. Start the FairCom DB SQL Server.
  3. Start ISQL and create a stored procedure as follows:
    1. # isql -a ADMIN -u admin ctreeSQL
      
      CREATE PROCEDURE admin.test( IN name CHAR (20) )
      
      BEGIN
      
      Integer testing = new Integer(24);
      
      END
  4. Start jswat.
  5. Select “New Session” from the “Session” menu and edit the following information:
    1. Assign a name (for instance “FairCom DB Session”).
    2. Switch to the “classes” panel and add the path to the ctreeSQLSP.jar file and the path to the ctreeSQL.dbs directory.
    3. Switch to the “Sources” panel and add the path to the ctreeSQL.dbs directory.
  6. Select the session just created from the Sessions Drop Down menu on the toolbar.
  7. From the “Session” menu, click on “Attach”
  8. Configure the Transport as "Attach by socket". Fill in Host and Port with information from your FairCom DB SQL Server configuration.
  9. Click OK (The “debugger console” should now read” “VM attached to session FairCom DB Session”.
  10. In the “Breakpoint” menu select “New Breakpoint” to create a new breakpoint.
    1. Set Breakpoint type to “Method.”
    2. Set Class to the stored procedure name (for example, admin_test_SP).
    3. Set Method to “dhSPwrap.”
  11. Return to ISQL and run the stored procedure:
    1. call test ('John Smith');
  12. The debugger displays the current line in the stored procedure.
 

Using Java Stored Procedures

This chapter describes basic stored procedure operations (such as creating and deleting) and provides a tutorial on using supplied FairCom DB SQL classes. See Java Class Reference for detailed reference information on the classes and their methods.

Stored procedures extend the SQL capabilities of a database by adding control flow through Java program constructs that enforce business rules and perform administrative tasks.

Stored procedures can take advantage of the power of Java programming features. Stored procedures can:

  • Receive and return input and output parameters
  • Handle exceptions
  • Include any number and kind of SQL statements to access the database
  • Return a procedure result set to the calling application
  • Make calls to other procedures
  • Use predefined and external Java classes

FairCom DB SQL provides support for SQL statements in Java through several classes. The following table summarizes the functionality of these FairCom DB SQL - supplied classes. (See Java Class Reference for detailed reference information.)

Summary of FairCom DB SQL Java Classes

Functionality FairCom DB SQL Java Class
Immediate (one-time) execution of FairCom DB SQL statements SQLIStatement
Prepared (repeated) execution of FairCom DB SQL statements SQLPStatement
Retrieval of FairCom DB SQL result sets SQLCursor
Returning a procedure result set to the application DhSQLResultSet
Exception handling for FairCom DB SQL statements DhSQLException

 

Stored Procedure Basics

This section discusses how to get started writing stored procedures.

The FairCom DB SQL CREATE PROCEDURE statement provides the basic framework for stored procedures. Use the CREATE PROCEDURE statement to submit a Java code snippet that will be compiled and stored in the database. The syntax for the CREATE PROCEDURE statement is:


CREATE PROCEDURE [ owner_name. ] procname
        ( [ parameter_decl [ , ... ] ) ] ]
        [ RESULT ( column_name data_type [ , ... ] ) ]
        [ IMPORT
            java_import_clause ]
        BEGIN
            java_snippet
        END

parameter_decl ::
        { IN | OUT | INOUT } parameter_name data_type
 

Note: When creating stored procedures, the key words BEGIN, RESULT, IMPORT and END should start at the first column of the line.

See Also

 

What Is a Java Snippet?

The core of the stored procedure is the Java snippet. The snippet contains a sequence of Java statements. When it processes a CREATE PROCEDURE statement, FairCom DB SQL adds header and footer “wrapper” code to the Java snippet. This wrapper code:

  • Declares a class with the name username_procname_SP (username is the user name of the database connection that issued the CREATE PROCEDURE statement and procname is the name supplied in the CREATE PROCEDURE statement).
  • Declares a method within that class that includes the Java snippet.

When an application calls the stored procedure, FairCom DB SQL calls the Java virtual machine to invoke the method of the username_procname_SP class.

 

Structure of Stored Procedures

There are two parts to any stored procedure:

  • The procedure specification must provide the name of the procedure and may include other optional clauses.
  • The procedure body contains the Java code that executes when an application invokes the procedure.

A simple stored procedure requires only the procedure name in the specification and a statement that requires no parameters in the body, as shown in the following example. The procedure in the following example assumes a table called HelloWorldTBL exists, and inserts a string into that table.

A Simple Stored Procedure Example

CREATE PROCEDURE HelloWorld () Procedure Specification

BEGIN

   SQLIStatement Insert_HelloWorld

      = new SQLIStatement ("INSERT INTO

        HelloWorldTBL(fld1) values

        ('Hello World!')");

   Insert_HelloWorld.execute();

END

Procedure Body

From the Interactive SQL utility, isql, you could execute the procedure as follows:

ISQL> CREATE TABLE helloworldTBL (fld1 CHAR(100));
ISQL> CALL HelloWorld();
0 records returned
ISQL> SELECT * FROM helloworldTBL;
FLD1
----
Hello World!
1 record selected

The procedure specification can also contain other optional clauses:

  • Parameter declarations specify the name and type of parameters that the calling application will pass and receive from the procedure. Parameters can be of type input, output, or both.
  • The procedure result set declaration details the names and types of fields in a result set the procedure generates. The result set is a set of rows that contain data generated by the procedure. If a procedure retrieves rows from a database table, for instance, it can store the rows in a result set for access by applications and other procedures.
    • names specified in the result-set declaration are not used within the stored procedure body. Instead, methods of the FairCom DB SQL Java classes refer to fields in the result set by ordinal number, not by name.)
  • The import clause specifies which packages the procedure needs from the Java core API. By default, the Java compiler imports the java.lang package. The IMPORT clause must list any other packages the procedure uses.

The following example shows a more complex procedure specification that contains these elements.

Complete Stored Procedure Example

Procedure Specification:

CREATE PROCEDURE new_sal(IN deptnum INTEGER, IN pct_incr INTEGER)  Parameter declarations
RESULT(empname CHAR(20), oldsal NUMERIC, newsal NUMERIC)  Procedure result set declaration
IMPORT import java.dbutils.SequenceType;  Import clause

Procedure Body:

BEGIN
.
.
.
END
Body

 

Setting Up Your Environment to Write Stored Procedures

Before you create stored procedures, you need to have a Java development environment running on your system. FairCom DB SQL stored procedures support the following environments:

  • On Unix and Windows XP/2003/Vista: Oracle JDK (previously known as "JavaSoft JDK™") Version 1.5

Specific FairCom DB SQL configuration options set the environment related paths required to enable stored procedure support.

Java Related Configuration Options

Configuration Option
(ctsrvr.cfg)
 
Example Configuration (Windows)
SETENV CLASSPATH SETENV CLASSPATH=C:\Program Files\Java\jdk1.6.0_13\jre\lib\rt.jar;C:\FairCom\V9.1.0\win32\bin\ace\sql\classes\ctreeSQLSP.jar
SETENV JVM_LIB SETENV JVM_LIB=C:\Program Files\Java\jdk1.6.0_13\jre\bin\server\jvm.dll
SETENV JAVA_COMPILER SETENV JAVA_COMPILER=C:\Program Files\Java\jdk1.6.0_13\bin\javac.exe

Note: The JAVA_COMPILER configuration option is only required to submit and compile stored procedures. It is not necessary to specify this option for calling and executing already compiled procedures.

 

Writing Stored Procedures

Use any text editor to write the CREATE PROCEDURE statement and save the source code as a text file. That way, you can easily modify the source code and try again if it generates syntax or Java compilation errors.

Submit the file containing the CREATE PROCEDURE statement to interactive SQL as a script, as shown in the following example.

Submitting Scripts to Create Stored Procedures


$ type helloworldscript.sql
SET ECHO ON;
SET AUTOCOMMIT OFF;
CREATE PROCEDURE HelloWorld ()

BEGIN
     SQLIStatement Insert_HelloWorld = new SQLIStatement
         ("INSERT INTO HelloWorldTBL(fld1) values ('Hello World!')");
     Insert_HelloWorld.execute();
END
commit work;
$ isql -s hello_world_script.sql example_db
SET AUTOCOMMIT OFF;
CREATE PROCEDURE HelloWorld ()

BEGIN
     SQLIStatement Insert_HelloWorld = new
       SQLIStatement ("INSERT INTO HelloWorld(fld1)
       values ('Hello World!')");
     Insert_HelloWorld.execute();
END
;
commit work;
$

Keep in mind that the Java snippet within the CREATE PROCEDURE statement does not execute as a standalone program. Instead, it executes in the context of an application call to the method of the class created by FairCom DB SQL. This characteristic has the following implications:

  • It is meaningless for a snippet to declare a main method, since it will never be executed.
  • If the snippet declares any classes, it must instantiate them within the snippet to invoke their methods.
  • FairCom DB SQL redirects the standard output stream to a file, sql_server.log. Method invocations such as System.out.println() will not display messages on the screen, however, instead writes to that file.
  • The Java System.exit() call is not allowed.

See Also

 

Invoking Stored Procedures

How applications call stored procedures depends on their environment. The sections below show examples for different environments.

ODBC

Calling Stored Procedures from ODBC

JDBC

Calling Stored Procedures from JDBC

.NET

Calling Stored Procedures from .NET

ISQL

Calling Stored Procedures from ISQL

 

Modifying and Deleting Stored Procedures

There is no “ALTER PROCEDURE” statement. To modify a procedure, you will need to drop and recreate it. To recreate the procedure, you need the original source of the CREATE PROCEDURE statement. Before you drop the procedure, decide which approach you will use to recreate it:

  • If you kept the original procedure definition in an FairCom DB SQL script file, simply edit the file and resubmit it through interactive SQL.
  • Query system tables to extract the source of the CREATE PROCEDURE statement to a file.

The FairCom DB SQL DROP PROCEDURE statement deletes stored procedures from the database. Exercise care in dropping procedures, since any procedure that calls the dropped procedure will fail.

 

Debugging Stored Procedures

Compiling Errors

If there’s a Java compilation error, FairCom DB SQL returns the error at create time and does not create the procedure.

Note: If the compilation of the procedure fails, FairCom DB SQL returns only the first error to the calling application.

The following example invokes an ISQL script that attempts to create a procedure that fails and generates a Java compilation error.

Example

	C:\example_scripts>type type_mismatch.sql
	CREATE PROCEDURE error_proc()
	BEGIN
	    Double dbl_val;
	    Integer int_val = new Integer(1234);
	    dbl_val = int_val;
	END
 
	C:\example_scripts>isql -s type_mismatch.sql testdb
	error(-20141): error in compiling the stored procedure
	:03: Incompatible type for =. Can't convert java.lang.Integer to java.lang.Double.

At run time, FairCom DB SQL creates a log file, sql_server.log.

Run Time

Custom message logging can be added with the log() and err() methods which write a character-string message to the SQL log file, sql_server.log.

Note: The log() method is not logged to sql_server.log by default and is intended for development use. Calling log() includes internal details useful in procedure design and should be disabled in production. Enable Java debugging with the FairCom DB SQL debugging flags configuration option:

SETENV TPESQLDBG=NNNNNNNNNNYN

The SQL Explorer tool has an -adv command-line switch to enable setting specific debug flags and will be found on the File menu option as Debug Flags. Check the Java checkbox and click Set.

You can include the values of variables or return values of methods in the string using the standard Java concatenation operator (+) as shown in the following example.

Example


 SQLCursor select_syscalctable = new SQLCursor (
  "SELECT fld FROM ADMIN.syscalctable ");
     select_syscalctable.open();
     select_syscalctable.fetch();
     err ("Any records? Found returned " + select_syscalctable.found());
.
.
.
 

The err() invocation in the previous example writes the following line to the sql_server.log file:

Any records? Found returned true

V11 Changes to Stored Procedure Server-side Debugging

In V11 and later, server-side stored procedure execution logging can be turned on and off using the TPESQLDBG environment variable. TPESQLDBG is an array of 'Y'/'N' characters that determine which debug options are enabled.

Prior to this revision, this was achieved by setting the 11th element (offset 10, java_debug) in the TPESQLDBG environment variable. The logging produced in this way is quite verbose and included information that was useful only to FairCom Technicians.

The interpretation of TPESQLDBG (and other methods setting the same debug features) has been modified as follows:

  • TPESQLDBG (which was an array of 12 'Y'/'N' characters) has been expanded to 13 elements.
  • The element at offset 12 is a new element named stp_logging that controls the log() method used in stored procedures to generate log messages.

Note that activating element #11 (java_debug) activates internal logging and log() method for ANY stored procedure language, not just Java.

See Also

 

Transactions and Stored Procedures

Any updates done by a stored procedure become part of the transaction that called the procedure. The transaction behavior is similar to executing the sequence of FairCom DB SQL statements in the procedure directly by the calling application.

Stored procedures cannot contain COMMIT or ROLLBACK statements.

 

Stored Procedure Security

  • Users issuing the CREATE PROCEDURE statement must have the DBA privilege or RESOURCE privilege.
  • The owner or users with the DBA privilege can execute or drop any stored procedure, and grant the EXECUTE privilege to other users.
  • When a procedure is being executed on behalf of a user with EXECUTE privilege on that procedure, for the objects that are accessed by the procedure, the procedure owner’s privileges are checked and not the user’s. This enables a user to execute a procedure successfully even when he does not have the privileges to directly access the objects that are accessed by the procedure, so long as he has EXECUTE privilege on the procedure.

 

Restrictions on Calling Java Methods in Stored Procedures

Java stored procedures cannot use the System.exit() method. Calling this method in Stored Procedure body results in a compilation error.

 

Using Triggers

Triggers are a special type of stored procedure that are automatically invoked (“fired”) when certain FairCom DB SQL operations are performed on the trigger’s target table. This chapter explains how to create and use triggers.

 

Trigger Basics

Triggers are a special type of stored procedure used to maintain database integrity.

Like stored procedures, triggers also contain Java code (embedded in a CREATE TRIGGER statement) and use FairCom DB SQL Java classes. However, triggers are automatically invoked (“fired”) by certain FairCom DB SQL operations (an INSERT, UPDATE, or DELETE operation) on the trigger’s target table.

This chapter provides a general description of triggers and discusses in detail where trigger procedures differ from stored procedures. Unless otherwise noted, much of the material in Using Stored Procedures also applies to triggers.

 

Triggers vs. Stored Procedures vs. Constraints

Triggers are identical to stored procedures in many respects. There are three main differences:

  • Triggers are automatic. When the trigger event (an INSERT, UPDATE, or DELETE statement) affects the specified table (and, optionally in UPDATE operations, the specified columns), the Java code contained in the body of the trigger executes. Stored procedures, on the other hand, must be explicitly invoked by an application or another procedure.
  • Triggers cannot have output parameters or a result set. Since triggers are automatic, there is no calling application to process any output they may generate. The practical consequence of this is that the Java code in the trigger body cannot invoke methods of the DhSQLResultSet class.
  • Triggers have limited input parameters. The only possible input parameters for triggers are values of columns in the rows affected by the trigger event. If the trigger includes the REFERENCING clause, FairCom DB SQL passes the values (either as they existed in the database or are specified in the INSERT or UPDATE statement) of each row affected. The Java code in the trigger body can use those values in its processing by invoking the getValue() method of the OLDROW and NEWROW objects (see “OLDROW and NEWROW Objects: Passing Values to Triggers”).

The automatic nature of triggers make them well-suited for enforcing referential integrity. In this regard, they are like constraints, since both triggers and constraints can help insure that a value stored in the foreign key of a table must either be null or be equal to some value in the matching unique or primary key of another table.

However, triggers differ from constraints in the following ways:

  • Triggers are active, while constraints are passive. While constraints prevent updates that violate referential integrity, triggers perform explicit actions in addition to the update operation.
  • Triggers can do much more than enforce referential integrity. Because they are passive, constraints are limited to preventing updates in a narrow set of conditions. Triggers are more flexible. The following section outlines some common uses for triggers.

 

Typical Uses for Triggers

Typical uses for triggers include combinations of the following:

Cascading deletes

A delete operation on one table causes additional rows to be deleted from other tables that are related to the first table by key values. This is an active way of enforcing referential integrity that a table constraint enforces passively.

Cascading updates

An update operation on one table causes additional rows to be updated in other tables that are related to the first table by key values. These updates are commonly limited to the key fields themselves. This is an active way of enforcing referential integrity that a table constraint enforces passively.

Summation updates

An update operation in one table causes a value in a row of another table to be updated by being increased or decreased.

Automatic archiving

A delete operation on one table creates an identical row in an archive table that is not otherwise used by the database.

 

Restrictions on Creating Triggers

Triggers can be created only on user tables. An attempt to create triggers on system tables (systrigger, systables, sysprocedures etc.) results in an error: (error (20158) : Can’t create triggers on system tables).

 

Structure of Triggers

Like a stored procedure, a trigger has a specification and a body.

The body of a trigger is the same as that of a stored procedure: BEGIN and END delimiters enclosing a Java snippet. The Java code in the snippet defines the triggered action that executes when the trigger is fired. As with stored procedures, when it processes a CREATE TRIGGER statement, FairCom DB SQL adds wrapper code to create a Java class and method that is invoked when the trigger is fired.

The trigger specification, however, is different from a stored procedure specification. It contains the following elements:

  • The CREATE clause specifies the name of the trigger. FairCom DB SQL stores the CREATE TRIGGER statement in the database under trigname. It also uses trigname in the name of the Java class that FairCom DB SQL declares to wrap around the Java snippet. The class name uses the format username_trigname_TP, where username is the user name of the database connection that issued the CREATE TRIGGER statement.
  • The BEFORE or AFTER keywords specify the trigger action time: whether the triggered action implemented by java_snippet executes before or after the triggering INSERT, UPDATE, or DELETE statement.
  • The INSERT, DELETE, or UPDATE keyword specifies the trigger event: which data modification command activates the trigger. If UPDATE is the trigger event, this clause can include an optional column list. Updates to any of the specified columns or use of a specified column in a search condition to update other values will activate the trigger. As long as a specified column is not used in either case then the trigger will not be activated. If an b trigger does not include the optional column list, an update statement specifying any of the table columns will activate the trigger.
  • The ON table_name clause specifies the trigger table: the table for which the specified trigger event activates the trigger. The ON clause cannot specify a view or a remote table.
  • The optional REFERENCING clause is allowed only if the trigger also specifies the FOR EACH ROW clause. It provides a mechanism for FairCom DB SQL to pass row values as input parameters to the stored procedure implemented by java_snippet. The code in java_snippet uses the getValue() method of the NEWROW and OLDROW objects to retrieve values of columns in rows affected by the trigger event and store them in procedure variables. See OLDROW and NEWROW Objects: Passing Values to Triggers for details.
  • The FOR EACH clause specifies the frequency with which the triggered action implemented by java_snippet executes:
    • FOR EACH ROW means the triggered action executes once for each row being updated by the triggering statement. CREATE TRIGGER must include the FOR EACH ROW clause if it also includes a REFERENCING clause.
    • FOR EACH STATEMENT means the triggered action executes only once for the whole triggering statement. FOR EACH STATEMENT is the default.
  • The IMPORT clause is the same as in stored procedures. It specifies standard Java classes to import.

The following example shows the elements of a trigger.

Structure of a Trigger

Trigger action time

Trigger table

CREATE TRIGGER BUG_UPDATE_TRIGGER

   AFTER

   UPDATE OF (STATUS, PRIORITY) Trigger event

   ON BUG_IN

   REFERENCING OLDROW, NEWROW

   FOR EACH ROW

   IMPORT

      import java.sql*;      } Import clause

Trigger
Specification
     
 

BEGIN

.

.

.

END

Trigger
Body

 

Create Trigger

Use the FairCom DB SQL CREATE TRIGGER statement to create a trigger. The syntax for the CREATE TRIGGER statement is:


CREATE  TRIGGER [ owner_name. ] trigname
    { BEFORE | AFTER }
    { INSERT |  DELETE |  UPDATE [ OF (column_name [ , ... ] ) }
ON table_name
    [ REFERENCING {  OLDROW  [ , NEWROW ]  | NEWROW  [ , OLDROW ]  }  ]
    [ FOR EACH { ROW | STATEMENT } ]
    [ IMPORT  java_import_clause ]

    BEGIN
        java_snippet 
    END

 

OLDROW and NEWROW Objects: Passing Values to Triggers

The OLDROW and NEWROW objects provide a mechanism for FairCom DB SQL to pass row values as input parameters to the stored procedure in a trigger that executes once for each affected row. If the CREATE TRIGGER statement contains the REFERENCING clause, FairCom DB SQL implicitly instantiates an OLDROW or NEWROW object (or both, depending on the arguments to the REFERENCING clause) when it creates the Java class.

This allows the Java code in the snippet to use the getValue() method of those objects to retrieve values of columns in rows affected by the trigger event and store them in procedure variables:

  • The OLDROW object contains values of a row as it exists in the database before an update or delete operation. It is instantiated when triggers specify an UPDATE...REFERENCING OLDROW or DELETE...REFERENCING OLDROW clause. It is meaningless and not available for insert operations.
  • The NEWROW object contains values of a row as specified in an INSERT or UPDATE statement. It is instantiated when triggers specify an UPDATE...REFERENCING NEWROW or INSERT...REFERENCING NEWROW clause. It is meaningless and not available for delete operations.

UPDATE is the only triggering statement that allows both NEWROW and OLDROW in the REFERENCING clause.

Triggers use the OLDROW.getValue() and NEWROW.getValue() methods to assign a value from a row being modified to a procedure variable. The format and arguments for getValue() are the same as in other c-treeSQL Java classes:

getValue ( col_num , data type ) ;

  • col_num is an integer that specifies which column affected row is of interest. getValue() retrieves the value in the column denoted by col_num (1 denotes the first column of the result set, 2 denotes the second, and so on).
  • data_type specifies the required FairCom DB SQL type of the returned column value (see Implicit Data Type Conversion Between SQL and Java Types for details on how FairCom DB SQL data types map to Java data types).

The following example shows an excerpt from a trigger that uses getValue() to assign values from both OLDROW and NEWROW objects.

Using getValue() to Process Row Values within Triggers


CREATE TRIGGER BUG_UPDATE_TRIGGER
AFTER UPDATE OF (STATUS, PRIORITY) ON BUG_INFO
REFERENCING OLDROW, NEWROW
FOR EACH ROW

IMPORT 
   import java.sql.* ;
BEGIN
   try
{    
  // column number of STATUS is 10
  String  old_status, new_status;

  old_status = (String)OLDROW.getValue(10,CHAR);
  new_status = (String)NEWROW.getValue(10,CHAR);

  if ((old_status.compareTo("OPEN") == 0) &&
      (new_status.compareTo("FIXED") == 0))
    {
     //  If STATUS has changed from OPEN to FIXED
     //  increment the bugs_fixed_cnt by 1 in the
     //  row corresponding to current month 
     //  and current year
     SQLIStatement  update_stmt = new SQLIStatement (
        " update BUG_STATUS set bugs_fixed_cnt = bugs_fixed_cnt + 1 "
        " where  month = ?  and year = ?");
        Integer current_month = 10;
        Integer current_year  = 1997;
        update_stmt.setParam(1, current_month);
        update_stmt.setParam(2, current_year);
        update_stmt.execute();
    }
}
catch(DhSQLException e)
  {throw e;}
END

 

Dynamically Disable Triggers

When a table contains a trigger, it can be desirable to avoid firing that trigger when performing administrative tasks such as bulk updates. This modification adds the possibility to disable triggers for the current session by calling:

SET TRIGGER OFF

Trigger executions can be reestablished by

SET TRIGGER ON

The user executing these commands needs to have resource permissions on the database.

 

Using User-Defined Scalar Functions

 

Introduction

Scalar functions are an integral part of the support provided by FairCom DB SQL for query expressions. FairCom DB SQL provides several built-in scalar functions that transform data in different ways. However, at times there is a requirement for custom-transformation of data—a transformation that is not provided by the provided functions. This problem is solved by the concept of a user-defined scalar function (UDF)—a scalar function that is defined by the user. FairCom DB SQL UDFs allow the user to define their own functions to transform data in some custom manner.

User-Defined Scalar Functions are an extension to the existing built-in scalar functions and return a single value each time one is invoked. These functions can be used in queries in the same way that system defined scalar functions are used.

The user defines functions by creating Java Stored Functions, modules written in Java that are similar to the ones written for stored procedures and triggers. The Java code snippet contained in the User-Defined Scalar Function definition is processed by FairCom DB SQL into a Java class definition and stored in the database in text and compiled form. User-Defined Scalar Functions can be created, executed and dropped using ISQL, ODBC and JDBC.

 

Structure of User-Defined Functions

The CREATE FUNCTION command creates a new User Defined Scalar Function in the current database

function_name is the name that is to be assigned to the function. Different owners can have functions with the same name in the same database

Each parameter_decl is of the form:

[ARG_TYPE] ARG_NAME DATA_TYPE

and is separated by a comma (‘,’)

  • ARG_TYPE is optional. When specified it can only be IN.
  • ARG_NAME specifies the name of the argument to the function. The function can access the values through the corresponding Java variables.
  • DATA_TYPE is any valid supported FairCom DB SQL data type which specifies the type of the argument.

The return value of the function is specified with the RETURNS key word followed by the data_type declaration.

The Java IMPORT statements which are needed for the correct functioning of the Java snippet (the code between BEGIN and END -- see below) need to be placed in the section between the IMPORT and BEGIN keywords. This section need not be present if there are no import statements.

The function cannot be created without specifying all the import statements needed by the snippet. (For details refer to any Java manual or book)

The Function body, referred to as the Java snippet, needs to be placed between the BEGIN and END keywords. Any valid Java code other than class or function definitions can be present here. The snippet must have a return statement.

Note: Each of the keywords IMPORT, BEGIN, and END need to be upper case and be present on a separate line. Once the IMPORT or BEGIN are specified, the statement is terminated by an END but not a semicolon (‘;’).

Creating a User Defined Scalar Function

	ISQL> CREATE FUNCTION str_cat(IN org_string VARCHAR(20), IN string_to_concat VARCHAR(20))
	RETURNS VARCHAR(40)
	IMPORT
	import java.math.*;
	BEGIN
	     String new_str = org_string +  string_to_concat ;
	     return new_str;
	END

The above example creates a User Defined Scalar Function, str_cat, that takes two input arguments and returns the concatenated string.

 

Create Function

User Defined Scalar Functions are created using the CREATE FUNCTION command. User Defined Scalar Functions can be created by any user with resource privilege.

The syntax for the CREATE FUNCTION statement is:


CREATE FUNCTION [ owner_name.]function_name
         ( [parameter_decl , ...] )
         RETURNS (data_type)
        [ IMPORT
                    java_import_clause ]
        BEGIN
            java_snippet
        END
parameter_decl ::
        [ IN ] parameter_name data_type

 

When creating stored procedures, the key words BEGIN, RETURNS, IMPORT, and END should start at the first column of the line. The function name is limited to 64 characters

 

Drop Function

Deletes a User Defined Scalar Function.

Syntax

DROP FUNCTION function_name

Dropping a User Defined Scalar Function

ISQL> DROP FUNCTION str_cat;

 

Invoking User-Defined Scalar Functions

User Defined Scalar Function are a type of FairCom DB SQL expression that return a value based on the argument(s) supplied. User Defined Scalar Functions are invoked in exactly the same manner as built in scalar functions.

User Defined Scalar Functions can be used in the SELECT list or in the WHERE clause. They can be used as parameters of other scalar functions or included with other SQL expressions. The parameter passed to a user defined scalar function can be a literal, field reference or any expression

 

With Constants

Example with Constants


SELECT str_cat('abcd','efgh') FROM syscalctable;
 
 
STR_CAT(ABCD,EFGH)
-------------------------------
abcdefgh
1 record selected

 

With Constants and Column References

Example with Constants and Column References


SELECT empfname, str_cat(empfname, emplname) FROM emp WHERE str_cat('mary', 'john') = 'maryjohn';
 

EMPFNAME          STR_CAT(EMPFNAME,EMPLNAME)
----------------  ---------------------------------------------
Mary              MaryJohn
1 records selected

 

With parameter reference (ODBC/JDBC)

Example with Parameter References


SELECT str_cat(?, ?) FROM emp
SELECT * FROM emp WHERE str_cat(?, ?) = 'MaryJohn'

 

User-Defined Scalar Function Security

  • Users issuing the CREATE FUNCTION statement must have the DBA privilege or RESOURCE privilege.
  • The owner or users with the DBA privilege can execute or drop any User Defined Scalar Function, and grant the EXECUTE privilege to other users.

 

Calling Scalar Functions from a User Defined Scalar Function

FairCom DB SQL does not have a mechanism for calling a scalar function directly from a user-defined function. To use scalar functions, it is necessary to call the function from within a FairCom DB SQL statement. FairCom DB SQL defines the special table SYSCALCTABLE which has only one row for use in situations where all the data is in the inputs.

Example


CREATE FUNCTION  myuser.TO_NATIVE_DATE(IN UNIX_TYPE_DATE INT)
RETURNS TIMESTAMP
IMPORT
import java.sql.*;
BEGIN
    StringBuffer query_str = new StringBuffer(“SELECT TIMESTAMPADD(SQL_TSI_SECOND,”);
    query_str.append(UNIX_TYPE_DATE).append(“, TO_TIMESTAMP('01/01/1970 00:00:00')) FROM SYSCACLTABLE”);
    SQLCursor SelCursor = new SQLCursor(query_str.toString());
    SelCursor.open();
    SelCursor.fetch();
    return(Timestamp)SelCursor.getValue(1, TIMESTAMP);
END