1 package net.jaekl.cfb.db.driver;
3 // Copyright (C) 2015 Christian Jaekl
5 import static net.jaekl.cfb.db.Column.Null.*;
7 import java.sql.Connection;
8 import java.sql.PreparedStatement;
9 import java.sql.ResultSet;
10 import java.sql.SQLException;
11 import java.util.ArrayList;
12 import java.util.List;
14 import net.jaekl.cfb.db.Column;
15 import net.jaekl.cfb.db.Column.Type;
16 import net.jaekl.cfb.db.Condition;
17 import net.jaekl.cfb.db.Row;
18 import net.jaekl.cfb.db.Sequence;
19 import net.jaekl.cfb.db.Table;
21 public abstract class DbDriver {
22 static int PENDING_LIMIT = 1024; // Rough limit at which point we'll start a new batch for batch updates
28 // Load the JDBC driver
29 public abstract void load() throws ClassNotFoundException;
31 public abstract Connection connect(String host, int port, String dbName, String user, String pass) throws SQLException;
33 public boolean createTable(Connection con, Table table) throws SQLException {
34 String sql = createTableSql(table);
35 try (PreparedStatement ps = con.prepareStatement(sql)) {
38 catch (SQLException exc) {
39 throw new SQLException("Failed to executeUpdate: " + sql, exc);
45 public boolean createSequence(Connection con, Sequence seq) throws SQLException
47 String sql = createSequenceSql(seq);
48 try (PreparedStatement ps = con.prepareStatement(sql)) {
51 catch (SQLException exc) {
52 throw new SQLException("Failed to executeUpdate: " + sql, exc);
58 public List<Row> select(Connection con, Column[] columns, Table[] tables, Condition[] conditions)
61 String sql = selectSql(columns, tables, conditions);
62 ArrayList<Row> result = new ArrayList<Row>();
64 try (PreparedStatement ps = con.prepareStatement(sql)) {
66 for (Condition condition : conditions) {
67 if (condition.getOperation().hasParam()) {
69 ps.setObject(index, condition.getValue());
73 try (ResultSet rs = ps.executeQuery()) {
75 Object[] values = new Object[columns.length];
76 for (index = 0; index < columns.length; ++index) {
77 values[index] = rs.getObject(index);
79 Row row = new Row(columns, values);
88 // Returns the number of rows inserted
89 public int insert(Connection con, Table table, Object[][] values) throws SQLException
92 int pendingValues = 0;
94 String sql = insertSql(table);
96 try (PreparedStatement ps = con.prepareStatement(sql))
98 for (int row = 0; row < values.length; ++row) {
99 Object[] data = values[row];
101 assert(null != data);
102 assert(data.length == table.getNumColumns());
104 for (int col = 0; col < data.length; ++col) {
105 ps.setObject(col + 1, data[col]);
110 int rowsFlushed = checkFlushBatch(ps, pendingValues, false);
111 if (rowsFlushed > 0) {
112 count += rowsFlushed;
117 count += checkFlushBatch(ps, pendingValues, true);
123 int checkFlushBatch(PreparedStatement ps, int pendingValues, boolean forceFlush) throws SQLException
127 if (forceFlush || (pendingValues >= PENDING_LIMIT))
129 int[] updateCounts = ps.executeBatch();
130 for (int i = 0; i < updateCounts.length; ++i) {
131 if (updateCounts[i] > 0) {
132 count += updateCounts[i];
140 String insertSql(Table table) {
141 StringBuilder sb = new StringBuilder("INSERT INTO ");
142 sb.append(table.getName())
143 .append(" VALUES (");
145 for (int i = 0; i < table.getNumColumns(); ++i) {
153 return sb.toString();
156 protected String selectSql(Column[] columns, Table[] tables, Condition[] conditions)
158 StringBuilder sb = new StringBuilder("SELECT ");
160 boolean firstColumn = true;
161 for (Column column : columns) {
168 sb.append(column.getName());
173 boolean firstTable = true;
174 for (Table table : tables) {
181 sb.append(table.getName());
184 if (null != conditions && conditions.length > 0) {
185 sb.append(" WHERE ");
187 boolean firstCondition = true;
189 for (Condition condition : conditions) {
190 if (firstCondition) {
191 firstCondition = false;
197 sb.append(condition.getColumn().getName())
198 .append(condition.getOperation().getSql());
202 return sb.toString();
205 protected String typeName(Type type) {
206 return type.toString();
209 protected String createColumnSql(Column column)
211 String result = column.getName() + " " + typeName(column.getType());
212 if (column.getWidth() > 0) {
213 result += "(" + column.getWidth() + ")";
216 if (NOT_NULL == column.getNull()) {
217 result += " NOT NULL";
226 protected String createTableSql(Table table)
228 assert(null != table);
229 assert(null != table.getName());
230 assert(table.getNumColumns() > 0);
232 StringBuilder sb = new StringBuilder();
234 sb.append("CREATE TABLE ")
235 .append(table.getName())
238 for (int idx = 0; idx < table.getNumColumns(); ++idx) {
242 sb.append(createColumnSql(table.getColumn(idx)));
247 return sb.toString();
250 protected String createSequenceSql(Sequence seq) {
252 assert(null != seq.getName());
254 return "CREATE SEQUENCE " + seq.getName();