1 package net.jaekl.cfb.store;
3 import java.sql.Connection;
4 import java.sql.SQLException;
6 import java.util.Locale;
8 import net.jaekl.cfb.CfbBundle;
9 import net.jaekl.cfb.analyze.Analysis;
10 import net.jaekl.cfb.db.CfbSchema;
11 import net.jaekl.cfb.db.Column;
12 import net.jaekl.cfb.db.Condition;
13 import net.jaekl.cfb.db.Operation;
14 import net.jaekl.cfb.db.Row;
15 import net.jaekl.cfb.db.Sort;
16 import net.jaekl.cfb.db.Table;
17 import net.jaekl.cfb.db.TypeMismatchException;
18 import net.jaekl.cfb.db.driver.DbDriver;
19 import net.jaekl.cfb.xml.BugCollection;
20 import net.jaekl.cfb.xml.BugInstance;
21 import net.jaekl.cfb.xml.LocalVariable;
22 import net.jaekl.cfb.xml.messages.BugCategory;
23 import net.jaekl.cfb.xml.messages.BugPattern;
24 import net.jaekl.cfb.xml.messages.MessageCollection;
26 public class DbStore {
29 MessageCollection m_msgColl;
31 public DbStore(Connection con, DbDriver driver, MessageCollection msgColl) {
37 public Analysis getPrior(Analysis analysis) throws SQLException, TypeMismatchException {
38 if (null == analysis) {
41 Long priorId = getPriorId(analysis);
42 if (null == priorId) {
46 return getAnalysis(priorId);
49 public boolean put(Analysis analysis) throws SQLException, TypeMismatchException, StoreException {
50 CfbBundle bundle = CfbBundle.getInst(Locale.getDefault());
52 if (null == analysis) {
56 // ----------------------------------
57 // Add a run record for this analysis
59 long runId = m_driver.nextVal(m_con, CfbSchema.RUN_SEQ);
63 analysis.getProjectName(),
64 analysis.getBuildNumber(),
69 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
74 // -------------------------------------
75 // Add a found record for each bug found
77 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
78 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
81 for (BugInstance bug : bugs)
83 Long foundId = Long.valueOf(m_driver.nextVal(m_con, CfbSchema.FOUND_SEQ));
84 Long bugId = Long.valueOf(m_msgColl.getPattern(bug.getType()).getId());
85 Long categoryId = Long.valueOf(m_msgColl.getCategory(bug.getCategory()).getId());
86 List<Location> locs = bug.getLocations();
87 Location firstLoc = (locs.size() > 0) ? locs.get(0) : null;
88 Location secondLoc = (locs.size() > 1) ? locs.get(1) : null;
89 Location thirdLoc = (locs.size() > 2) ? locs.get(2) : null;
91 if (BugPattern.UNKNOWN.getId() == bugId) {
92 throw new StoreException(bundle.get(CfbBundle.BUG_TYPE_UNKNOWN, ""+bug.getType()));
94 if (BugCategory.UNKNOWN.getId() == categoryId) {
95 throw new StoreException(bundle.get(CfbBundle.BUG_CATEGORY_UNKNOWN, ""+bug.getCategory()));
98 values[row][0] = foundId;
99 values[row][1] = runId;
100 values[row][2] = bugId;
101 values[row][3] = categoryId;
102 values[row][4] = getLocId(firstLoc);
103 values[row][5] = getLocId(secondLoc);
104 values[row][6] = getLocId(thirdLoc);
105 values[row][7] = getVarId(bug);
109 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
110 return (bugs.size() == count);
113 String getBugType(Long bugPatternId) throws SQLException, TypeMismatchException
115 Column[] columns = { CfbSchema.TYPE };
116 Table[] tables = { CfbSchema.BUGS };
117 Condition[] conditions = { new Condition(CfbSchema.BUGID, bugPatternId, Operation.EQUAL) };
118 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
119 String type = row.getString(0);
123 String getCategoryName(Long categoryId) throws SQLException, TypeMismatchException
125 Column[] columns = { CfbSchema.CATEGORY };
126 Table[] tables = { CfbSchema.CATEGORIES };
127 Condition[] conditions = { new Condition(CfbSchema.CATEGORYID, categoryId, Operation.EQUAL) };
128 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
129 String name = row.getString(0);
134 Location getLoc(Long locId) throws SQLException, TypeMismatchException
140 Column[] columns = { CfbSchema.CLASSNAME, CfbSchema.METHODNAME, CfbSchema.METHODROLE, CfbSchema.STARTLINE, CfbSchema.ENDLINE };
141 Table[] tables = { CfbSchema.LOCATIONS };
142 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);
156 Long getLocId(Location loc) throws SQLException, TypeMismatchException
161 Long locId = findLocId(loc);
166 return storeLoc(loc);
169 Long findLocId(Location loc) throws SQLException, TypeMismatchException
171 Column[] columns = { CfbSchema.LOCID };
172 Table[] tables = { CfbSchema.LOCATIONS };
174 Condition[] conditions = {
175 new Condition( CfbSchema.CLASSNAME, loc.getClassName(), Operation.EQUAL ),
176 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
177 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
178 new Condition( CfbSchema.STARTLINE, loc.getStart(), Operation.EQUAL ),
179 new Condition( CfbSchema.ENDLINE, loc.getEnd(), Operation.EQUAL )
181 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
182 if (rows.size() > 0) {
183 assert(1 == rows.size()); // should only have one match
185 return rows.get(0).getLong(0);
188 return null; // not found
191 Long storeLoc(Location loc) throws SQLException
193 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
195 Object[][] values = { {
200 Long.valueOf(loc.getStart()),
201 Long.valueOf(loc.getEnd())
203 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
208 return Long.valueOf(locId);
211 Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
217 List<LocalVariable> vars = bug.getVariables();
218 if ((null == vars) || (0 == vars.size())) {
222 return getVarId(vars.get(0));
225 LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException
231 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
232 Table[] tables = { CfbSchema.VARIABLES };
233 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
235 List<Row> result = m_driver.select(m_con, columns, tables, conditions);
236 if (result.size() < 1) {
237 throw new SQLException("No variable found for ID " + varId);
239 if (result.size() > 1) {
240 throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
243 String varName = result.get(0).getString(0);
244 String varRole = result.get(0).getString(1);
246 return new LocalVariable(varId, varName, varRole);
249 Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
255 Long result = findVarId(var);
257 if (null != result) {
261 return storeVar(var);
264 Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
266 Column[] columns = { CfbSchema.VARID_PK };
267 Table[] tables = { CfbSchema.VARIABLES };
269 Condition[] conditions = {
270 new Condition( CfbSchema.NAME, var.getName(), Operation.EQUAL ),
271 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
273 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
274 if (rows.size() > 0) {
275 assert(1 == rows.size()); // should only have one match
277 return rows.get(0).getLong(0);
280 return null; // not found
283 Long storeVar(LocalVariable var) throws SQLException
285 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
287 Object[][] values = { {
292 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
297 return Long.valueOf(varId);
300 Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
302 Column[] columns = { CfbSchema.RUNID };
303 Table[] tables = { CfbSchema.RUNS };
304 Condition[] conditions = {
305 new Condition( CfbSchema.PROJNAME, analysis.getProjectName(), Operation.EQUAL ),
306 new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN )
308 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
311 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
312 if (rows.size() < 1) {
315 return rows.get(0).getLong(0);
318 Analysis getAnalysis(Long analysisId) throws SQLException, TypeMismatchException
320 Column[] columns = { CfbSchema.PROJNAME, CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
321 Table[] tables = { CfbSchema.RUNS };
322 Condition[] conditions = { new Condition( CfbSchema.RUNID, analysisId, Operation.EQUAL ) };
324 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
325 if (rows.size() < 1) {
329 Row row = rows.get(0);
331 String projName = row.getString(0);
332 String version = row.getString(1);
333 java.util.Date start= row.getDate(2);
334 java.util.Date end = row.getDate(3);
336 Analysis prior = new Analysis(projName, version);
337 prior.setId(analysisId.longValue());
338 prior.setStart(start);
341 prior.setBugCollection(getBugCollection(analysisId));
346 BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException
351 CfbSchema.CATEGORYID,
352 CfbSchema.FIRSTLOCID,
353 CfbSchema.SECONDLOCID,
354 CfbSchema.THIRDLOCID,
360 Condition[] conditions = {
361 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
364 BugCollection coll = new BugCollection();
366 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
368 for (Row row : rows) {
369 // long foundId = row.getLong(0);
370 Long bugId = row.getLong(1);
371 Long categoryId = row.getLong(2);
372 Long firstLocId = row.getLong(3);
373 Long secondLocId = row.getLong(4);
374 Long thirdLocId = row.getLong(5);
375 Long varId = row.getLong(6);
377 String bugType = getBugType(bugId);
378 String category = getCategoryName(categoryId);
379 Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
380 LocalVariable[] vars = { getVar(varId) };
383 BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);