Introduction

Comdb2 provides Java programming language binding with Cdb2jdbc. Cdb2jdbc is a JDBC Type 4 driver, which means that the driver is a platform-independent, pure Java implementation.

Installation

Installing from Source

To check out the source, please follow the instructions.

Maven

To install cdb2jdbc from source, the following additional software packages are required:

Once you check out the source and have all the required software installed on the system, change directory to cdb2jdbc under comdb2 source and type mvn clean install.

cd cdb2jdbc
mvn clean install

cdb2jdbc should be successfully installed in your local Maven repository. The JAR files normally can be found in ~/.m2/repository/com/bloomberg/comdb2/cdb2jdbc/.

A word of caution: the build can fail if the version of protocol buffers installed on the system mismatches the version specified in cdb2jdbc/pom.xml. If you encounter problems, update the protobuf-java version in the .pom file to match what’s on the system. Another option is to build the driver inside a Docker container by running make jdbc-docker-build in cdb2jdbc (JAR files will be written to cdb2jdbc/maven.m2/repository/com/bloomberg/comdb2/cdb2jdbc/2.0.0/)

Gradle

Another way to install cdb2jdbc from source is the gradle wrapper. The following software packages are required:

  • JDK 1.7 or above

Note that existing installations of gradle and protocol buffers are not required for the gradle build

Once you check out the source and have all the required software installed on the system, change directory to cdb2jdbc under comdb2 source and type ./gradlew install or ./gradlew.bat install for Windows.

cd cdb2jdbc
./gradlew install

You can also use an existing install of gradle instead of the wrapper. At least version 2.12 is required.

This build will install cdb2jdbc into your local Maven repository. The JAR files normally can be found in ~/.m2/repository/com/bloomberg/comdb2/cdb2jdbc/.

Setting up Cdb2jdbc

There are 2 approaches to set up cdb2jdbc: using build tools or setting the classpath.

Build tools

As a Maven dependency

To introduce cdb2jdbc in your applications as a Maven dependency, add the following to pom.xml, with the version available from your Maven repository.

<dependency>
  <groupId>com.bloomberg.comdb2</groupId>
  <artifactId>cdb2jdbc</artifactId>
  <version>major.minor.patch</version>
</dependency>

As a Gradle dependency

If you followed the steps above to install cdb2jdbc form source, it should be in your local Maven repository. Add the following to your build.gradle with the version replaced to the cdb2jdbc version.

repositories {
    mavenLocal()
}

dependencies {
    compile 'com.bloomberg.comdb2:cdb2jdbc:major.minor.patch'
}

Setting the Classpath

By default, an uber JAR is built along with cdb2jdbc and is named cdb2jdbc-<version>-shaded.jar. An uber JAR is a JAR file which contains all its dependencies. To use the JAR without Maven, you would include it in CLASSPATH.

export CLASSPATH=<path_to_the_uber_jar>:$CLASSPATH

Using Cdb2jdbc

* The section is not intended as a guide to JDBC programming. For more information, please refer to the official JDBC website

Loading the Driver

One common approach for loading the driver is to use Class.forName(). To load cdb2jdbc, you would use:

Class.forName("com.bloomberg.comdb2.jdbc.Driver");

Connecting to a Database

A Comdb2 database is represented by a JDBC URL. Cdb2jdbc takes one of the following forms:

jdbc:comdb2://<stage>/<database>[?options]
jdbc:comdb2://<host>[:port][, <host>[:port], ...]/<database>[?options]

For example, to connect to a local database called testdb, you would use:

Connection conn = DriverManager.getConnection("jdbc:comdb2://localhost/testdb");

The parameters are as follows:

  • stage

    Please refer to cdb2_open for the information about stage.

  • host

    The host name of the server.

  • port

    The port number the database is listening on. If not specified, cdb2jdbc queries pmux to get the dynamically allocated port number.

    * To support connection failover, you would define multiple host/port pairs in the URL, separated by commas.

  • database

    The database name.

  • options

    • user=String

      The database user. The default is empty.

    • password=String

      The password of the database user. The default is empty.

    • sotimeout=Integer

      Socket timeout for the target database, in milliseconds. The default is 5,000 milliseconds.

    • maxquerytime=Integer

      The maximum execution time allowed in seconds for a query.

    • connect_timeout=Integer

      Connect timeout in milliseconds. The default is 100 milliseconds.

    • comdb2db_timeout=Integer

      Socket timeout for comdb2db, in milliseconds. The default is 5,000 milliseconds.

    • dbinfo_timeout=Integer

      Socket timeout for the DBINFO response, in milliseconds. The default is 500 milliseconds.

    • load_balance=”room” | “randomroom” | “random”

      The load balance policy.

    • default_type=String

      Please refer to Client Setup for more information.

    • room=String

      Please refer to Client Setup for more information.

    • comdb2dbname=String

      Please refer to Client Setup for more information.

    • dnssuffix=String

      Please refer to Client Setup for more information.

    • portmuxport=Integer

      The port number which pmux is listening on. The default is 5105.

    • tcpbufsz=Integer

      The value for SO_RCVBUF, which is the maximum socket receive buffer size for the underlying TCP connections to the database server.

    • microsecond_fraction=Boolean

      The precision of the fractional second when binding a java.sql.Timestamp parameter. If it is set to false, millisecond precision is used. otherwise, microsecond precision is used. The default is true.

    • preferred_machine=String

      When set, the driver connects to the preferred machine whenever possible, with “RANDOM” load balance strategy.

    • ssl_mode=String

      Can be one of the following values:

      • ALLOW

      • REQUIRE

      • VERIFY_CA

      • VERIFY_HOSTNAME

    • key_store=String

      Path to the client keystore.

    • key_store_password=String

      Passphrase of the client keystore.

    • key_store_type=String

      Type of the keystore. The default is "JKS".

    • trust_store=String

      Path to the certificate authority (CA) keystore.

    • trust_store_password=String

      Passphrase of the CA keystore.

    • trust_store_type=String

      Type of the trusted CA keystore. The default is "JKS".

    • crl=String

      Path to the Certificate Revocation List (CRL), in PEM format.

    • allow_pmux_route=Boolean

      Allow connection forwarding via pmux. The default is false.

    • verify_retry=Boolean

      Toggle verifyretry. The default is false. See also optimistic concurrency control.

    • use_txn_for_batch=Boolean

      Set it to true to execute a batch in its own transaction. The default is false.

    * To define multiple options, separate them by ampersands.

Issuing a Query and Browsing the Result

The example below issues a simple SELECT query and prints the rows.

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT column FROM table WHERE column = 1");
while (rs.next())
    System.format("column is %s\n", rs.getString(1));
rs.close();
stmt.close();

The example uses PreparedStatement to issue a query.

int column = 1;
PreparedStatement ps = conn.prepareStatement("SELECT column FROM table WHERE column = ?");
ps.setInt(1, column);
ResultSet rs = ps.executeQuery();
while (rs.next())
    System.format("column is %s\n", rs.getString(1));
rs.close();
ps.close();

Performing Updates

To perform updates (INSERT, UPDATE or DELETE), you would use executeUpdate(). This function does not return a ResultSet object. Instead it returns the number of rows affected.

The example performs a delete and prints the number of rows deleted.

Statement stmt = conn.createStatement();
int ndel = stmt.executeUpdate("DELETE FROM table WHERE column = 1");
System.format("%d row(s) deleted\n", ndel);
stmt.close();

Invoking Stored Procedures

Cdb2jdbc does not implement the CallableStatement interface. Instead, you should use the Statement or PreparedStatement.

The example invokes a stored procedure called foo.

Statement sp = conn.createStatement();
sp.executeQuery("exec procedure foo()");

The result would come back as a normal ResultSet object.

Using SSL connections

The jdbc driver has built-in SSL support. It uses SSL if the server requires SSL. Otherwise it falls back to plaintext. The process is transparent to the application. To enforce SSL, you would add ssl_mode=REQUIRE to the JDBC URL.

If the server requires client certificates, you need to provide the driver with a Java KeyStore (JKS).

A JKS can be converted from an OpenSSL certificate. First, you would convert the certificate to DER format if it is in PEM format using OpenSSL:

# Convert PEM to something java understands first
$ openssl x509 -in client.pem -out client.crt.der -outform der

To convert a DER certificate to JKS, you would use $JAVA_HOME/bin/keytool:

# Convert the DER certificate to a java KeyStore file.
$ keytool -import -file client.crt.der -keystore path/to/keystore -alias comdb2

To load the JKS into the driver, the JDBC URL looks like this:

jdbc:comdb2//<hostname>/<database>?key_store=<path/to/jks>&key_store_password=<passwd>

A trusted CA keystore can be generated the same way to authenticate the server.

To load the trusted CA JKS into the driver, the JDBC URL looks like this:

jdbc:comdb2//<hostname>/<database>?trust_store=<path/to/jks>&trust_store_password=<passwd>

Comdb2 Extensions to the JDBC API

Executing Typed Queries

A typed query gives applications more control over return types. The database will coerce the types of the resulting columns to the types specified by the application. If the types aren’t compatible, an exception will be thrown.

To access the extension, you would need to cast the java.sql.Statement object to com.bloomberg.comdb2.jdbc.Comdb2Statement. For example:

conn = DriverManager.getConnection("jdbc:comdb2:/localhost/testdb");
stmt = conn.createStatement();
comdb2stmt = (Comdb2Statement)stmt;
String sql = "select now()";
rset = comdb2stmt.executeQuery(sql, Arrays.asList(java.sql.Types.VARCHAR));

In the example above, the row will come back as a java.lang.String instead of a java.sql.TIMESTAMP.

Using Intervals

JDBC standard does not define data types for intervals. You could work it around using Comdb2 interval types. For example, to bind an INTERVALDS (interval day to second) value, you would use:

// Load driver, get connection and create a parepared statement...
// bind an interval year-month (+3 mon)
stmt.setObject(1, new Cdb2Types.IntervalYearMonth(1, 0, 3));

Using Named Parameters for PreparedStatement

Comdb2 has built-in support for named parameters. You would simply use @param_name instead of ? in your queries:

PreparedStatement stmt = conn.prepareStatement("insert into employee values (@id, @firstname, @lastname)");

Java and Comdb2 Types

The table below shows the conversions between Java and Comdb2 types.

Java Type Comdb2 Type
java.lang.Short short
java.lang.Short u_short
java.lang.Integer int
java.lang.Integer u_int
java.lang.Long longlong
java.lang.Float float
java.lang.Double double
java.math.BigDecimal
java.lang.String
decimal32
java.math.BigDecimal
java.lang,String
decimal64
java.math.BigDecimal
java.lang.String
decimal128
java.sql.Blob
java.sql.Array
byte[]
byte
java.sql.Blob
java.sql.Array
byte[]
blob
java.lang.String cstring
java.lang.String vutf8
java.sql.Date
java.sql.Time
java.sql.Timestamp
java.util.Calendar
datetime
java.sql.Timestamp datetimeus
com.bloomberg.comdb2.jdbc.Cdb2Types.IntervalYearMonth intervalym
com.bloomberg.comdb2.jdbc.Cdb2Types.IntervalDaySecond intervalds
com.bloomberg.comdb2.jdbc.Cdb2Types.IntervalDaySecondUs intervaldsus

SQLSTATEs in Cdb2jdbc

The following table shows how SQLSTATEs are mapped to SQLExceptions in cdb2jdbc.

SQLSTATE SQLException Comment
08000 SQLNonTransientConnectionException
SQLTransientConnectionException
connection errors
42000 SQLSyntaxErrorException syntax errors
28000 SQLInvalidAuthorizationSpecException invalid credentials
22000 SQLNonTransientException data errors
25000 SQLNonTransientException wrong sql engine state
0A000 SQLFeatureNotSupportedException not supported
23000 SQLIntegrityConstraintViolationException constraint violations
COMDB SQLException db errors