BEA Logo BEA WebLogic Server Release 5.0

  Corporate Info  |  News  |  Solutions  |  Products  |  Partners  |  Services  |  Events  |  Download  |  How To Buy

Using jdbcKona/Sybase and jdbcKona/MSSQLServer

I. Introduction
What's in this document
Mapping of types between SQL Server and JDBC

II. Using jdbcKona/Sybase and jdbcKona/MSSQLServer
How to connect to a DBMS with jdbcKona
Closing JDBC objects
Using codesets
Executing and canceling queries
Interleaving operations on a connection
Using stored procedures and OpenServer RPCs
Support for stored procedures
Support for OpenServer named params:
CallableStatement.setParamName()
Support for SQL Server RPC facility
Using WebLogic applications with Sybase OpenServer via RPCs
Executing multistatement queries
Autocommit
SQLExceptions
Working with Text and Image types
WebLogic's extensions:
Statement.executeWriteText() and Statement.getTextTimestamp()
Notes on DatabaseMetaData methods
Notes on transaction isolation levels

III. What is not currently supported

IV. Change history

Other guides and resources
Installing WebLogic (non-Windows)
Installing WebLogic (Windows)
Developers Guides
API Reference Manual
Using the jdbcKona Type 2 JDBC drivers
Using WebLogic JDBC
Implementing with dbKona
Performance tuning your JDBC application
Troubleshooting JDBC hangs and SEGVs
Choosing a Java Database Connectivity driver
Glossary

I. Introduction

What's in this document

Covered in this document are general guidelines for using the WebLogic jdbcKona native JDBC drivers for Sybase and Microsoft SQL Server. For general notes and an implementation guide that cover all of WebLogic's native JDBC drivers, check the jdbcKona overview and implementation guide.

If you are using WebLogic JDBC, WebLogic's multitier JDBC implementation, you should also refer to the Developers Guide Using WebLogic JDBC for more information.

Top of this section

Mapping of types between SQL Server and JDBC

Mappings from Java to JDBC and JDBC to Java are available in Section 8 of the JDBC specification at JavaSoft.

    Sybase and MS SQL Server JDBC
    (java.sql.Types)
    (var)Binary (var)Binary
    Bit boolean
    (var)Char (var)Char
    Decimal Numeric
    Double precision Double
    Image Longvarbinary
    Int Integer
    Money Numeric
    N(var)char not supported
    Ntext not supported
    Numeric Numeric
    Real Float
    Smallint Smallint
    Smallmoney Numeric
    Text Longvarchar
    Tinyint Tinyint
    N/A Long

The following table illustrates mappings from JDBC types to Sybase DB-LIB types.

    JDBC Sybase/MS SQL Server
    boolean SYBBIT
    SQLBIT
    Double SYBFLT8
    SQLFLT8
    Float SYBREAL
    SQLREAL
    Integer SYBINT1, SYBINT2, SYBINT4
    SQLINT1, SQLINT2, SQLINT4
    Numeric SYBNUMERIC, SYBDECIMAL,
    SYBMONEY, SYBMONEY4
    SQLNUMERIC, SQLDECIMAL,
    SQLMONEY, SQLMONEY4
    Timestamp SYBDATETIME, SYBDATETIME4
    SQLDATETIME, SQLDATETIME4
    Varchar or Longvarchar SYBCHAR, SYBTEXT
    SQLCHAR, SQLTEXT
    Varbinary or Longvarbinary SYBBINARY, SYBIMAGE
    SQLBINARY, SQLIMAGE

Top of the page

II. Using jdbcKona/MSSQLServer and jdbcKona/Sybase

There are many similarities between Sybase SQL Server and Microsoft SQL Server. When the term SQL Server is used here, it refers to both. Notes specific to Sybase or Microsoft SQL Server are marked with the full name.

Top of this page

How to connect to a Sybase or SQL Server DBMS with jdbcKona

In general, connecting happens in two steps:

  1. You must load the proper JDBC driver, and then you must obtain a connection. The most efficient way to load the JDBC driver is to call Class.forName().newInstance() with the name of the driver class, which properly loads and registers the JDBC driver, as in this example:
      Class.forName("weblogic.jdbc.dblib.Driver").newInstance();
  2. You request a JDBC connection by calling the DriverManager.getConnection() method, which takes as its parameters the URL of the driver and other information about the connection.

Note that each step describes the JDBC driver, but in a different format. The full package name is period-separated, and the URL is colon-separated. The URL must include at least weblogic:jdbc:sybase or weblogic:jdbc:mssqlserver, and may include other information, including server name and database name.

There are variations on this basic pattern which are described here for both Sybase and MS SQL Server. For a full code example, check the beginning sections in the Overview and implementation guide.

Method 1

The simplest way to connect is with the URL of the JDBC driver. You can append information that describes the server name and the database name, as shown in this Sybase example:
  Class.forName("weblogic.jdbc.dblib.Driver").newInstance();
  Connection conn =
    DriverManager.getConnection("jdbc:weblogic:sybase:mach2:mydb",
                                "sa",
	              	        "");
where mach2 is the server name and mydb is the name of the database; and where sa is a valid DBMS username.

Method 2

You can also pass a java.util.Properties object with parameters for connection as an argument to the DriverManager.getConnection() method. In this example we illustrate how to connect to a Sybase database ("mydb") on the server host "mach2", with the DBMS username "sa":
  Properties props = new Properties();
  props.put("user",         "sa");
  props.put("password",     "");
  props.put("server",       "mach2");
  props.put("db",           "mydb");

  Class.forName("weblogic.jdbc.dblib.Driver").newInstance();
  Connection conn =
    DriverManager.getConnection("jdbc:weblogic:sybase", props);

Here is another example that shows an additional, optional property that you may choose to set, for th application name for your Sybase or MS SQL Server JDBC connections. The DBMS associates these with the JDBC Connection. When set, this name will be put into sysprocesses under the column "program_name" and will show up in sp_who. The driver will automatically set the hostname.

  Properties props = new Properties();
  props.put("user",         "sa");
  props.put("password",     "");
  props.put("server",       "mach2");
  props.put("db",           "mydb");
  props.put("appname",      "MyApplication");


  Class.forName("weblogic.jdbc.dblib.Driver").newInstance();
  Connection conn =
    DriverManager.getConnection("jdbc:weblogic:sybase", props);

Here is a similar example that shows how to connect to an Microsoft SQL Server database. Note that the only difference is the URL for the driver; for Microsoft SQLServer, it is "jdbc:weblogic:mssqlserver".

  Properties props = new Properties();
  props.put("user",         "sa");
  props.put("password",     "");
  props.put("server",       "mach2");
  props.put("db",           "mydb");

  Class.forName("weblogic.jdbc.dblib.Driver").newInstance();
  Connection conn =
    DriverManager.getConnection("jdbc:weblogic:mssqlserver", props);

If you do not supply a server name ("mach2" in the example above), the system will look for an environment variable (DSQUERY in the case of Sybase, ORACLE_SID in the case of Oracle). You may also choose to add the server name to the URL, with this format:

"jdbc:weblogic:sybase:mach2"

You can also set all of the properties in a single URL, for use with products like PowerSoft's PowerJ. For details, see Using URLs with WebLogic products.

Method 3

If you prefer, you can load the JDBC driver from the command line with the command:

 $ java -Djdbc.drivers=weblogic.jdbc.dblib.Driver classname

where classname is the name of the application you want to run; and then use a Properties object to set parameters necessary for connecting to the DBMS. In this case, you will not need to call the Class.forName().newInstance() method, as shown here in this jdbcKona/MSSQLServer example:

  Properties props = new Properties();
  props.put("user",         "sa");
  props.put("password",     "");
  props.put("server",       "mach2");
  props.put("db",           "mydb");

  Connection conn =
    DriverManager.getConnection("jdbc:weblogic:mssqlserver", props);

Closing JDBC objects

It is important to routinely and conscientiously close JDBC objects in your code in a finally {} code block. Closing objects releases resources on the remote DBMS and within your application.

jdbcKona objects that you should close() after final use:

  • Statement (PreparedStatement, CallableStatement). Note that with SQL Server, you should always call close() immediately after you have finished working with a Statement and its results. You cannot safely close it later, because the close affects all statements on the Connection. For details on handling Statements in SQL Server, see Interleaving operations on a connection.

  • ResultSet. Call ResultSet.close() when you have finished working with the results of a query.

  • Connection. Always call the Connection.close()method to close the Connection when you have finished working with it.

If you are using WebLogic JDBC in a multitier environment with a two-tier jdbcKona driver, you will set connection properties in a slightly different way. See the Developers Guide Using WebLogic JDBC for more details.

Top of this section

Using codesets

With Release 3.1, both drivers support the use of multibyte-character codesets, based on codeset support in the JDK rather than the native vendor library. To use this feature, set the property weblogic.codeset for your JDBC Connection, as shown here:
  Properties props = new Properties();
  props.put("user",             "sa");
  props.put("password",         "");
  props.put("server",           "mach2");
  props.put("db",               "mydb");
  props.put("weblogic.codeset", "Cp1254");

  Class.forName("weblogic.jdbc.dblib.Driver").newInstance();
  Connection conn =
    DriverManager.getConnection("jdbc:weblogic:sybase", props);

Although the valid codeset names are JVM-dependent, these are described as part of the JavaSoft Internationalization specification. Note that codeset support depends upon the codesets available on your DBMS.

Top of this section

Executing and canceling DBMS queries

Executing queries: JDBC allows the Statement.executeUpdate() method to execute queries that return no results and the Statement.executeQuery() method to execute queries that return only a single ResultSet. Although this works with many SQL Server queries, a SQL Server query may return multiple ResultSets.

Good SQL Server programming practice suggests that, when you are not sure about how the results will be returned, you should call the Statement.execute() method, and then call the following methods inside a loop until there are no more results:

  • Statement.getResultSet()
  • Statement.getUpdateCount()
  • Statement.getMoreResults()

The descriptions for these methods in the version 1.0 JavaSoft JDBC API specification or earlier were incomplete and ambiguous. There are new corrected descriptions in the JavaSoft JDBC specification, which WebLogic products implement, and which are reproduced here for clarity.

    /**
     * getResultSet returns the current result as a ResultSet.  It
     * should only be called once per result.
     *
     * @return the current result as a ResultSet; null if the result
     * is an update count or there are no more results
     * @see #execute 
     */
    ResultSet getResultSet() throws SQLException; 

    /**
     * getUpdateCount returns the current result as an update count;
     * if the result is a ResultSet or there are no more results -1
     * is returned.  It should only be called once per result.
     * 
     * The only way to tell for sure that the result is an update
     * count is to first test to see if it is a ResultSet. If it is
     * not a ResultSet it is either an update count or there are no
     * more results.
     *
     * @return the current result as an update count; -1 if it is a
     * ResultSet or there are no more results
     * @see #execute 
     */
    int getUpdateCount() throws SQLException; 

    /**
     * getMoreResults moves to a Statement's next result.
     * It returns true if this result is a ResultSet.
     * getMoreResults also implicitly closes any current
     * ResultSet obtained with getResultSet.
     *
     * There are no more results when (!getMoreResults() &&
     * (getUpdateCount() == -1)
     *
     * @return true if the next result is a ResultSet; false if it is
     * an update count or there are no more results
     * @see #execute 
     */
    boolean getMoreResults() throws SQLException; 

Canceling queries: In DB-Library, you must read all of the results from your current query or call dbcancel or decanquery; otherwise, your connection can get out of sync and you will be unable to issue new queries. If you need to stop processing a query before all rows and ResultSets have been read, we require that you call either the ResultSet.close() or the Statement.close() method. Calling ResultSet.close() closes only your current result set; you can still retrieve other result sets if your query returns more than one.

Top of this section

Interleaving operations on a connection

Some application programs may require multiple Statements to execute simultaneously. This is needed if the application wishes to do its own JOIN outside of SQL, with a loop retrieving rows from an SQL select one row at a time and then performing another SQL statement for each iteration of the loop.

The only way to execute two statements simultaneously is to open two JDBC Connections and create a JDBC Statement on each Connection. Each JDBC Connection object maintains a separate connection to the SQL Server, so there are no restrictions on executing different statements simultaneously over different Connection objects.

Other applications may need to interleave two statements on the same connection, executing one and then the other. This is necessary to execute a JDBC PreparedStatement or CallableStatement repeatedly, or to avoid the small overhead of opening and closing Statements repeatedly.

Rules for using multiple statements on the same connection

To execute multiple statements on the same connection, the basic rule is this: After you execute a statement, you must either read all the results from that statement or cancel it or close it. If you try to perform any other executes on that Statement, or another Statement on that connection, you will get a DB-LIB error, which is trapped and reported as the following JDBC SQLException:

  You have tried to execute a Statement or call a DatabaseMetaData
  method without reading all of the results of a previous Statement
  execute or DatabaseMetaData method.

A query may return multiple results and/or update counts. This can cause errors if Statements and their results are handled improperly. You should call Statement.close() after calling any of the execute methods, unless you exhaust all of the results of the executed query.

Handling a Statement (and its subclasses CallableStatement and PreparedStatement) falls into three basic categories, based on the method used to execute the query. Each case has a set of precautions that will prevent problems.

  • The simplest case is when executing a query will not return a ResultSet. Use Statement.executeUpdate(query) when you are sure that your query will not return a ResultSet--even an empty one-- or that your query will return a single ResultSet that you do not care about. Some examples are SQL DELETES, INSERTS, and UPDATES. This method may return only the row count of the affected rows. You must eventually close the Statement, even though you do not retrieve any results. Here is an example:
      Connection conn;   // Open SQL Server connection
    
      Statement stmt = conn.createStatement();
      stmt.executeUpdate("insert into empdemo values" +
                         "(0, 'John Smith', 12)");
      stmt.close();

  • Statement.executeQuery(query) returns only a single ResultSet. When you use this method, you should exhaust all the results in the ResultSet by calling ResultSet.next() until it returns false, or call the close() method on the Statement when you have finished with the results. Here is an example:
      Connection conn;   // Open SQL Server connection
    
      Statement stmt = conn.createStatement();
      ResultSet rs = stmt.executeQuery("select * from empdemo");
      while (rs.next()) {
        (. . . continue program execution)
      }

  • Depending on the exact query or stored procedure executed, the method Statement.execute(query) may potentially return any sequence of multiple ResultSets and multiple update counts, in any order. When you use this method, you should exhaust all of the update counts and ResultSets returned, or close the Statement. Here is a short example:
      Connection conn;   // Open SQL Server connection
      Statement stmt3 = conn.createStatement();
      stmt3.execute("create procedure proc_getResults as " +
                    "begin select name from sysusers \n" +
                    "select gid from sysusers end");
      stmt3.close();
    
      CallableStatement cstmt3 =
        conn.prepareCall("{call proc_getResults()}");
    
      cstmt3.execute();
      while (true) {
        ResultSet rs = cstmt3.getResultSet();
        int updateCount = cstmt3.getUpdateCount();
        // No more results or counts
        if (rs == null && updateCount == -1)
          break;
        // There is a ResultSet
        if (rs != null) {
          while (rs.next())
            System.out.println("Value: " + rs.getString(1));
        }
        else {
          // There is an update count
          System.out.println ("Update count = " +
                              cstmt3.getUpdateCount());
        }
        cstmt3.getMoreResults();
      }
      cstmt3.close();

    For a more complex illustration, see the example in the next section. Also check Executing multistatement queries for another example that illustrates handling a query that may return a combination of ResultSets and update counts.

For more advanced usage, follow these rules:

  • If possible, call the ResultSet.next() method on each result set until it returns false. This includes ResultSets returned by DatabaseMetaData methods.

  • If you are executing a query that may return multiple ResultSets and/or update counts, use the Statement.execute() method rather than the Statement.executeQuery() method, and call Statement.getMoreResults() until there are no more ResultSets and no more update counts.

  • If you do not wish to read all results in the current ResultSet, call the ResultSet.close() method on that ResultSet. This includes ResultSets returned by DatabaseMetaData methods. Please follow the example in above.

  • If you do not wish to continue executing the current Statement or processing its ResultSets but you want to leave the Statement available to be re-executed later, call the Statement.cancel() method on the current Statement. Eventually when you are finished executing, call the Statement.close() method to close the Statement.

  • When you do not wish to continue executing the current Statement or processing its ResultSets and you are not planning to re-execute the Statement in the future, call the Statement.close() method on the current Statement.
Top of this section

Using stored procedures and OpenServer RPCs

Use the JDBC CallableStatement class for SQL Server stored procedures and RPCs.

Support for stored procedures

The JDBC extended SQL keyword CALL is used instead of the SQL Server keyword EXECUTE to call stored procedures from SQL.

Stored procedure input parameters are mapped to JDBC IN parameters, using the java.sql.CallableStatement.setXXX() methods, such as setInt(), and JDBC PreparedStatement '?' syntax. CallableStatement is a subclass of PreparedStatement, so all of the PreparedStatement.setXXX() methods are inherited by CallableStatement.

Stored procedure OUT parameters and return status are mapped to JDBC Out parameters, using the java.sql.CallableStatement.registerOutParameter() methods and JDBC PreparedStatement '?' syntax.

A parameter may be both IN and OUT, which requires both a setXXX() and a registerOutParameter() call to be done on the same parameter number.

Support for OpenServer named parameters

WebLogic has an extension to JDBC that allows SQL Server users to apply names to parameters. The extension is the setParamName(int index, String name) method in weblogic.jdbc.dblib.CallableStatement. It is not necessary to use this extension to invoke an RPC unless the RPC is in an OpenServer application and the OpenServer application relies on named parameters. There are several guidelines for using this extension to JDBC:

  • When you instantiate a java.sql.CallableStatement object and you intend to use this extension to JDBC, you must explicitly cast the object as weblogic.jdbc.dblib.CallableStatement.

  • The setParamName() method should be called only once per parameter.

  • If any parameter in the CallableStatement is named with this method, you must name every parameter in the RPC invocation, or an OpenServer error will result.

  • The name assigned to each parameter with the setParamName() method must exactly match the name given to the parameter in the declaration of the RCP, for either a SQL Server stored procedure or an OpenServer RCP. The CallableStatement will fail to execute if a name mismatch occurs.

Support for the SQL Server RPC facility

In addition to stored procedures, WebLogic's implementation of JDBC supports the SQL Server RPC facility, where user-defined procedures on a Sybase OpenServer or Microsoft Open Data Service can be called as if they were local to the client. The JDBC extended SQL keyword CALLRPC, a WebLogic extension, is used to call OpenServer RPCs.

CALLRPC can also be used instead of CALL to call SQL Server stored procedures, but CALLRPC is limited in the kinds of arguments it can handle. We recommend using CALL if you do not need to communicate with an Open Server or Open Data Service.

Usage. CALL and CALLRPC use the same syntax and handle results and OUT parameters in exactly the same way. The code example at the end of this section works identically whether you use {? = CALL sp_getmessage(?, ?)} or {? = CALLRPC sp_getmessage(?, ?)}.

Limitations for CALLRPC. CALLRPC does not work with parameters of type NUMERIC in some versions of Sybase System 10, but it does work with parameters of this type with Microsoft SQL Server 6.5 and 7.0. We will determine soon whether this works in Sybase System 11. The issue is a problem with the Sybase DB-LIB call "DBRPCPARAM()", which does not recognize the SYBNUMERIC type code. We will be working with Sybase to determine in which versions this problem has been fixed.

Processing results from a stored procedure or OpenServer RPC. You must process all ResultSets returned by your stored procedure or RPC using the Statement.execute() and Statement.getResultSet() methods before any of the OUT parameters and return status are available.

Here is an example that uses a Sybase system stored procedure named 'sp_getmessages', which takes a message number as an input parameter and returns the message text as an output parameter:

  #SQL Server Syntax (if you were programming in DB-LIBRARY)
  DECLARE @retval int
  DECLARE @msgno int
  DECLARE @message varchar(100)

  SELECT  @msgno = 18000   # a typical SQL Server message number
  EXECUTE @retval = sp_getmessage(@msgno, @message OUTPUT)

  #Equivalent JDBC Syntax:
  { ? = CALL sp_getmessage(?, ?) }

  #Actual JDBC code to get the results:
  {
    // This code assumes conn is an open JDBC Connection
    CallableStatement stmt =
      conn.prepareCall("{ ? = call sp_getmessage(?, ?) }" );
    // Set up the 3 parameters to the callable statement:
    // Parameter 1, which is output only, is the
    // stored procedure return value
    stmt.registerOutParameter(1, java.sql.Types.INTEGER);

    // Parameter 2, which is input only, is the msgno
    // argument to sp_getmessage
    stmt.setInt(2, 18000);                   // msgno 18000
    // Parameter 3, which is output only, is the
    // message text returned for that msgno
    stmt.registerOutParameter(3, java.sql.Types.VARCHAR);

    boolean hasResultSet = stmt.execute();
    while (true) {
      ResultSet rs = stmt.getResultSet();
      int updateCount = stmt.getUpdateCount();
      if (rs == null && updateCount == -1)   // No more results
        break; 
      // We have a ResultSet
      if (rs != null) {
        while (rs.next()) {
          System.out.println("Get first col by id:" + rs.getString(1));
        }
      }
      // We have an update count
      else {
        System.out.println("Update count = " + stmt.getUpdateCount());
      }
      stmt.getMoreResults();
    }

    int retstat = stmt.getInt(1);
    String msg = stmt.getString(3);

    System.out.println("sp_getmessage: status = " + retstat +
                       " msg = " + msg);
    stmt.close();
  }

Using WebLogic applications with Sybase OpenServer via RPCs

WebLogic includes two files in the distribution that you can compile and use to demonstrate the communications between WebLogic and Sybase OpenServer applications via RPCs:

  • examples/jdbc/openserver/regWebProc.c. A simple OpenServer adapted from regproc.c, one of the OpenServer examples provided by Sybase in $SYBASE/sample/srvlib.
  • examples/jdbc/openserver/rpcTest.java. A simple Java application that connects to a running instance of regWebProc and invokes an RPC in the OpenServer application.
To use these sample programs:

  1. Copy regWebProc.c into $SYBASE/sample/srvlib.

  2. Compile it in the same way that the Sybase makefile compiles regproc.

  3. Create an interfaces file entry for the OpenServer.

  4. Start regWebProc with the following command:
      $ regWebProc OpenServer_name

    where OpenServer_name is the interfaces file entry for the OpenServer. Expect output to stdout as the regWebProc process starts.

  5. Test connectivity with isql by logging in to the OpenServer in the same way you log in to SQL Server, after this pattern:
      $ isql -Uuser -Ppassword -sOpenServer_name

    where OpenServer_name is the interfaces file entry name for regWebProc.

  6. After making sure that your CLASSPATH includes the WebLogic classes directory, compile rpcTest.java with the following command:
      $ javac rpcTest.java

  7. While regWebProc is running, start rpcTest with the following command (where all of the arguments are one a single line):
      $ java OpenServer_name rpcTest

    where OpenServer_name is the interfaces file entry name for regWebProc.

The rpcTest application invokes an RPC in the regWebProc OpenServer application. The RPC, rp_types() takes 3 input parameters -- a string, an int, and a float -- and returns raw data. When you run rpcTest successfully, the 3 parameters should be printed to stdout by regWebProc ("yesindeedy!", 123, and 128.5), and subsequently, 1 row of data (like select 1) should be printed to stdout by rpcTest as it receives a response from the OpenServer. If the test fails, the output file rpcTest.out will contain a Java stack trace.

Top of this section

Executing multistatement queries

SQL Server allows the execution of multiple SQL statements in the same "command batch." This is equivalent to typing multiple commands in ISQL before typing "go." You can use this facility to execute multiple statements in the same JDBC execute() method. Follow these rules:

  • Separate multiple statements with spaces, tabs, or (recommended) newlines.
  • Do not use the word go.
There are some restrictions on the use of multiple statements. You should not combine a USE command with other commands in the same batch, and you cannot create and reference a table in the same batch. Please consult your SQL Server documentation for specific rules that apply to this facility in your version of SQL Server.

Because these statements can return any combination of result sets and update counts, your result handling code must allow for this. (There is a similar issue in calling stored procedures, and the code for both cases looks almost identical.) Here is an example:

  Statement stmt = conn.createStatement();
  String query = "select * from foo" + "\n"
    + "update bar set val =1 where id=1" + "\n"
    + "select * from bar";

  boolean hasResultSet = stmt.execute(query);
  while (true) {
    ResultSet rs = stmt.getResultSet();
    int updateCount = stmt.getUpdateCount();

    // If there are no more results, break
    if (rs == null && updateCount == -1)
      break; 

    // Check to see if there is a ResultSet
    if (rs != null) {
      while (rs.next()) {
        System.out.println("Get first col by id:" + rs.getString(1));
      }
    }
    // Otherwise, there will be an update count
    else {
      System.out.println("Update count = " + stmt.getUpdateCount());
    }
    stmt.getMoreResults();
  }
Top of this section

Autocommit

The default transaction mode for both JDBC and SQL Server is autocommit on. In this mode, each SQL statement is its own transaction, so there is never a need for a BEGIN TRANSACTION or an END TRANSACTION for a single statement. To execute a multistatement transaction, bracket the multiple statements with BEGIN TRANSACTION and END TRANSACTION.

BEGIN TRANSACTION is not supported in all vendor versions of SQL, so it is impossible to write vendor-independent transaction logic in JDBC. This could be solved if JDBC had a Connection.begin() method. If you need this feature, please contact jdbc@wombat.eng.sun.com and ask that it be added to future revisions of the JDBC spec.

JDBC also supports autocommit off mode, also known as ANSI-compliant mode. In this mode, the Connection always has an implicit transaction associated with it, and any call to the Connection.rollback() or Connection.commit() methods ends the current transaction and starts a new transaction. To toggle between modes, call Connection.setAutoCommit(boolean). This mode is implemented in Sybase SQL Server using the SET CHAINED ON command. There is no equivalent to autoCommit off in MS SQL Server or in Sybase SQL Server 4.9x that we have found.

More on autocommit with Sybase.

The setting for autocommit has significant implications for Sybase SQL Server, because autocommit affects how Sybase behaves in transactions, transaction counts, and transaction nesting. Sybase SQL Server behaves completely differently according to whether autocommit is set to on or off. WebLogic recommends that you use the default setting for autocommit (autocommit set to on) unless you have a full understanding of Sybase and of how changing autocommit will affect your application.

If you do choose to set autocommit to off, Sybase recommends that you run stored procedures in the same mode as they were originally created. That is, if your stored proc was created with autocommit set to on, you should execute it with autocommit set to on, and if the stored proc was created with autocommit set to off, you should execute it with autocommit set to off.

In the default mode (autocommit set to on), you can specify that a group of updates commit or rollback as a group in the following way:

  statement.executeUpdate("begin transaction");

  // Do a series of updates
  statement.executeUpdate("insert xyz values . . .");
  statement.executeUpdate("update abc where . . .");
  statement.executeUpdate("delete mnop where . . .");

  // Decide whether to commit or rollback
  // Commit or rollback
  if (wantToCommit) 
    statement.executeUpdate("commit transaction");
  else
    statement.executeUpdate("rollback transaction");

You can also nest transactions, use named transactions, and establish savepoints with the same approach. Please check the SQL Server Reference Manual for more details.

More on autocommit with MS SQL Server.

MS SQL Server does not support setting autocommit to false, and WebLogic recommends always running with autocommit set to true. However, with WebLogic's jdbcKona/MSSQLServer, making a call to Connection.setAutoCommit(false) does supply functionality that simulates expected behavior, using the MS SQL Server set implicit_transactions command. If you have set autocommit to false, you must subsequently call Connection.commit() at some time before closing the Statement, if you want your executes to be saved. Ideally, commit() should be called after any series of calls to Statement.execute() that comprises a single logically consistent change to the data. Note that when you are within an uncommitted transaction, all database resources affected by calls to execute() are locked until commit() is called. For example, if you must debit one account and then credit another, those two actions should be done together and committed with a single call to commit(), but the commit should occur then, and not after any more logically related debit-credit pairs.

Please note that if commit() is not called before the Statement is closed, all updates in the outstanding transaction on the Connection will be rolled back. The outstanding transaction includes all updates since the last commit(), rollback(), or since the Connection was made, whichever happened last.

You should not mix transaction management calls between JDBC and SQL; for example, do not use Statement.execute("COMMIT TRANS") and Connection.commit() calls together. WebLogic strongly recommends that users of this added functionality rely exclusively on JDBC transaction management, by calling Connection.commit() and Connection.rollback() for transaction management.

Top of this section

SQLExceptions

When a SQLException is thrown as a result of a SQL Server error, set the SQLException error code to the SQL Server error number, so that an application program can determine the type of error.

Top of this section

Working with Text and Image types

There is information on line from Sybase about Text/Image data that you also may find useful, at http://sybooks.sybase.com/cgi-bin/nph-dynaweb/con11101/dblib/2348 .

Restrictions on Text and Image datatypes

The JDBC Longvarchar and Longvarbinary types are mapped to the SQL Server types Text and Image, the only SQL Server types that allow data longer than 255 bytes. With the restrictions described below, Text and data can be read and written through SQL queries or through a special API using textpointers. Image or Longvarbinary data must use the special API. If you are working with Longvarchar, you can use the same methods to select, insert, or update them in SQL queries as you use with any other datatypes.

Here are the restrictions:

There is a default 32K-per-field restriction on Text/Image data retrieved by an SQL select in the Sybase SQL Server, and a 4K restriction for MS SQL Server; a select will receive at most this much data per field. Larger values will be truncated silently by the DBMS. You can adjust the amount of Text/Image data returned by a select by calling the Statement.setMaxFieldSize() method with a different value (smaller or larger). Note that needlessly large settings could cause the JDBC drive to needlessly run out of memory. Also note that setMaxFieldSize() is an instance method, so it needs to be called for every Statement object that will retrieve Text/Image data.

If your Text/Image data fits within these restrictions, you can use SQL queries as with any other datatype and ignore the following section. Otherwise, if your Text data does not fit within these restrictions, or if you are retrieving Image (non-Text) data, you will use textpointers for retrieving, inserting, and updating, as explained in "Handling larger Text/Image data."

Handling larger Text/Image data

Updates to Longvarchar or Longvarbinary columns using textpointers require methods that do not exist in the current JDBC 1.0 specification. This feature is valuable enough that we have supplied a public method for it that is not part of the JDBC API. If you need this feature, please contact jdbc@wombat.eng.sun.com and ask that it be added to future revisions of the JDBC spec.

SQL Server does not handle columns of type Text/Image the same way it handles other datatypes. The differences, visible both in the SQL statements used to access Text/Image data and in the additional non-SQL programming necessary to access Text/Image, are based on the SQL Server concept known as the text pointer.

A SQL Server table with a column of type Text or Image stores a 16-byte binary value (a text pointer) that describes where the Text/Image data is actually stored on the SQL Server logical device. Consequently, operations involving Text/Image data require two steps: you must

  1. Use a SQL select statement to retrieve the text pointer.
  2. Then read or write the actual Text/Image data.

Retrieving Text/Image data. With the jdbcKona SQL Server drivers, you select Text/Image data in the same way that you get results of other types. The two-step process of retrieving the text pointer and using it to read the data is hidden. There are, however, two restrictions on working with the results:

  • The ResultSet must contain only a single column of type Text or Image. (This is a SQL Server restriction, not a jdbcKona restriction.)
  • The ResultSet getXXX() routine to access the retrieved data must be one of the ResultSet methods that returns a Java java.io.InputStream, such as getAsciiStream().

Here is an example for retrieving Text/Image data. It assumes a table with the following schema:

CREATE TABLE textTable (id INT NOT NULL, textdata TEXT NULL)
  Connection conn; //Open SQL Server connection

  Statement stmt = conn.createStatement();
  ResultSet rs =
    stmt.executeQuery("select textdata from textTable where id > 10");
  while (rs.next()) {
    InputStream x = rs.getAsciiStream(1);
    if (rs.wasNull()) {
      System.out.println("");
      continue;
    }
    while ((int ch = x.read()) != -1)
      System.out.print((char)ch);
  }

Inserting or Updating Text/Image data. SQL Server does not allow you to insert Text/Image data as part of a SQL INSERT or UPDATE. These SQL operations with Text/Image data require a multistep operation with multiple SQL statements and a special DBLIB C routine called dbwritetext. We provide a special JDBC extension around dbwritetext: weblogic.jdbc.dblib.Statement.executeWriteText(). There are four method signatures for this method; you may use either a byte array or an InputStream as a source for the Text/Image type, and you may also elect to use a Sybase timestamp for versioning.

Text/Image updates will usually require a second connection to the SQL Server DBMS; one connection selects the text pointer, and the other carries out the update referenced by the text pointer. If you are updating only a single text value in a single row, this may not be necessary; but if you are scanning through multiple rows and modifying Text/Image type values in each, you will need to use a second JDBC Connection.

Here is a step-by-step example that outlines the sequence of operations for updating Text/Image types.

Step 1. Open two connections to the SQL Server

The example, which uses the table with the schema shown above, assumes that you have already opened two java.sql.Connection objects, conn and conn2. In this example, we also initialize several variables.

  Connection conn;
  Connection conn2;
  byte[] textptr;                // Text pointer
  byte[] myData;                 // Text/image data to be sent 
  int myDataOffset = 0;          // Offset of Text/Image data
  int myDataLen = myData.length; // Length of Text/Image data
If you are updating a Text/Image value that already has data in it, skip to Step 4.

Step 2. Insert a row for the data

Using the first Connection conn, insert the row and specify a null value in the Text/Image field. At this point there is no valid text pointer in the field.

  Statement stmt = conn.createStatement();
  stmt.executeUpdate("insert textTable values(99, null)");
  stmt.close();
Note that if you are updating a Text/Image value that already has data in it, you should omit Step 2 and Step 3.

Step 3. Update the database

Using the first Connection conn, update the text pointer to null again to force a valid text pointer value that points to empty data. After this, there will be a valid text pointer in the field.

  stmt = conn.createStatement();
  stmt.executeUpdate("update textTable set textdata " +
                     "= null where id = 99");
  stmt.close();

Note that if you are updating a Text/Image value that already has data in it, you should omit Step 2 and Step 3.

Step 4. Select the text pointer to be updated as a BINARY value

Using the first Connection conn, select the field to get the actual text pointer value as a BINARY value.

  stmt = conn.createStatement();
  ResultSet rs =
    stmt.executeQuery("select textptr(textdata) " +
                      "from textTable where id = 99");
  if (!rs.next())
    throw new SQLException("Select from textTable failed");
  textptr = rs.getBytes(1);

Step 5. Write the data

Using the second Connection conn2, create a weblogic.jdbc.dblib.Statement object. Since you do not import this package or any of its classes -- you should import java.sql.* instead -- you must use the fully-qualified class name when you create the Statement object. Then use the retrieved text pointer value with one of the weblogic.jdbc.dblib.Statement.executeWriteText() methods (jdbcKona extensions to to JDBC) to actually write the Text/Image data. There are two executeWriteText() methods; one for writing an array of bytes (byte[]), the other for using an InputStream as the source of data.

In the example, we use a byte array as the source of data. Note that you must explicitly cast the Statement.

  weblogic.jdbc.dblib.Statement stmt2 =
      (weblogic.jdbc.dblib.Statement) conn2.createStatement();
  stmt2.executeWriteText("textTable",// Table name for update
                 "textdata", // Text/Image column name for update
		 textptr,    // Text pointer value
	         true,       // True if write operation should be logged
		 mydata,     // Text/Image data to be written
		 myoffset,   // Offset into mydata of 1st byte
		 myDataLen,  // Length of data to be written

Note that logging a write of Text/Image data is an expensive operation, so you may want to set logging to false. In that case, you must configure the SQL Server DBMS to allow nonlogged text updates.

Here is an example that sets the unlogged updates option:

1> use master
2> go
1> sp_dboption mydb, "sel", "true"
2> go
Database option 'select into/bulkcopy' turned ON for database 'mydb'.
Run the CHECKPOINT command in the database that was changed.
(return status = 0)
1> use mydb
2> go
1> checkpoint
2> go

Note also that Step 5 can be done in SQL using a SQL Server extension to standard SQL called WRITETEXT, but that can only be done with data embedded in the statement, and with a maximum of 120 Kbytes or less. Here is how Step 5 would be written using SQL WRITETEXT:

  WRITETEXT textTable.textdata @textptr with log "My data"

Here is another example of using the executeWriteText() method that incorporates the use of a SQL Server timestamp to compare the version to be updated and the version stored in the column. WebLogic provides an extension to JDBC, weblogic.jdbc.dblib.Statement.getTextTimestamp() to get access to the timestamp data.

This code example shows how getTextTimestamp() is used. Note that the Statement must be cast as a weblogic.jdbc.dblib.Statement to take advantage of WebLogic's extensions to JDBC. The following code snippet shows the usage:

  // Select the data using a Statement "stmt"
  ResultSet rs =
    stmt.executeQuery("select doc from db..texttable where doc_no = 99");

  if (!rs.next())
    throw new SQLException("Select from texttable failed");

  weblogic.jdbc.dblib.Statement wstmt =
    (weblogic.jdbc.dblib.Statement) stmt;

  byte[] timestamp = wstmt.getTextTimestamp();
  while(rs.next());

  FileInputStream file = new FileInputStream(mytextfile);
  stmt.executeWriteText("db..texttable",
                        "doc",
			textptr,
			true,
			file,
			(int)mytextfile.length(),
			timestamp);
The full example for this illustration is included in the distribution in both the examples/jdbc/sybase and examples/jdbc/mssqlserver directories as simpleTextWithTimestamp.

Top of this section

Notes on DatabaseMetaData methods

With release version 2.1, all of DatabaseMetaData is implemented in jdbcKona/Sybase and jdbcKona/MSSQLServer. There are some variations that are specific to SQL Server that are detailed here:

  • SQL wildcards are not allowed as arguments to DatabaseMetaData routines, with the following exceptions:

    • The getProcedures() method allows the String schemaPattern and the String procedureNamePattern arguments to be wildcards.
    • The getColumns() method allows the String schemaPattern, the String tableNamePattern, and the String columnNamePattern to be wildcards.

  • Methods with the String catalog argument only work in the current database, and can only be called with either the name of the current database, the Java empty String (""), or Java NULL.

  • To implement the ODBC standard metadata methods such as getTables(), the WebLogic drivers rely on the ODBC stored procedures such as sp_tables that Microsoft and Sybase supply. These stored procedures only work in the current database and reject any catalog (database) arguments. Wildcard expressions will work for the tablename and schema (owner) arguments.

    If you are already in the correct database, you can call getTables() as follows:

      DatabaseMetaData dmeta = connection.getMetaData();
      ResultSet rs = dmeta.getTables("", "", "%", null);

    If you are not in the desired database, change to that database, create a DatabaseMetaData object, and then run getTables() with an empty catalog argument. Assuming you are in the database "master," and you want to retrieve metadata for database "pub," you would follow this pattern:

      // Save the name of your current database
      String lastdb = connection.getCatalog();
    
      // Change to the new database. You could also issue a
      // "use database" command.
      connection.setCatalog("pubs");
    
      // Create the DatabaseMetaData object for the new database
      DatabaseMetaData dmeta = connection.getMetaData();
    
      // Issue the call
      ResultSet rs = dmeta.getTables("", "", "%", null);
    
      // Process the results
      while (rs.next()) {
        . . . print out the rows . . .
      }
    
      // Switch back to the previous database
      connection.setCatalog(lastdb);

WebLogic release 2.3 added new DEFERABILITY column to the ResultSet for the following methods, to conform to JDBC 1.1:

  • DatabaseMetaData.getImportedKeys()
  • DatabaseMetaData.getExportedKeys()
  • DatabaseMetaData.getCrossReferences()
Top of this section

Notes on transaction isolation levels

The JDBC Connection.setTransactionIsolation(level) method allows the transaction isolation level to be set for all subsequent transactions. Note that if you are already in a transaction, a call to Connection.setTransactionIsolation() will fail.

For Microsoft SQL Server, all transaction isolation levels except TRANSACTION_NONE are supported.

The mapping between JDBC constants (found in the Connection class) and Sybase isolation levels is as follows:

Constant in Connection class Sybase equivalent
TRANSACTION_NONE Not supported (use TRANSACTION_READ_COMMITTED)
TRANSACTION_READ_UNCOMMITTED Sybase level 0 (allows dirty reads)
TRANSACTION_READ_COMMITTED Sybase level 1 (prevents dirty reads)
TRANSACTION_REPEATABLE_READ Not supported (use TRANSACTION_SERIALIZABLE)
TRANSACTION_SERIALIZABLE Sybase level 3 (prevents phantoms)

Top of this section

III. What is not supported in the jdbcKona SQL Server drivers

Some of the JDBC API is not currently implemented, including:

Support for the SQL Server "compute" functionality. SQL Server supports "compute" queries that interleave regular result rows and vector aggregate (computed) rows. An example is:

  select db_name(id), id, size from sysusages
  order by id
  compute sum(size) by id

Although this feature could be supported in jdbcKona, there is no way to retrieve the results of such a query within the parameters of the JDBC API, and no easy way to extend the JDBC model. If you need this feature, please contact jdbc@wombat.eng.sun.com and ask that it be added to future revisions of the JDBC spec.

Support for Sybase SQL Server cursors. Cursors are not currently supported.

Top of this section

IV. Change history

Release 4.0.1

Added a change to ensure that Statement.setMaxRows() affects only the Statement on which it is called. The Transact-SQL setrowcount command, which is used to implement setMaxRows, affects all subsequent results on the client's connection. With this change, the drivers reset maxRows as needed for each Statement.

Release 3.1.6

To provide the functionality of setAutocommit(true), the jdbcKona/MSSQLServer driver sent SQL begin transaction and commit transaction commands. In release 3.1.6, the driver instead uses the SQL Server set implicit_transactions command for this purpose. The set implicit_transactions command has the advantage that it does not begin a transaction in the SQL Server until a statement is received. When the driver used the begin transaction command, a transaction was opened whenever the previous transaction ended. If such an open transaction remained open for a long time, it could cause problems with truncating the transaction log, since the log cannot be truncated past the longest open transaction. See More on autocommit with MS SQL Server for more about this feature.

Release 3.1.2

When you call Statement.execute(), any current result set is cancelled. This behavior has been extended so that Statement.execute() cancels the current result set, as well as any subsequent result sets pending.

PreparedStatement.clearParameters() now clears parameter values without unregistering output parameters.

Statement.execute() was returning true in some cases where the first result was not a result set. This is fixed.

Fixed a problem where PreparedStatement() could not create a parameter of type DECIMAL.

Release 3.1

Sybase. Changed behavior so that we no longer throw a fatal exception in response to Sybase error 2409, which signals that the character set associated with the client is not loaded on the DBMS. A Connection is now successfully returned in spite of this Sybase error; those users still interested in the 2409 error can use the Connection.getWarnings() to check for the error.

The jdbcKona/Sybase and jdbcKona/MSSQLServer drivers now have full codeset support that is based on codeset support in the JDK rather than the native vendor implementations. For more information on using alternate codesets, see the Developers Guide, Using jdbcKona/Sybase and jdbcKona/MSSQLServer.

Release 3.0.4

Fixed obscure problem in the Sybase and MS SQL Server jdbcKona drivers that caused a very long batch update (more than 250,000 bytes) to be cancelled before completion if the latency time was excessive.

In jdbcKona/Sybase, added support for READ_UNCOMMITTED to Sybase isolation levels.

Release 3.0.1 -- 3/10/98

Added codeset support to define the Java-supported codeset that the native layer will use to interact with the DBMS. The valid names are JDK dependent, but are described in the JavaSoft I18n specification.

Release 3.0 -- 1/29/98

No changes.

Release 2.5 -- 8/25/97

Added support for Microsoft's 2.0 JVM. Microsoft currently has two official versions of their Java runtime available, WebLogic's jdbcKona native two-tier drivers are compatible with SDK-2.0, which is currently in beta.

Added support for JDBC Extended SQL for jdbcKona/Sybase and jdbcKona/MSSQLServer. JavaSoft's JDBC specification includes a feature called SQL Extensions, or SQL Escape Syntax. This is support for embedding DBMS-independent access into the myriad secondary functions provided by every DBMS, which most often takes the form of vendor-specific extensions to SQL. For more information, including examples, of WebLogic support for extended SQL in the jdbcKona drivers, see the Developers Guide, Overview of the jdbcKona native drivers.

Release 2.4 -- 5/20/97

Added examples/jdbc/sybase/storedprocs.java that shows how to generate and retrieve user-defined messages from stored procedures to Java, including non-static data or time-dependent message content. This example also shows an example of creating and retrieving user-defined messages from T-SQL.

Fixed problem with MS SQL Server money types.

Added performance enhancement on retrieval of Sybase MONEY, DECIMAL, and NUMERIC types.

Increased buffer size from 2K to 64K for faster SQL Server Text/Image reads and writes.

Added a WebLogic extension to JDBC, that mimics autoCommit(false) for MS SQL Server users. For more information, see the Using jdbcKona/Sybase and jdbcKona/MSSQLServer.

Completed all versions of PreparedStatement.setObject() for SQL Server.

Release 2.3.2 -- 3/18/97

Added a WebLogic extension to JDBC for Sybase OpenServer, in the class weblogic.jdbc.dblib.CallableStatement. The method setParamName() allows setting parameter names for use with OpenServer RPC or SQL Server stored procedures.

Added functionality for returning a Sybase timestamp associated with the Text/Image field of the current row. See new method signatures for weblogic.jdbc.dblib.Statement.executeWriteText() and new method weblogic.jdbc.dblib.Statement.getTextTimestamp().

Increased buffer sizes from 2K to 64K for faster reads and writes of SQL Server Text/Image types.

Fixed problem with returns of incorrect vendor codes in SQLExceptions thrown during query execution.

jdbcKona/MSSQLServer only. Some problems reported were cleared up with the installation of patch 2 of MS SQL Server 6.5. We highly recommend that you install this patch.

Fixed problem with DatabaseMetaData.supportsTransactionIsolationLevel().

Fixed problem with DatabaseMetData.getColumns(). Note that Sybase does not provide COLUMN_DEF, SQL_DATA_TYPE, or IS_NULLABLE. These calls are set to NULL or "" as appropriate.

Added support for usage of NULL values of NUMERIC and DECIMAL data types. Also added support on CallableStatements for numerica values beyond the default 10-digit, no-decimal-point value.

Release 2.3 -- 12/23/96

The PreparedStatement methods setString(), setBytes(), setAsciiStream(), setUnicodeStream, and setObject() now allow inserts/updates on SQL Server text/image columns of up to approximately 120 Kbytes (previously limited to 255 bytes in length). For longer lengths than 120 Kbytes, use the WebLogic extension Statement.executeWriteText(). jdbcKona/Sybase and jdbcKona/MSSQLServer classes affected by this change are PreparedStatement and CallableStatement.

Changed ResultSet.getObject() to return Timestamp rather than Date, when retrieving a DBMS column of type SYBDATETIME (SQLDATETIME), for more precision.

To conform to JDBC 1.1, added new DEFERABILITY column to the ResultSets for DatabaseMetaData.getImportedKeys(), DatabaseMetaData.getExportedKeys(), and DatabaseMetaData.getCrossReferences.

SQL Server passwords are no longer displayed if login fails.

When a SQLException is thrown as a result of a SQL Server error, the SQLException error code should be set to the SQL Server error number so that the application program can determine the type of error.

Microsoft only: Fixed occasional SQLException resulting from a call to Connection.setTransactionIsolation().

Release 2.2 -- 10/27/96

Added support for Sybase OpenServer RPCs.

Calling ResultsSet.getBytes() on a ResultSet containing a single Text or Image column no longer fails.

Problems retrieving data of type Text/Image using a SQL select statement have been fixed. There are new instructions in "Working with Text and Image types" that describe the changes in detail.

When a SQLException is thrown because the query execution failed on the SQL Server, the Exception message now contains the text of the query.

Fixed a problem where queries containing an SQL SELECT on a Text/Image column and at least one other column would sometimes append extra bytes to the data retrieved from the Text/Image column.

Added support for Windows95.

Release 2.1.1 -- 9/9/96

Added RPC support for Sybase Open Server and Microsoft Data Server. For full details, see the Using stored procedures and RPCs.

Fixed problems with the following methods in the jdbcKona drivers for SQL Server: Connection.setCatalog(), Connection.getCatalog(), and DatabaseMetaData.getCatalogs().

Release 2.1 -- 8/14/96

Production release of the jdbcKona drivers.

Release 2.0.6 -- 8/5/96

Realigned implementation with revised version of the JDBC API for multiple result sets. Please see Executing and canceling DBMS queries for more information.

Completed implementation of DatabaseMetaData methods (with the exception of getURL()); tested only with Sybase.

Release 2.0.3 -- 7/8/96

First beta release of jdbcKona/Sybase and jdbcKona/MSSQLServer.

 

Copyright © 2000 BEA Systems, Inc. All rights reserved.
Required browser: Netscape 4.0 or higher, or Microsoft Internet Explorer 4.0 or higher.
Last updated 04/05/1999