import static net.jaekl.cfb.db.Column.Null.*;
import static net.jaekl.cfb.db.Column.Type.*;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import net.jaekl.cfb.analyze.MessageMap;
import net.jaekl.cfb.db.driver.DbDriver;
public class CfbSchema extends Schema {
+ MessageMap m_msgMap;
+
+ public static final Sequence BUG_SEQ = new Sequence("BUG_SEQ");
+ public static final Sequence CATEGORY_SEQ = new Sequence("CATEGORY_SEQ");
+ public static final Sequence FOUND_SEQ = new Sequence("FOUND_SEQ");
+ public static final Sequence LOC_SEQ = new Sequence("LOC_SEQ");
+ public static final Sequence RUN_SEQ = new Sequence("RUN_SEQ");
+
+ public static final String BUGID = "BUGID";
+ public static final String CATEGORYID = "CATEGORYID";
+ public static final String FOUNDID = "FOUNDID";
+ public static final String LOCID = "LOCID";
+ public static final String RUNID = "RUNID";
+
// Define each table as follows:
// {
// { table_name },
// { column_name, type, width (-1 for default), null/not_null }
// }
- private static final Object[][][] TABLES = {
- {
- // Description of each possible bug
- { "BUG" },
- { "BUGID", INTEGER, -1, NOT_NULL },
- { "TYPE", VARCHAR, 80, NOT_NULL }
- },
- {
- // Description of each possible bug category
- { "CATEGORY" },
- { "CATEGORYID", INTEGER, -1, NOT_NULL },
- { "CATEGORY", VARCHAR, 80, NOT_NULL }
- },
- {
- // One BugInstance, found during an analysis
- { "FOUND" },
- { "FOUNDID", INTEGER, -1, NOT_NULL },
- { "BUGID", INTEGER, -1, NOT_NULL },
- { "CATEGORYID", INTEGER, -1, NOT_NULL },
- { "FIRSTLOCID", INTEGER, -1, NOT_NULL },
- { "SECONDLOCID", INTEGER, -1, NULL },
- { "THIRDLOCID", INTEGER, -1, NULL }
- },
- {
- // Location in the source code referenced by a BugInstance
- { "LOCATION" },
- { "LOCID", INTEGER, -1, NOT_NULL },
- { "CLASSNAME", VARCHAR, 256, NOT_NULL },
- { "STARTLINE", INTEGER, -1, NULL },
- { "ENDLINE", INTEGER, -1, NULL }
- },
- {
- // Runs of FindBugs, normally one per build version
- { "RUN" },
- { "RUNID", INTEGER, -1, NOT_NULL },
- { "VERSION", VARCHAR, 32, NULL },
- { "STARTTIME", TIMESTAMPTZ, -1, NOT_NULL },
- { "ENDTIME", TIMESTAMPTZ, -1, NOT_NULL }
- }
- };
+ private static final Object[][] BUGS_DEFN =
+ {
+ // Description of each possible bug
+ { "BUG" },
+ { BUGID, INTEGER, -1, NOT_NULL },
+ { "TYPE", VARCHAR, 80, NOT_NULL }
+ };
+ private static final Object[][] CATEGORIES_DEFN =
+ {
+ // Description of each possible bug category
+ { "CATEGORY" },
+ { CATEGORYID, INTEGER, -1, NOT_NULL },
+ { "CATEGORY", VARCHAR, 80, NOT_NULL }
+ };
+ private static final Object[][] FOUND_DEFN =
+ {
+ // One BugInstance, found during an analysis
+ { "FOUND" },
+ { FOUNDID, INTEGER, -1, NOT_NULL },
+ { "BUGID", INTEGER, -1, NOT_NULL },
+ { "CATEGORYID", INTEGER, -1, NOT_NULL },
+ { "FIRSTLOCID", INTEGER, -1, NOT_NULL },
+ { "SECONDLOCID", INTEGER, -1, NULL },
+ { "THIRDLOCID", INTEGER, -1, NULL }
+ };
+ private static final Object[][] LOCATIONS_DEFN =
+ {
+ // Location in the source code referenced by a BugInstance
+ { "LOCATION" },
+ { LOCID, INTEGER, -1, NOT_NULL },
+ { "CLASSNAME", VARCHAR, 256, NOT_NULL },
+ { "STARTLINE", INTEGER, -1, NULL },
+ { "ENDLINE", INTEGER, -1, NULL }
+ };
+ private static final Object[][] RUNS_DEFN =
+ {
+ // Runs of FindBugs, normally one per build version
+ { "RUN" },
+ { RUNID, INTEGER, -1, NOT_NULL },
+ { "VERSION", VARCHAR, 32, NULL },
+ { "STARTTIME", TIMESTAMPTZ, -1, NOT_NULL },
+ { "ENDTIME", TIMESTAMPTZ, -1, NOT_NULL }
+ };
+
+ public static final Table BUGS = Table.construct(BUGS_DEFN);
+ public static final Table CATEGORIES = Table.construct(CATEGORIES_DEFN);
+ public static final Table FOUND = Table.construct(FOUND_DEFN);
+ public static final Table LOCATIONS = Table.construct(LOCATIONS_DEFN);
+ public static final Table RUNS = Table.construct(RUNS_DEFN);
+
+ private static final Sequence[] SEQUENCES = {
+ BUG_SEQ,
+ CATEGORY_SEQ,
+ FOUND_SEQ,
+ LOC_SEQ,
+ RUN_SEQ
+ };
+
+ private static final Table[] TABLES = {
+ BUGS,
+ CATEGORIES,
+ FOUND,
+ LOCATIONS,
+ RUNS
+ };
public CfbSchema(DbDriver driver) {
super("CFB", driver);
+
+ m_msgMap = null;
addTables(TABLES);
- }
+ addSequences(SEQUENCES);
+ }
+
+ public void setMessageMap(MessageMap msgMap) {
+ m_msgMap = msgMap;
+ }
+
+ @Override
+ boolean postCreationInit(Connection con) throws SQLException {
+ assert(null != m_msgMap);
+
+
+
+ return true;
+ }
}
import net.jaekl.cfb.db.Table;
public abstract class DbDriver {
+ static int PENDING_LIMIT = 1024; // Rough limit at which point we'll start a new batch for batch updates
+
DbDriver() {
}
return result;
}
+ // Returns the number of rows inserted
+ public int insert(Connection con, Table table, Object[][] values) throws SQLException
+ {
+ int count = 0;
+ int pendingValues = 0;
+
+ String sql = insertSql(table);
+
+ try (PreparedStatement ps = con.prepareStatement(sql))
+ {
+ for (int row = 0; row < values.length; ++row) {
+ Object[] data = values[row];
+
+ assert(null != data);
+ assert(data.length == table.getNumColumns());
+
+ for (int col = 0; col < data.length; ++col) {
+ ps.setObject(col + 1, data[col]);
+ pendingValues++;
+ }
+ ps.addBatch();
+
+ int rowsFlushed = checkFlushBatch(ps, pendingValues, false);
+ if (rowsFlushed > 0) {
+ count += rowsFlushed;
+ pendingValues = 0;
+ }
+ }
+
+ count += checkFlushBatch(ps, pendingValues, true);
+ }
+
+ return count;
+ }
+
+ int checkFlushBatch(PreparedStatement ps, int pendingValues, boolean forceFlush) throws SQLException
+ {
+ int count = 0;
+
+ if (forceFlush || (pendingValues >= PENDING_LIMIT))
+ {
+ int[] updateCounts = ps.executeBatch();
+ for (int i = 0; i < updateCounts.length; ++i) {
+ if (updateCounts[i] > 0) {
+ count += updateCounts[i];
+ }
+ }
+ }
+
+ return count;
+ }
+
+ String insertSql(Table table) {
+ StringBuilder sb = new StringBuilder("INSERT INTO ");
+ sb.append(table.getName())
+ .append(" VALUES (");
+
+ for (int i = 0; i < table.getNumColumns(); ++i) {
+ if (i > 0) {
+ sb.append(",");
+ }
+ sb.append("?");
+ }
+ sb.append(")");
+
+ return sb.toString();
+ }
+
protected String selectSql(Column[] columns, Table[] tables, Condition[] conditions)
{
StringBuilder sb = new StringBuilder("SELECT ");