From 58107a0cbb49652e7772ce80fb73d2c027590eb1 Mon Sep 17 00:00:00 2001 From: Chris Jaekl Date: Fri, 25 Sep 2015 22:01:59 +0900 Subject: [PATCH] A few changes: (1) improve sequence support so that sequences can have their next value fetched from the DB (2) add option ("-r") to remove (drop) the schema and all associated data from the db (3) populate the bugs and categories tables when creating the database --- prod/cfb.properties | 2 +- prod/net/jaekl/cfb/CFB.java | 9 +++ prod/net/jaekl/cfb/analyze/MessageMap.java | 6 +- prod/net/jaekl/cfb/db/CfbSchema.java | 48 ++++++++++++++- prod/net/jaekl/cfb/db/Schema.java | 29 ++++++++- prod/net/jaekl/cfb/db/driver/DbDriver.java | 59 ++++++++++++++++++- .../jaekl/cfb/db/driver/PostgresqlDriver.java | 8 +++ .../jaekl/cfb/xml/messages/BugCategory.java | 4 +- .../jaekl/cfb/xml/messages/BugPattern.java | 4 +- 9 files changed, 158 insertions(+), 11 deletions(-) diff --git a/prod/cfb.properties b/prod/cfb.properties index 78c3352..5027818 100644 --- a/prod/cfb.properties +++ b/prod/cfb.properties @@ -1,5 +1,5 @@ analysis.failed=Attempt to analyze source code failed. Will now stop. -cannot.connect.to.db=Unable to connect to database {2} on {0}:{1} as user {3}. +cannot.connect.to.db=Unable to connect to, or to initialize, database {2} on {0}:{1} as user {3}. cannot.exec=Got result code {1} when attempting to execute command-line: {0} stderr.was=-----8<------ Error (stderr) output was: ------8<----- stdout.was=-----8<----- Console (stdout) output was: -----8<----- diff --git a/prod/net/jaekl/cfb/CFB.java b/prod/net/jaekl/cfb/CFB.java index f229ce1..924d331 100644 --- a/prod/net/jaekl/cfb/CFB.java +++ b/prod/net/jaekl/cfb/CFB.java @@ -47,6 +47,7 @@ public class CFB { String m_user; // db user String m_pass; // db password String m_buildNum; // build number (version) + boolean m_removeSchema; // purge DB schema CFB(Locale locale) { m_driver = new PostgresqlDriver(); @@ -62,6 +63,7 @@ public class CFB { m_pass = ""; m_user = "user"; m_buildNum = null; + m_removeSchema = false; } Options createOptions() { @@ -72,6 +74,7 @@ public class CFB { opt.addOption("h", "host", true, "DB hostname"); opt.addOption("n", "number", true, "Build number (version)"); opt.addOption("p", "pass", true, "DB password"); + opt.addOption("r", "remove", false, "Remove database schema (drop all data)"); opt.addOption("t", "port", true, "DB port"); opt.addOption("u", "user", true, "DB username"); @@ -98,6 +101,7 @@ public class CFB { if (line.hasOption("p")) { m_pass = line.getOptionValue("p"); } + m_removeSchema = line.hasOption("r"); if (line.hasOption("t")) { m_port = Integer.parseInt(line.getOptionValue("t")); } @@ -160,6 +164,11 @@ public class CFB { try (Connection con = m_driver.connect(m_host, m_port, m_dbName, m_user, m_pass)) { m_schema.setMessageMap(messageMap); + + if (m_removeSchema) { + m_schema.purge(con); + return; + } m_schema.ensureDbInitialized(con); } catch (SQLException exc) { diff --git a/prod/net/jaekl/cfb/analyze/MessageMap.java b/prod/net/jaekl/cfb/analyze/MessageMap.java index ac5288f..9718003 100644 --- a/prod/net/jaekl/cfb/analyze/MessageMap.java +++ b/prod/net/jaekl/cfb/analyze/MessageMap.java @@ -36,9 +36,11 @@ public class MessageMap { String langName = locale.getLanguage(); - File msgXml = new File(findBugsDir.getAbsolutePath() + File.separator + MESSAGES + "_" + langName + "." + XML); + String basePath = findBugsDir.getAbsolutePath() + File.separator + "etc" + File.separator; + + File msgXml = new File(basePath + MESSAGES + "_" + langName + "." + XML); if (! msgXml.canRead()) { - msgXml = new File(findBugsDir.getAbsolutePath() + File.separator + MESSAGES + "." + XML); + msgXml = new File(basePath + MESSAGES + "." + XML); } if (! msgXml.canRead()) { diff --git a/prod/net/jaekl/cfb/db/CfbSchema.java b/prod/net/jaekl/cfb/db/CfbSchema.java index 1b989ff..d80be57 100644 --- a/prod/net/jaekl/cfb/db/CfbSchema.java +++ b/prod/net/jaekl/cfb/db/CfbSchema.java @@ -7,9 +7,12 @@ import static net.jaekl.cfb.db.Column.Type.*; import java.sql.Connection; import java.sql.SQLException; +import java.util.Collection; import net.jaekl.cfb.analyze.MessageMap; import net.jaekl.cfb.db.driver.DbDriver; +import net.jaekl.cfb.xml.messages.BugCategory; +import net.jaekl.cfb.xml.messages.BugPattern; public class CfbSchema extends Schema { @@ -115,8 +118,51 @@ public class CfbSchema extends Schema { boolean postCreationInit(Connection con) throws SQLException { assert(null != m_msgMap); - + if (! insertCategories(con)) { + return false; + } + if (! insertPatterns(con)) { + return false; + } return true; } + + boolean insertCategories(Connection con) throws SQLException { + Collection categories = m_msgMap.getColl().getCategories(); + + Object[][] values = new Object[categories.size()][CATEGORIES.getNumColumns()]; + + int row = 0; + for (BugCategory cat : categories) { + long categoryId = m_driver.nextVal(con, CATEGORY_SEQ); + + values[row][0] = Long.valueOf(categoryId); + values[row][1] = cat.getCategory(); + row++; + } + + int count = m_driver.insert(con, CATEGORIES, values); + + return (categories.size() == count); + } + + boolean insertPatterns(Connection con) throws SQLException { + Collection patterns = m_msgMap.getColl().getPatterns(); + + Object[][] values = new Object[patterns.size()][BUGS.getNumColumns()]; + + int row = 0; + for (BugPattern bug : patterns) { + long bugId = m_driver.nextVal(con, BUG_SEQ); + + values[row][0] = Long.valueOf(bugId); + values[row][1] = bug.getType(); + row++; + } + + int count = m_driver.insert(con, BUGS, values); + + return (patterns.size() == count); + } } diff --git a/prod/net/jaekl/cfb/db/Schema.java b/prod/net/jaekl/cfb/db/Schema.java index 4937fae..898687e 100644 --- a/prod/net/jaekl/cfb/db/Schema.java +++ b/prod/net/jaekl/cfb/db/Schema.java @@ -41,12 +41,17 @@ public class Schema { } if (!postCreationInit(con)) { - + return false; } return true; } + public void purge(Connection con) throws SQLException { + dropAllTables(con); + dropAllSequences(con); + } + boolean postCreationInit(Connection con) throws SQLException { // no-op // Override this in a derived class if you need to initialize something @@ -90,6 +95,17 @@ public class Schema { return true; } + void dropAllTables(Connection con) { + for (Table table : m_tables) { + try { + m_driver.dropTable(con, table); + } + catch (SQLException e) { + e.printStackTrace(); + } + } + } + boolean createAllSequences(Connection con) throws SQLException { for (Sequence seq : m_sequences) { if (!m_driver.createSequence(con, seq)) { @@ -99,6 +115,17 @@ public class Schema { return true; } + void dropAllSequences(Connection con) { + for (Sequence seq : m_sequences) { + try { + m_driver.dropSequence(con, seq); + } + catch (SQLException e) { + e.printStackTrace(); + } + } + } + void addTable(Table table) { m_tables.add(table); } diff --git a/prod/net/jaekl/cfb/db/driver/DbDriver.java b/prod/net/jaekl/cfb/db/driver/DbDriver.java index ac9f8cc..ecfe2a7 100644 --- a/prod/net/jaekl/cfb/db/driver/DbDriver.java +++ b/prod/net/jaekl/cfb/db/driver/DbDriver.java @@ -30,7 +30,8 @@ public abstract class DbDriver { public abstract Connection connect(String host, int port, String dbName, String user, String pass) throws SQLException; - public boolean createTable(Connection con, Table table) throws SQLException { + public boolean createTable(Connection con, Table table) throws SQLException + { String sql = createTableSql(table); try (PreparedStatement ps = con.prepareStatement(sql)) { ps.executeUpdate(); @@ -42,6 +43,17 @@ public abstract class DbDriver { return true; } + public void dropTable(Connection con, Table table) throws SQLException + { + String sql = dropTableSql(table); + try (PreparedStatement ps = con.prepareStatement(sql)) { + ps.executeUpdate(); + } + catch (SQLException exc) { + throw new SQLException("Failed to drop table: " + sql, exc); + } + } + public boolean createSequence(Connection con, Sequence seq) throws SQLException { String sql = createSequenceSql(seq); @@ -55,6 +67,17 @@ public abstract class DbDriver { return true; } + public void dropSequence(Connection con, Sequence seq) throws SQLException + { + String sql = dropSequenceSql(seq); + try (PreparedStatement ps = con.prepareStatement(sql)) { + ps.executeUpdate(); + } + catch (SQLException exc) { + throw new SQLException("Failed to drop sequence: " + sql, exc); + } + } + public List select(Connection con, Column[] columns, Table[] tables, Condition[] conditions) throws SQLException { @@ -74,7 +97,7 @@ public abstract class DbDriver { while (rs.next()) { Object[] values = new Object[columns.length]; for (index = 0; index < columns.length; ++index) { - values[index] = rs.getObject(index); + values[index] = rs.getObject(index + 1); } Row row = new Row(columns, values); result.add(row); @@ -120,6 +143,22 @@ public abstract class DbDriver { return count; } + public long nextVal(Connection con, Sequence seq) throws SQLException + { + String sql = nextValSql(seq); + + try (PreparedStatement ps = con.prepareStatement(sql)) + { + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + return rs.getLong(1); + } + } + } + + throw new SQLException("No value returned for sequence: " + sql); + } + int checkFlushBatch(PreparedStatement ps, int pendingValues, boolean forceFlush) throws SQLException { int count = 0; @@ -247,10 +286,26 @@ public abstract class DbDriver { return sb.toString(); } + protected String dropTableSql(Table table) { + assert(null != table); + assert(null != table.getName()); + + return "DROP TABLE " + table.getName(); + } + protected String createSequenceSql(Sequence seq) { assert(null != seq); assert(null != seq.getName()); return "CREATE SEQUENCE " + seq.getName(); } + + protected String dropSequenceSql(Sequence seq) { + assert(null != seq); + assert(null != seq.getName()); + + return "DROP SEQUENCE " + seq.getName(); + } + + abstract protected String nextValSql(Sequence seq); } diff --git a/prod/net/jaekl/cfb/db/driver/PostgresqlDriver.java b/prod/net/jaekl/cfb/db/driver/PostgresqlDriver.java index a8d28f9..8e19fc4 100644 --- a/prod/net/jaekl/cfb/db/driver/PostgresqlDriver.java +++ b/prod/net/jaekl/cfb/db/driver/PostgresqlDriver.java @@ -7,6 +7,8 @@ import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; +import net.jaekl.cfb.db.Sequence; + public class PostgresqlDriver extends DbDriver { @Override @@ -26,4 +28,10 @@ public class PostgresqlDriver extends DbDriver { //props.setProperty("ssl", "true"); return DriverManager.getConnection(url, props); } + + @Override + public String nextValSql(Sequence seq) + { + return " SELECT NEXTVAL('" + seq.getName() + "') "; + } } diff --git a/prod/net/jaekl/cfb/xml/messages/BugCategory.java b/prod/net/jaekl/cfb/xml/messages/BugCategory.java index 6b5b492..9e1f539 100644 --- a/prod/net/jaekl/cfb/xml/messages/BugCategory.java +++ b/prod/net/jaekl/cfb/xml/messages/BugCategory.java @@ -21,9 +21,9 @@ public class BugCategory extends ParseResult { String m_abbrev; String m_details; - public BugCategory(String tagName, String[] internalMemberTags, Object[][] externalParserTags) + public BugCategory() { - super(tagName, internalMemberTags, externalParserTags); + super(TAG, INTERNAL, EXTERNAL); m_category = m_descr = m_abbrev = m_details = ""; } diff --git a/prod/net/jaekl/cfb/xml/messages/BugPattern.java b/prod/net/jaekl/cfb/xml/messages/BugPattern.java index 82ada92..b75733b 100644 --- a/prod/net/jaekl/cfb/xml/messages/BugPattern.java +++ b/prod/net/jaekl/cfb/xml/messages/BugPattern.java @@ -21,9 +21,9 @@ public class BugPattern extends ParseResult { String m_long; String m_details; - public BugPattern(String tagName, String[] internalMemberTags, Object[][] externalParserTags) + public BugPattern() { - super(tagName, internalMemberTags, externalParserTags); + super(TAG, INTERNAL, EXTERNAL); m_type = m_short = m_long = m_details = ""; } -- 2.39.2