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());
53 assert (null != analysis.getBuildNumber());
55 // ----------------------------------
56 // Add a run record for this analysis
58 long runId = m_driver.nextVal(m_con, CfbSchema.RUN_SEQ);
62 analysis.getProjectName(),
63 analysis.getBuildNumber(),
68 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
73 // -------------------------------------
74 // Add a found record for each bug found
76 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
77 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
80 for (BugInstance bug : bugs)
82 Long foundId = Long.valueOf(m_driver.nextVal(m_con, CfbSchema.FOUND_SEQ));
83 Long bugId = Long.valueOf(m_msgColl.getPattern(bug.getType()).getId());
84 Long categoryId = Long.valueOf(m_msgColl.getCategory(bug.getCategory()).getId());
85 List<Location> locs = bug.getLocations();
86 Location firstLoc = (locs.size() > 0) ? locs.get(0) : null;
87 Location secondLoc = (locs.size() > 1) ? locs.get(1) : null;
88 Location thirdLoc = (locs.size() > 2) ? locs.get(2) : null;
90 if (BugPattern.UNKNOWN.getId() == bugId) {
91 throw new StoreException(StoreException.Type.UNKNOWN_PATTERN, ""+bug.getType());
93 if (BugCategory.UNKNOWN.getId() == categoryId) {
94 throw new StoreException(StoreException.Type.UNKNOWN_CATEGORY, ""+bug.getCategory());
97 values[row][0] = foundId;
98 values[row][1] = runId;
99 values[row][2] = bugId;
100 values[row][3] = categoryId;
101 values[row][4] = getLocId(firstLoc);
102 values[row][5] = getLocId(secondLoc);
103 values[row][6] = getLocId(thirdLoc);
104 values[row][7] = getVarId(bug);
108 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
109 return (bugs.size() == count);
112 String getBugType(Long bugPatternId) throws SQLException, TypeMismatchException
114 Column[] columns = { CfbSchema.TYPE };
115 Table[] tables = { CfbSchema.BUGS };
116 Condition[] conditions = { new Condition(CfbSchema.BUGID, bugPatternId, Operation.EQUAL) };
117 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
118 String type = row.getString(0);
122 String getCategoryName(Long categoryId) throws SQLException, TypeMismatchException
124 Column[] columns = { CfbSchema.CATEGORY };
125 Table[] tables = { CfbSchema.CATEGORIES };
126 Condition[] conditions = { new Condition(CfbSchema.CATEGORYID, categoryId, Operation.EQUAL) };
127 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
128 String name = row.getString(0);
133 Location getLoc(Long locId) throws TypeMismatchException, StoreException
139 Column[] columns = { CfbSchema.CLASSNAME, CfbSchema.METHODNAME, CfbSchema.METHODROLE, CfbSchema.STARTLINE, CfbSchema.ENDLINE };
140 Table[] tables = { CfbSchema.LOCATIONS };
141 Condition[] conditions = { new Condition(CfbSchema.LOCID, locId, Operation.EQUAL) };
144 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
146 String className = row.getString(0);
147 String methodName = row.getString(1);
148 String methodRole = row.getString(2);
149 Integer startLine = row.getInt(3);
150 Integer endLine = row.getInt(4);
152 Location loc = new Location(locId, className, methodName, methodRole, startLine, endLine);
155 catch (SQLException exc) {
156 throw new StoreException(exc, StoreException.Type.INVALID_LOC_ID, ""+locId);
160 Long getLocId(Location loc) throws SQLException, TypeMismatchException
165 Long locId = findLocId(loc);
170 return storeLoc(loc);
173 Long findLocId(Location loc) throws SQLException, TypeMismatchException
175 Column[] columns = { CfbSchema.LOCID };
176 Table[] tables = { CfbSchema.LOCATIONS };
178 Condition[] conditions = {
179 new Condition( CfbSchema.CLASSNAME, loc.getClassName(), Operation.EQUAL ),
180 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
181 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
182 new Condition( CfbSchema.STARTLINE, loc.getStart(), Operation.EQUAL ),
183 new Condition( CfbSchema.ENDLINE, loc.getEnd(), Operation.EQUAL )
185 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
186 if (rows.size() > 0) {
187 assert(1 == rows.size()); // should only have one match
189 return rows.get(0).getLong(0);
192 return null; // not found
195 Long storeLoc(Location loc) throws SQLException
197 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
199 Object[][] values = { {
204 Long.valueOf(loc.getStart()),
205 Long.valueOf(loc.getEnd())
207 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
212 return Long.valueOf(locId);
215 Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
221 List<LocalVariable> vars = bug.getVariables();
222 if ((null == vars) || (0 == vars.size())) {
226 return getVarId(vars.get(0));
229 LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException, StoreException
235 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
236 Table[] tables = { CfbSchema.VARIABLES };
237 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
239 List<Row> result = m_driver.select(m_con, columns, tables, conditions);
240 if (result.size() < 1) {
241 throw new StoreException(StoreException.Type.INVALID_VAR_ID, ""+varId);
243 if (result.size() > 1) {
244 throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
247 String varName = result.get(0).getString(0);
248 String varRole = result.get(0).getString(1);
250 return new LocalVariable(varId, varName, varRole);
253 Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
259 Long result = findVarId(var);
261 if (null != result) {
265 return storeVar(var);
268 Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
270 Column[] columns = { CfbSchema.VARID_PK };
271 Table[] tables = { CfbSchema.VARIABLES };
273 Condition[] conditions = {
274 new Condition( CfbSchema.NAME, var.getName(), Operation.EQUAL ),
275 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
277 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
278 if (rows.size() > 0) {
279 assert(1 == rows.size()); // should only have one match
281 return rows.get(0).getLong(0);
284 return null; // not found
287 Long storeVar(LocalVariable var) throws SQLException
289 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
291 Object[][] values = { {
296 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
301 return Long.valueOf(varId);
304 Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
306 Column[] columns = { CfbSchema.RUNID };
307 Table[] tables = { CfbSchema.RUNS };
308 Condition[] conditions = {
309 new Condition( CfbSchema.PROJNAME, analysis.getProjectName(), Operation.EQUAL ),
310 new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN )
312 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
315 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
316 if (rows.size() < 1) {
319 return rows.get(0).getLong(0);
322 Analysis getAnalysis(Long analysisId) throws SQLException, TypeMismatchException, StoreException
324 Column[] columns = { CfbSchema.PROJNAME, CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
325 Table[] tables = { CfbSchema.RUNS };
326 Condition[] conditions = { new Condition( CfbSchema.RUNID, analysisId, Operation.EQUAL ) };
328 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
329 if (rows.size() < 1) {
333 Row row = rows.get(0);
335 String projName = row.getString(0);
336 String version = row.getString(1);
337 java.util.Date start= row.getDate(2);
338 java.util.Date end = row.getDate(3);
340 Analysis prior = new Analysis(projName, version);
341 prior.setId(analysisId.longValue());
342 prior.setStart(start);
345 prior.setBugCollection(getBugCollection(analysisId));
350 BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException, StoreException
355 CfbSchema.CATEGORYID,
356 CfbSchema.FIRSTLOCID,
357 CfbSchema.SECONDLOCID,
358 CfbSchema.THIRDLOCID,
364 Condition[] conditions = {
365 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
368 BugCollection coll = new BugCollection();
370 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
372 for (Row row : rows) {
373 // long foundId = row.getLong(0);
374 Long bugId = row.getLong(1);
375 Long categoryId = row.getLong(2);
376 Long firstLocId = row.getLong(3);
377 Long secondLocId = row.getLong(4);
378 Long thirdLocId = row.getLong(5);
379 Long varId = row.getLong(6);
381 String bugType = getBugType(bugId);
382 String category = getCategoryName(categoryId);
383 Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
384 LocalVariable[] vars = { getVar(varId) };
387 BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);