1 package net.jaekl.cfb.store;
3 import java.sql.Connection;
4 import java.sql.SQLException;
7 import net.jaekl.cfb.analyze.Analysis;
8 import net.jaekl.cfb.db.CfbSchema;
9 import net.jaekl.cfb.db.Column;
10 import net.jaekl.cfb.db.Condition;
11 import net.jaekl.cfb.db.Operation;
12 import net.jaekl.cfb.db.Row;
13 import net.jaekl.cfb.db.Sort;
14 import net.jaekl.cfb.db.Table;
15 import net.jaekl.cfb.db.TypeMismatchException;
16 import net.jaekl.cfb.db.driver.DbDriver;
17 import net.jaekl.cfb.xml.BugCollection;
18 import net.jaekl.cfb.xml.BugInstance;
19 import net.jaekl.cfb.xml.LocalVariable;
20 import net.jaekl.cfb.xml.messages.MessageCollection;
22 public class DbStore {
25 MessageCollection m_msgColl;
27 public DbStore(Connection con, DbDriver driver, MessageCollection msgColl) {
33 public Analysis getPrior(Analysis analysis) throws SQLException, TypeMismatchException {
34 if (null == analysis) {
37 Long priorId = getPriorId(analysis);
38 if (null == priorId) {
42 return getAnalysis(priorId);
45 public boolean put(Analysis analysis) throws SQLException, TypeMismatchException {
46 if (null == analysis) {
50 // ----------------------------------
51 // Add a run record for this analysis
53 long runId = m_driver.nextVal(m_con, CfbSchema.RUN_SEQ);
57 analysis.getBuildNumber(),
62 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
67 // -------------------------------------
68 // Add a found record for each bug found
70 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
71 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
74 for (BugInstance bug : bugs)
76 Long foundId = Long.valueOf(m_driver.nextVal(m_con, CfbSchema.FOUND_SEQ));
77 Long bugId = Long.valueOf(m_msgColl.getPattern(bug.getType()).getId());
78 Long categoryId = Long.valueOf(m_msgColl.getCategory(bug.getCategory()).getId());
79 List<Location> locs = bug.getLocations();
80 Location firstLoc = (locs.size() > 0) ? locs.get(0) : null;
81 Location secondLoc = (locs.size() > 1) ? locs.get(1) : null;
82 Location thirdLoc = (locs.size() > 2) ? locs.get(2) : null;
84 values[row][0] = foundId;
85 values[row][1] = runId;
86 values[row][2] = bugId;
87 values[row][3] = categoryId;
88 values[row][4] = getLocId(firstLoc);
89 values[row][5] = getLocId(secondLoc);
90 values[row][6] = getLocId(thirdLoc);
91 values[row][7] = getVarId(bug);
95 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
96 return (bugs.size() == count);
99 String getBugType(Long bugPatternId) throws SQLException, TypeMismatchException
101 Column[] columns = { CfbSchema.TYPE };
102 Table[] tables = { CfbSchema.BUGS };
103 Condition[] conditions = { new Condition(CfbSchema.BUGID, bugPatternId, Operation.EQUAL) };
104 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
105 String type = row.getString(0);
109 String getCategoryName(Long categoryId) throws SQLException, TypeMismatchException
111 Column[] columns = { CfbSchema.CATEGORY };
112 Table[] tables = { CfbSchema.CATEGORIES };
113 Condition[] conditions = { new Condition(CfbSchema.CATEGORYID, categoryId, Operation.EQUAL) };
114 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
115 String name = row.getString(0);
120 Location getLoc(Long locId) throws SQLException, TypeMismatchException
122 Column[] columns = { CfbSchema.CLASSNAME, CfbSchema.METHODNAME, CfbSchema.METHODROLE, CfbSchema.STARTLINE, CfbSchema.ENDLINE };
123 Table[] tables = { CfbSchema.LOCATIONS };
124 Condition[] conditions = { new Condition(CfbSchema.LOCID, locId, Operation.EQUAL) };
126 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
128 String className = row.getString(0);
129 String methodName = row.getString(1);
130 String methodRole = row.getString(2);
131 long startLine = row.getLong(3);
132 long endLine = row.getLong(4);
134 Location loc = new Location(locId, className, methodName, methodRole, startLine, endLine);
138 Long getLocId(Location loc) throws SQLException, TypeMismatchException
143 Long locId = findLocId(loc);
148 return storeLoc(loc);
151 Long findLocId(Location loc) throws SQLException, TypeMismatchException
153 Column[] columns = { CfbSchema.LOCID };
154 Table[] tables = { CfbSchema.LOCATIONS };
156 Condition[] conditions = {
157 new Condition( CfbSchema.CLASSNAME, loc.getClassName(), Operation.EQUAL ),
158 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
159 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
160 new Condition( CfbSchema.STARTLINE, loc.getStart(), Operation.EQUAL ),
161 new Condition( CfbSchema.ENDLINE, loc.getEnd(), Operation.EQUAL )
163 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
164 if (rows.size() > 0) {
165 assert(1 == rows.size()); // should only have one match
167 return rows.get(0).getLong(0);
170 return null; // not found
173 Long storeLoc(Location loc) throws SQLException
175 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
177 Object[][] values = { {
182 Long.valueOf(loc.getStart()),
183 Long.valueOf(loc.getEnd())
185 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
190 return Long.valueOf(locId);
193 Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
199 List<LocalVariable> vars = bug.getVariables();
200 if ((null == vars) || (0 == vars.size())) {
204 return getVarId(vars.get(0));
207 LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException
209 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
210 Table[] tables = { CfbSchema.VARIABLES };
211 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
213 List<Row> result = m_driver.select(m_con, columns, tables, conditions);
214 if (result.size() < 1) {
215 throw new SQLException("No variable found for ID " + varId);
217 if (result.size() > 1) {
218 throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
221 String varName = result.get(0).getString(0);
222 String varRole = result.get(0).getString(1);
224 return new LocalVariable(varId, varName, varRole);
227 Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
233 Long result = findVarId(var);
235 if (null != result) {
239 return storeVar(var);
242 Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
244 Column[] columns = { CfbSchema.VARID_PK };
245 Table[] tables = { CfbSchema.VARIABLES };
247 Condition[] conditions = {
248 new Condition( CfbSchema.NAME, var.getName(), Operation.EQUAL ),
249 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
251 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
252 if (rows.size() > 0) {
253 assert(1 == rows.size()); // should only have one match
255 return rows.get(0).getLong(0);
258 return null; // not found
261 Long storeVar(LocalVariable var) throws SQLException
263 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
265 Object[][] values = { {
270 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
275 return Long.valueOf(varId);
278 Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
280 Column[] columns = { CfbSchema.RUNID };
281 Table[] tables = { CfbSchema.RUNS };
282 Condition[] conditions = { new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN ) };
283 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
286 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
287 if (rows.size() < 1) {
290 return rows.get(0).getLong(0);
293 Analysis getAnalysis(Long priorId) throws SQLException, TypeMismatchException
295 Column[] columns = { CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
296 Table[] tables = { CfbSchema.RUNS };
297 Condition[] conditions = { new Condition( CfbSchema.RUNID, priorId, Operation.EQUAL ) };
299 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
300 if (rows.size() < 1) {
304 Row row = rows.get(0);
306 String version = row.getString(0);
307 java.util.Date start= row.getDate(1);
308 java.util.Date end = row.getDate(2);
310 Analysis prior = new Analysis(version);
311 prior.setId(priorId.longValue());
312 prior.setStart(start);
315 prior.setBugCollection(getBugCollection(priorId));
320 BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException
325 CfbSchema.CATEGORYID,
326 CfbSchema.FIRSTLOCID,
327 CfbSchema.SECONDLOCID,
328 CfbSchema.THIRDLOCID,
334 Condition[] conditions = {
335 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
338 BugCollection coll = new BugCollection();
340 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
342 for (Row row : rows) {
343 // long foundId = row.getLong(0);
344 long bugId = row.getLong(1);
345 long categoryId = row.getLong(2);
346 long firstLocId = row.getLong(3);
347 long secondLocId = row.getLong(4);
348 long thirdLocId = row.getLong(5);
349 long varId = row.getLong(6);
351 String bugType = getBugType(bugId);
352 String category = getCategoryName(categoryId);
353 Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
354 LocalVariable[] vars = { getVar(Long.valueOf(varId)) };
357 BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);
358 coll.getBugs().add(bug);