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 assert (null != analysis.getProjectName());
54 // ----------------------------------
55 // Add a run record for this analysis
57 long runId = m_driver.nextVal(m_con, CfbSchema.RUN_SEQ);
61 analysis.getProjectName(),
62 analysis.getBuildNumber(),
67 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
72 // -------------------------------------
73 // Add a found record for each bug found
75 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
76 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
79 for (BugInstance bug : bugs)
81 Long foundId = Long.valueOf(m_driver.nextVal(m_con, CfbSchema.FOUND_SEQ));
82 Long bugId = Long.valueOf(m_msgColl.getPattern(bug.getType()).getId());
83 Long categoryId = Long.valueOf(m_msgColl.getCategory(bug.getCategory()).getId());
84 List<Location> locs = bug.getLocations();
85 Location firstLoc = (locs.size() > 0) ? locs.get(0) : null;
86 Location secondLoc = (locs.size() > 1) ? locs.get(1) : null;
87 Location thirdLoc = (locs.size() > 2) ? locs.get(2) : null;
89 if (BugPattern.UNKNOWN.getId() == bugId) {
90 throw new StoreException(StoreException.Type.UNKNOWN_PATTERN, ""+bug.getType());
92 if (BugCategory.UNKNOWN.getId() == categoryId) {
93 throw new StoreException(StoreException.Type.UNKNOWN_CATEGORY, ""+bug.getCategory());
96 values[row][0] = foundId;
97 values[row][1] = runId;
98 values[row][2] = bugId;
99 values[row][3] = categoryId;
100 values[row][4] = getLocId(firstLoc);
101 values[row][5] = getLocId(secondLoc);
102 values[row][6] = getLocId(thirdLoc);
103 values[row][7] = getVarId(bug);
107 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
108 return (bugs.size() == count);
111 String getBugType(Long bugPatternId) throws SQLException, TypeMismatchException
113 Column[] columns = { CfbSchema.TYPE };
114 Table[] tables = { CfbSchema.BUGS };
115 Condition[] conditions = { new Condition(CfbSchema.BUGID, bugPatternId, Operation.EQUAL) };
116 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
117 String type = row.getString(0);
121 String getCategoryName(Long categoryId) throws SQLException, TypeMismatchException
123 Column[] columns = { CfbSchema.CATEGORY };
124 Table[] tables = { CfbSchema.CATEGORIES };
125 Condition[] conditions = { new Condition(CfbSchema.CATEGORYID, categoryId, Operation.EQUAL) };
126 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
127 String name = row.getString(0);
132 Location getLoc(Long locId) throws TypeMismatchException, StoreException
138 Column[] columns = { CfbSchema.CLASSNAME, CfbSchema.METHODNAME, CfbSchema.METHODROLE, CfbSchema.STARTLINE, CfbSchema.ENDLINE };
139 Table[] tables = { CfbSchema.LOCATIONS };
140 Condition[] conditions = { new Condition(CfbSchema.LOCID, locId, Operation.EQUAL) };
143 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
145 String className = row.getString(0);
146 String methodName = row.getString(1);
147 String methodRole = row.getString(2);
148 Integer startLine = row.getInt(3);
149 Integer endLine = row.getInt(4);
151 Location loc = new Location(locId, className, methodName, methodRole, startLine, endLine);
154 catch (SQLException exc) {
155 throw new StoreException(exc, StoreException.Type.INVALID_LOC_ID, ""+locId);
159 Long getLocId(Location loc) throws SQLException, TypeMismatchException
164 Long locId = findLocId(loc);
169 return storeLoc(loc);
172 Long findLocId(Location loc) throws SQLException, TypeMismatchException
174 Column[] columns = { CfbSchema.LOCID };
175 Table[] tables = { CfbSchema.LOCATIONS };
177 Condition[] conditions = {
178 new Condition( CfbSchema.CLASSNAME, loc.getClassName(), Operation.EQUAL ),
179 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
180 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
181 new Condition( CfbSchema.STARTLINE, loc.getStart(), Operation.EQUAL ),
182 new Condition( CfbSchema.ENDLINE, loc.getEnd(), Operation.EQUAL )
184 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
185 if (rows.size() > 0) {
186 assert(1 == rows.size()); // should only have one match
188 return rows.get(0).getLong(0);
191 return null; // not found
194 Long storeLoc(Location loc) throws SQLException
196 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
198 Object[][] values = { {
203 Long.valueOf(loc.getStart()),
204 Long.valueOf(loc.getEnd())
206 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
211 return Long.valueOf(locId);
214 Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
220 List<LocalVariable> vars = bug.getVariables();
221 if ((null == vars) || (0 == vars.size())) {
225 return getVarId(vars.get(0));
228 LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException, StoreException
234 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
235 Table[] tables = { CfbSchema.VARIABLES };
236 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
238 List<Row> result = m_driver.select(m_con, columns, tables, conditions);
239 if (result.size() < 1) {
240 throw new StoreException(StoreException.Type.INVALID_VAR_ID, ""+varId);
242 if (result.size() > 1) {
243 throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
246 String varName = result.get(0).getString(0);
247 String varRole = result.get(0).getString(1);
249 return new LocalVariable(varId, varName, varRole);
252 Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
258 Long result = findVarId(var);
260 if (null != result) {
264 return storeVar(var);
267 Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
269 Column[] columns = { CfbSchema.VARID_PK };
270 Table[] tables = { CfbSchema.VARIABLES };
272 Condition[] conditions = {
273 new Condition( CfbSchema.NAME, var.getName(), Operation.EQUAL ),
274 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
276 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
277 if (rows.size() > 0) {
278 assert(1 == rows.size()); // should only have one match
280 return rows.get(0).getLong(0);
283 return null; // not found
286 Long storeVar(LocalVariable var) throws SQLException
288 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
290 Object[][] values = { {
295 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
300 return Long.valueOf(varId);
303 Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
305 Column[] columns = { CfbSchema.RUNID };
306 Table[] tables = { CfbSchema.RUNS };
307 Condition[] conditions = {
308 new Condition( CfbSchema.PROJNAME, analysis.getProjectName(), Operation.EQUAL ),
309 new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN )
311 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
314 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
315 if (rows.size() < 1) {
318 return rows.get(0).getLong(0);
321 Analysis getAnalysis(Long analysisId) throws SQLException, TypeMismatchException, StoreException
323 Column[] columns = { CfbSchema.PROJNAME, CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
324 Table[] tables = { CfbSchema.RUNS };
325 Condition[] conditions = { new Condition( CfbSchema.RUNID, analysisId, Operation.EQUAL ) };
327 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
328 if (rows.size() < 1) {
332 Row row = rows.get(0);
334 String projName = row.getString(0);
335 String version = row.getString(1);
336 java.util.Date start= row.getDate(2);
337 java.util.Date end = row.getDate(3);
339 Analysis prior = new Analysis(projName, version);
340 prior.setId(analysisId.longValue());
341 prior.setStart(start);
344 prior.setBugCollection(getBugCollection(analysisId));
349 BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException, StoreException
354 CfbSchema.CATEGORYID,
355 CfbSchema.FIRSTLOCID,
356 CfbSchema.SECONDLOCID,
357 CfbSchema.THIRDLOCID,
363 Condition[] conditions = {
364 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
367 BugCollection coll = new BugCollection();
369 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
371 for (Row row : rows) {
372 // long foundId = row.getLong(0);
373 Long bugId = row.getLong(1);
374 Long categoryId = row.getLong(2);
375 Long firstLocId = row.getLong(3);
376 Long secondLocId = row.getLong(4);
377 Long thirdLocId = row.getLong(5);
378 Long varId = row.getLong(6);
380 String bugType = getBugType(bugId);
381 String category = getCategoryName(categoryId);
382 Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
383 LocalVariable[] vars = { getVar(varId) };
386 BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);