+package net.jaekl.cfb.db.driver;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import net.jaekl.cfb.db.Sequence;
+
+public class SqliteDriver extends DbDriver {
+ static final long SEQ_NO_VALUE = (-1);
+ static final long SEQ_INIT_VALUE = 0;
+
+ @Override
+ public void load() throws ClassNotFoundException {
+ Class.forName("org.sqlite.JDBC");
+ }
+
+ @Override
+ public Connection connect(String host, int port, String dbName, String user, String pass)
+ throws SQLException
+ {
+ String url = "jdbc:sqlite:" + dbName;
+ return DriverManager.getConnection(url);
+ }
+
+ @Override
+ public long nextVal(Connection con, Sequence seq) throws SQLException
+ {
+ final String sqlRead = "SELECT value FROM " + seq.getName();
+ final String sqlIncr = "UPDATE " + seq.getName() + " SET value=? WHERE value=?";
+ long value = SEQ_NO_VALUE;
+
+ boolean auto = con.getAutoCommit();
+ try (
+ PreparedStatement psRead = con.prepareStatement(sqlRead);
+ PreparedStatement psIncr = con.prepareStatement(sqlIncr);
+ )
+ {
+ con.setAutoCommit(false);
+
+ for (int retryCount = 10; retryCount > 0; retryCount--) {
+ try ( ResultSet rs = psRead.executeQuery() )
+ {
+ if (rs.next()) {
+ value = rs.getLong(1);
+ }
+ }
+
+ if (value >= SEQ_INIT_VALUE) {
+ psIncr.setLong(1, value + 1);
+ psIncr.setLong(2, value);
+ int count = psIncr.executeUpdate();
+ if (1 == count) {
+ return (value + 1);
+ }
+ }
+ }
+ }
+ finally {
+ con.setAutoCommit(auto);
+ }
+
+ throw new SQLException("Unable to get next value for sequence " + seq.getName() + ". Retry count exceeded.");
+ }
+
+ @Override
+ public boolean createSequence(Connection con, Sequence seq)
+ throws SQLException
+ {
+ String sqlCreate = "CREATE TABLE " + seq.getName() + " ( value INTEGER )";
+ String sqlInsert = "INSERT INTO " + seq.getName() + " VALUES ( 0 )";
+
+ executeUpdate(con, sqlCreate);
+ executeUpdate(con, sqlInsert);
+
+ return true;
+ }
+}