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 {
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 SQLException, TypeMismatchException
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) };
140 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
142 String className = row.getString(0);
143 String methodName = row.getString(1);
144 String methodRole = row.getString(2);
145 Integer startLine = row.getInt(3);
146 Integer endLine = row.getInt(4);
148 Location loc = new Location(locId, className, methodName, methodRole, startLine, endLine);
152 Long getLocId(Location loc) throws SQLException, TypeMismatchException
157 Long locId = findLocId(loc);
162 return storeLoc(loc);
165 Long findLocId(Location loc) throws SQLException, TypeMismatchException
167 Column[] columns = { CfbSchema.LOCID };
168 Table[] tables = { CfbSchema.LOCATIONS };
170 Condition[] conditions = {
171 new Condition( CfbSchema.CLASSNAME, loc.getClassName(), Operation.EQUAL ),
172 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
173 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
174 new Condition( CfbSchema.STARTLINE, loc.getStart(), Operation.EQUAL ),
175 new Condition( CfbSchema.ENDLINE, loc.getEnd(), Operation.EQUAL )
177 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
178 if (rows.size() > 0) {
179 assert(1 == rows.size()); // should only have one match
181 return rows.get(0).getLong(0);
184 return null; // not found
187 Long storeLoc(Location loc) throws SQLException
189 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
191 Object[][] values = { {
196 Long.valueOf(loc.getStart()),
197 Long.valueOf(loc.getEnd())
199 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
204 return Long.valueOf(locId);
207 Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
213 List<LocalVariable> vars = bug.getVariables();
214 if ((null == vars) || (0 == vars.size())) {
218 return getVarId(vars.get(0));
221 LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException
227 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
228 Table[] tables = { CfbSchema.VARIABLES };
229 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
231 List<Row> result = m_driver.select(m_con, columns, tables, conditions);
232 if (result.size() < 1) {
233 throw new SQLException("No variable found for ID " + varId);
235 if (result.size() > 1) {
236 throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
239 String varName = result.get(0).getString(0);
240 String varRole = result.get(0).getString(1);
242 return new LocalVariable(varId, varName, varRole);
245 Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
251 Long result = findVarId(var);
253 if (null != result) {
257 return storeVar(var);
260 Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
262 Column[] columns = { CfbSchema.VARID_PK };
263 Table[] tables = { CfbSchema.VARIABLES };
265 Condition[] conditions = {
266 new Condition( CfbSchema.NAME, var.getName(), Operation.EQUAL ),
267 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
269 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
270 if (rows.size() > 0) {
271 assert(1 == rows.size()); // should only have one match
273 return rows.get(0).getLong(0);
276 return null; // not found
279 Long storeVar(LocalVariable var) throws SQLException
281 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
283 Object[][] values = { {
288 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
293 return Long.valueOf(varId);
296 Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
298 Column[] columns = { CfbSchema.RUNID };
299 Table[] tables = { CfbSchema.RUNS };
300 Condition[] conditions = {
301 new Condition( CfbSchema.PROJNAME, analysis.getProjectName(), Operation.EQUAL ),
302 new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN )
304 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
307 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
308 if (rows.size() < 1) {
311 return rows.get(0).getLong(0);
314 Analysis getAnalysis(Long analysisId) throws SQLException, TypeMismatchException
316 Column[] columns = { CfbSchema.PROJNAME, CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
317 Table[] tables = { CfbSchema.RUNS };
318 Condition[] conditions = { new Condition( CfbSchema.RUNID, analysisId, Operation.EQUAL ) };
320 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
321 if (rows.size() < 1) {
325 Row row = rows.get(0);
327 String projName = row.getString(0);
328 String version = row.getString(1);
329 java.util.Date start= row.getDate(2);
330 java.util.Date end = row.getDate(3);
332 Analysis prior = new Analysis(projName, version);
333 prior.setId(analysisId.longValue());
334 prior.setStart(start);
337 prior.setBugCollection(getBugCollection(analysisId));
342 BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException
347 CfbSchema.CATEGORYID,
348 CfbSchema.FIRSTLOCID,
349 CfbSchema.SECONDLOCID,
350 CfbSchema.THIRDLOCID,
356 Condition[] conditions = {
357 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
360 BugCollection coll = new BugCollection();
362 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
364 for (Row row : rows) {
365 // long foundId = row.getLong(0);
366 Long bugId = row.getLong(1);
367 Long categoryId = row.getLong(2);
368 Long firstLocId = row.getLong(3);
369 Long secondLocId = row.getLong(4);
370 Long thirdLocId = row.getLong(5);
371 Long varId = row.getLong(6);
373 String bugType = getBugType(bugId);
374 String category = getCategoryName(categoryId);
375 Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
376 LocalVariable[] vars = { getVar(varId) };
379 BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);