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.MessageCollection;
22 public class DbStore {
25 MessageCollection m_msgColl;
27 public DbStore(Connection con, DbDriver driver, MessageCollection msgColl) {
33 public Analysis getPrior(Analysis analysis) throws SQLException, TypeMismatchException {
34 if (null == analysis) {
37 Long priorId = getPriorId(analysis);
38 if (null == priorId) {
42 return getAnalysis(priorId);
45 public boolean put(Analysis analysis) throws SQLException, TypeMismatchException {
46 if (null == analysis) {
50 // ----------------------------------
51 // Add a run record for this analysis
53 long runId = m_driver.nextVal(m_con, CfbSchema.RUN_SEQ);
57 analysis.getBuildNumber(),
62 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
67 // -------------------------------------
68 // Add a found record for each bug found
70 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
71 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
74 for (BugInstance bug : bugs)
76 Long foundId = Long.valueOf(m_driver.nextVal(m_con, CfbSchema.FOUND_SEQ));
77 Long bugId = Long.valueOf(m_msgColl.getPattern(bug.getType()).getId());
78 Long categoryId = Long.valueOf(m_msgColl.getCategory(bug.getCategory()).getId());
79 List<Location> locs = bug.getLocations();
80 Location firstLoc = (locs.size() > 0) ? locs.get(0) : null;
81 Location secondLoc = (locs.size() > 1) ? locs.get(1) : null;
82 Location thirdLoc = (locs.size() > 2) ? locs.get(2) : null;
84 values[row][0] = foundId;
85 values[row][1] = runId;
86 values[row][2] = bugId;
87 values[row][3] = categoryId;
88 values[row][4] = getLocId(firstLoc);
89 values[row][5] = getLocId(secondLoc);
90 values[row][6] = getLocId(thirdLoc);
91 values[row][7] = getVarId(bug);
95 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
96 return (bugs.size() == count);
99 String getBugType(Long bugPatternId) throws SQLException, TypeMismatchException
101 Column[] columns = { CfbSchema.TYPE };
102 Table[] tables = { CfbSchema.BUGS };
103 Condition[] conditions = { new Condition(CfbSchema.BUGID, bugPatternId, Operation.EQUAL) };
104 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
105 String type = row.getString(0);
109 String getCategoryName(Long categoryId) throws SQLException, TypeMismatchException
111 Column[] columns = { CfbSchema.CATEGORY };
112 Table[] tables = { CfbSchema.CATEGORIES };
113 Condition[] conditions = { new Condition(CfbSchema.CATEGORYID, categoryId, Operation.EQUAL) };
114 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
115 String name = row.getString(0);
120 Location getLoc(Long locId) throws SQLException, TypeMismatchException
126 Column[] columns = { CfbSchema.CLASSNAME, CfbSchema.METHODNAME, CfbSchema.METHODROLE, CfbSchema.STARTLINE, CfbSchema.ENDLINE };
127 Table[] tables = { CfbSchema.LOCATIONS };
128 Condition[] conditions = { new Condition(CfbSchema.LOCID, locId, Operation.EQUAL) };
130 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
132 String className = row.getString(0);
133 String methodName = row.getString(1);
134 String methodRole = row.getString(2);
135 Integer startLine = row.getInt(3);
136 Integer endLine = row.getInt(4);
138 Location loc = new Location(locId, className, methodName, methodRole, startLine, endLine);
142 Long getLocId(Location loc) throws SQLException, TypeMismatchException
147 Long locId = findLocId(loc);
152 return storeLoc(loc);
155 Long findLocId(Location loc) throws SQLException, TypeMismatchException
157 Column[] columns = { CfbSchema.LOCID };
158 Table[] tables = { CfbSchema.LOCATIONS };
160 Condition[] conditions = {
161 new Condition( CfbSchema.CLASSNAME, loc.getClassName(), Operation.EQUAL ),
162 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
163 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
164 new Condition( CfbSchema.STARTLINE, loc.getStart(), Operation.EQUAL ),
165 new Condition( CfbSchema.ENDLINE, loc.getEnd(), Operation.EQUAL )
167 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
168 if (rows.size() > 0) {
169 assert(1 == rows.size()); // should only have one match
171 return rows.get(0).getLong(0);
174 return null; // not found
177 Long storeLoc(Location loc) throws SQLException
179 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
181 Object[][] values = { {
186 Long.valueOf(loc.getStart()),
187 Long.valueOf(loc.getEnd())
189 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
194 return Long.valueOf(locId);
197 Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
203 List<LocalVariable> vars = bug.getVariables();
204 if ((null == vars) || (0 == vars.size())) {
208 return getVarId(vars.get(0));
211 LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException
217 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
218 Table[] tables = { CfbSchema.VARIABLES };
219 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
221 List<Row> result = m_driver.select(m_con, columns, tables, conditions);
222 if (result.size() < 1) {
223 throw new SQLException("No variable found for ID " + varId);
225 if (result.size() > 1) {
226 throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
229 String varName = result.get(0).getString(0);
230 String varRole = result.get(0).getString(1);
232 return new LocalVariable(varId, varName, varRole);
235 Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
241 Long result = findVarId(var);
243 if (null != result) {
247 return storeVar(var);
250 Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
252 Column[] columns = { CfbSchema.VARID_PK };
253 Table[] tables = { CfbSchema.VARIABLES };
255 Condition[] conditions = {
256 new Condition( CfbSchema.NAME, var.getName(), Operation.EQUAL ),
257 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
259 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
260 if (rows.size() > 0) {
261 assert(1 == rows.size()); // should only have one match
263 return rows.get(0).getLong(0);
266 return null; // not found
269 Long storeVar(LocalVariable var) throws SQLException
271 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
273 Object[][] values = { {
278 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
283 return Long.valueOf(varId);
286 Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
288 Column[] columns = { CfbSchema.RUNID };
289 Table[] tables = { CfbSchema.RUNS };
290 Condition[] conditions = { new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN ) };
291 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
294 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
295 if (rows.size() < 1) {
298 return rows.get(0).getLong(0);
301 Analysis getAnalysis(Long analysisId) throws SQLException, TypeMismatchException
303 Column[] columns = { CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
304 Table[] tables = { CfbSchema.RUNS };
305 Condition[] conditions = { new Condition( CfbSchema.RUNID, analysisId, Operation.EQUAL ) };
307 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
308 if (rows.size() < 1) {
312 Row row = rows.get(0);
314 String version = row.getString(0);
315 java.util.Date start= row.getDate(1);
316 java.util.Date end = row.getDate(2);
318 Analysis prior = new Analysis(version);
319 prior.setId(analysisId.longValue());
320 prior.setStart(start);
323 prior.setBugCollection(getBugCollection(analysisId));
328 BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException
333 CfbSchema.CATEGORYID,
334 CfbSchema.FIRSTLOCID,
335 CfbSchema.SECONDLOCID,
336 CfbSchema.THIRDLOCID,
342 Condition[] conditions = {
343 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
346 BugCollection coll = new BugCollection();
348 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
350 for (Row row : rows) {
351 // long foundId = row.getLong(0);
352 Long bugId = row.getLong(1);
353 Long categoryId = row.getLong(2);
354 Long firstLocId = row.getLong(3);
355 Long secondLocId = row.getLong(4);
356 Long thirdLocId = row.getLong(5);
357 Long varId = row.getLong(6);
359 String bugType = getBugType(bugId);
360 String category = getCategoryName(categoryId);
361 Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
362 LocalVariable[] vars = { getVar(varId) };
365 BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);