Restructure database code.
authorChris Jaekl <chris@ringo.jaekl.net>
Thu, 24 Sep 2015 13:06:49 +0000 (22:06 +0900)
committerChris Jaekl <chris@ringo.jaekl.net>
Thu, 24 Sep 2015 13:06:49 +0000 (22:06 +0900)
prod/net/jaekl/cfb/CFB.java
prod/net/jaekl/cfb/db/CfbSchema.java
prod/net/jaekl/cfb/db/Schema.java
prod/net/jaekl/cfb/db/driver/DbDriver.java
prod/net/jaekl/cfb/xml/messages/MessageCollection.java

index 28d2b1c698dc437113d58e1899596f4882fc32b6..f229ce1d7eae767674bfdb268ec9f377a55c4767 100644 (file)
@@ -152,19 +152,21 @@ public class CFB {
                if ( ! parseArgs(pw, args) ) {
                        return;
                }
+
+               File findBugsDir = getFindBugsDir();
+               File workDir = new File(".");
+               MessageMap messageMap = new MessageMap();
+               messageMap.load(findBugsDir, Locale.getDefault(Category.DISPLAY));
                
                try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) {
-                       m_schema.ensureDbInitialized(con);                      
+                       m_schema.setMessageMap(messageMap);
+                       m_schema.ensureDbInitialized(con);      
                }
                catch (SQLException exc) {
                        reportUnableToConnect(pw, exc);
                        return;
                }
                
-               File findBugsDir = getFindBugsDir();
-               File workDir = new File(".");
-               MessageMap messageMap = new MessageMap();
-               messageMap.load(findBugsDir, Locale.getDefault(Category.DISPLAY));
                Analyzer analyzer = new Analyzer(messageMap);
                Analysis analysis = analyzer.analyze(pw, workDir, m_fbp, m_buildNum);
                if (null == analysis) {
index e214b1bc59172dda99363b7b4865266dce20ec74..1b989ff5e3ba6a91c372d06dd32e29b86715d9ff 100644 (file)
@@ -4,59 +4,119 @@ package net.jaekl.cfb.db;
 
 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;
+       }
 }
index f802b58ca3cf71f89f7b5ef6c8b0f57c95382c66..4937fae153eae94dacf8c051c8c49d07b7775892 100644 (file)
@@ -40,6 +40,17 @@ public class Schema {
                        return false;
                }
                
+               if (!postCreationInit(con)) {
+                       
+               }
+               
+               return true;
+       }
+       
+       boolean postCreationInit(Connection con) throws SQLException {
+               // no-op
+               // Override this in a derived class if you need to initialize something 
+               // after the tables and sequences are created.
                return true;
        }
        
@@ -98,14 +109,20 @@ public class Schema {
        //   { table_name },
        //   { column_name, type, width (-1 for default), null/not_null }
        // }
-       void addTables(Object[][][] tables) 
+       void addTables(Table[] tables) 
        {
-               for (Object[][] table : tables) {
-                       addTable(Table.construct(table));
+               for (Table table : tables) {
+                       addTable(table);
                }
        }
        
        void addSequence(Sequence seq) {
                m_sequences.add(seq);
        }
+       
+       void addSequences(Sequence[] sequences) {
+               for (Sequence sequence : sequences) {
+                       addSequence(sequence);
+               }
+       }
 }
index 525ca7049d3444545a717a9788e51595b29697f3..ac9f8ccdad2030150d25d0fe06cd15078c8d7fb4 100644 (file)
@@ -19,6 +19,8 @@ import net.jaekl.cfb.db.Sequence;
 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() {
                
        }
@@ -83,6 +85,74 @@ public abstract class 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 ");
index cf16e237ddd47ad4a916996737ff492760bbd9f0..ba4b97ca7b45797b214b6959987e14bdf2bd803f 100644 (file)
@@ -1,5 +1,6 @@
 package net.jaekl.cfb.xml.messages;
 
+import java.util.Collection;
 import java.util.HashMap;
 
 import net.jaekl.qd.xml.ParseResult;
@@ -20,6 +21,12 @@ public class MessageCollection extends ParseResult {
                m_categories = new HashMap<String, BugCategory>();
                m_patterns   = new HashMap<String, BugPattern>();
        }
+       
+       public Collection<BugCategory> getCategories() { return m_categories.values(); }
+       public BugCategory getCategory(String category) { return m_categories.get(category); }
+       
+       public Collection<BugPattern> getPatterns() { return m_patterns.values(); }
+       public BugPattern getPattern(String type) { return m_patterns.get(type); }
 
        @Override
        public void endContents(String uri, String localName, String qName, String chars)