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.BugCategory;
21 import net.jaekl.cfb.xml.messages.BugPattern;
22 import net.jaekl.cfb.xml.messages.MessageCollection;
24 public class DbStore {
27 MessageCollection m_msgColl;
29 public DbStore(Connection con, DbDriver driver, MessageCollection msgColl) {
35 public Analysis getPrior(Analysis analysis) throws SQLException, TypeMismatchException, StoreException {
36 if (null == analysis) {
39 Long priorId = getPriorId(analysis);
40 if (null == priorId) {
44 return getAnalysis(priorId);
47 public boolean put(Analysis analysis) throws SQLException, TypeMismatchException, StoreException {
48 if (null == analysis) {
52 // ----------------------------------
53 // Add a run record for this analysis
55 long runId = m_driver.nextVal(m_con, CfbSchema.RUN_SEQ);
59 analysis.getProjectName(),
60 analysis.getBuildNumber(),
65 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
70 // -------------------------------------
71 // Add a found record for each bug found
73 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
74 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
77 for (BugInstance bug : bugs)
79 Long foundId = Long.valueOf(m_driver.nextVal(m_con, CfbSchema.FOUND_SEQ));
80 Long bugId = Long.valueOf(m_msgColl.getPattern(bug.getType()).getId());
81 Long categoryId = Long.valueOf(m_msgColl.getCategory(bug.getCategory()).getId());
82 List<Location> locs = bug.getLocations();
83 Location firstLoc = (locs.size() > 0) ? locs.get(0) : null;
84 Location secondLoc = (locs.size() > 1) ? locs.get(1) : null;
85 Location thirdLoc = (locs.size() > 2) ? locs.get(2) : null;
87 if (BugPattern.UNKNOWN.getId() == bugId) {
88 throw new StoreException(StoreException.Type.UNKNOWN_PATTERN, ""+bug.getType());
90 if (BugCategory.UNKNOWN.getId() == categoryId) {
91 throw new StoreException(StoreException.Type.UNKNOWN_CATEGORY, ""+bug.getCategory());
94 values[row][0] = foundId;
95 values[row][1] = runId;
96 values[row][2] = bugId;
97 values[row][3] = categoryId;
98 values[row][4] = getLocId(firstLoc);
99 values[row][5] = getLocId(secondLoc);
100 values[row][6] = getLocId(thirdLoc);
101 values[row][7] = getVarId(bug);
105 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
106 return (bugs.size() == count);
109 String getBugType(Long bugPatternId) throws SQLException, TypeMismatchException
111 Column[] columns = { CfbSchema.TYPE };
112 Table[] tables = { CfbSchema.BUGS };
113 Condition[] conditions = { new Condition(CfbSchema.BUGID, bugPatternId, Operation.EQUAL) };
114 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
115 String type = row.getString(0);
119 String getCategoryName(Long categoryId) throws SQLException, TypeMismatchException
121 Column[] columns = { CfbSchema.CATEGORY };
122 Table[] tables = { CfbSchema.CATEGORIES };
123 Condition[] conditions = { new Condition(CfbSchema.CATEGORYID, categoryId, Operation.EQUAL) };
124 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
125 String name = row.getString(0);
130 Location getLoc(Long locId) throws TypeMismatchException, StoreException
136 Column[] columns = { CfbSchema.CLASSNAME, CfbSchema.METHODNAME, CfbSchema.METHODROLE, CfbSchema.STARTLINE, CfbSchema.ENDLINE };
137 Table[] tables = { CfbSchema.LOCATIONS };
138 Condition[] conditions = { new Condition(CfbSchema.LOCID, locId, Operation.EQUAL) };
141 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
143 String className = row.getString(0);
144 String methodName = row.getString(1);
145 String methodRole = row.getString(2);
146 Integer startLine = row.getInt(3);
147 Integer endLine = row.getInt(4);
149 Location loc = new Location(locId, className, methodName, methodRole, startLine, endLine);
152 catch (SQLException exc) {
153 throw new StoreException(exc, StoreException.Type.INVALID_LOC_ID, ""+locId);
157 Long getLocId(Location loc) throws SQLException, TypeMismatchException
162 Long locId = findLocId(loc);
167 return storeLoc(loc);
170 Long findLocId(Location loc) throws SQLException, TypeMismatchException
172 Column[] columns = { CfbSchema.LOCID };
173 Table[] tables = { CfbSchema.LOCATIONS };
175 Condition[] conditions = {
176 new Condition( CfbSchema.CLASSNAME, loc.getClassName(), Operation.EQUAL ),
177 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
178 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
179 new Condition( CfbSchema.STARTLINE, loc.getStart(), Operation.EQUAL ),
180 new Condition( CfbSchema.ENDLINE, loc.getEnd(), Operation.EQUAL )
182 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
183 if (rows.size() > 0) {
184 assert(1 == rows.size()); // should only have one match
186 return rows.get(0).getLong(0);
189 return null; // not found
192 Long storeLoc(Location loc) throws SQLException
194 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
196 Object[][] values = { {
201 Long.valueOf(loc.getStart()),
202 Long.valueOf(loc.getEnd())
204 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
209 return Long.valueOf(locId);
212 Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
218 List<LocalVariable> vars = bug.getVariables();
219 if ((null == vars) || (0 == vars.size())) {
223 return getVarId(vars.get(0));
226 LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException
232 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
233 Table[] tables = { CfbSchema.VARIABLES };
234 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
236 List<Row> result = m_driver.select(m_con, columns, tables, conditions);
237 if (result.size() < 1) {
238 throw new SQLException("No variable found for ID " + varId);
240 if (result.size() > 1) {
241 throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
244 String varName = result.get(0).getString(0);
245 String varRole = result.get(0).getString(1);
247 return new LocalVariable(varId, varName, varRole);
250 Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
256 Long result = findVarId(var);
258 if (null != result) {
262 return storeVar(var);
265 Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
267 Column[] columns = { CfbSchema.VARID_PK };
268 Table[] tables = { CfbSchema.VARIABLES };
270 Condition[] conditions = {
271 new Condition( CfbSchema.NAME, var.getName(), Operation.EQUAL ),
272 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
274 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
275 if (rows.size() > 0) {
276 assert(1 == rows.size()); // should only have one match
278 return rows.get(0).getLong(0);
281 return null; // not found
284 Long storeVar(LocalVariable var) throws SQLException
286 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
288 Object[][] values = { {
293 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
298 return Long.valueOf(varId);
301 Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
303 Column[] columns = { CfbSchema.RUNID };
304 Table[] tables = { CfbSchema.RUNS };
305 Condition[] conditions = {
306 new Condition( CfbSchema.PROJNAME, analysis.getProjectName(), Operation.EQUAL ),
307 new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN )
309 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
312 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
313 if (rows.size() < 1) {
316 return rows.get(0).getLong(0);
319 Analysis getAnalysis(Long analysisId) throws SQLException, TypeMismatchException, StoreException
321 Column[] columns = { CfbSchema.PROJNAME, CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
322 Table[] tables = { CfbSchema.RUNS };
323 Condition[] conditions = { new Condition( CfbSchema.RUNID, analysisId, Operation.EQUAL ) };
325 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
326 if (rows.size() < 1) {
330 Row row = rows.get(0);
332 String projName = row.getString(0);
333 String version = row.getString(1);
334 java.util.Date start= row.getDate(2);
335 java.util.Date end = row.getDate(3);
337 Analysis prior = new Analysis(projName, version);
338 prior.setId(analysisId.longValue());
339 prior.setStart(start);
342 prior.setBugCollection(getBugCollection(analysisId));
347 BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException, StoreException
352 CfbSchema.CATEGORYID,
353 CfbSchema.FIRSTLOCID,
354 CfbSchema.SECONDLOCID,
355 CfbSchema.THIRDLOCID,
361 Condition[] conditions = {
362 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
365 BugCollection coll = new BugCollection();
367 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
369 for (Row row : rows) {
370 // long foundId = row.getLong(0);
371 Long bugId = row.getLong(1);
372 Long categoryId = row.getLong(2);
373 Long firstLocId = row.getLong(3);
374 Long secondLocId = row.getLong(4);
375 Long thirdLocId = row.getLong(5);
376 Long varId = row.getLong(6);
378 String bugType = getBugType(bugId);
379 String category = getCategoryName(categoryId);
380 Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
381 LocalVariable[] vars = { getVar(varId) };
384 BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);