1 package net.jaekl.cfb.store;
3 import java.sql.Connection;
4 import java.sql.SQLException;
5 import java.util.ArrayList;
8 import net.jaekl.cfb.analyze.Analysis;
9 import net.jaekl.cfb.db.CfbSchema;
10 import net.jaekl.cfb.db.Column;
11 import net.jaekl.cfb.db.Condition;
12 import net.jaekl.cfb.db.Operation;
13 import net.jaekl.cfb.db.Row;
14 import net.jaekl.cfb.db.Sort;
15 import net.jaekl.cfb.db.Table;
16 import net.jaekl.cfb.db.TypeMismatchException;
17 import net.jaekl.cfb.db.driver.DbDriver;
18 import net.jaekl.cfb.xml.BugClass;
19 import net.jaekl.cfb.xml.BugCollection;
20 import net.jaekl.cfb.xml.BugInstance;
21 import net.jaekl.cfb.xml.BugMethod;
22 import net.jaekl.cfb.xml.LocalVariable;
23 import net.jaekl.cfb.xml.SourceLine;
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 {
50 if (null == analysis) {
54 // ----------------------------------
55 // Add a run record for this analysis
57 long runId = m_driver.nextVal(m_con, CfbSchema.RUN_SEQ);
61 analysis.getBuildNumber(),
66 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
71 // -------------------------------------
72 // Add a found record for each bug found
74 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
75 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
78 for (BugInstance bug : bugs)
80 Long foundId = Long.valueOf(m_driver.nextVal(m_con, CfbSchema.FOUND_SEQ));
81 Long bugId = Long.valueOf(m_msgColl.getPattern(bug.getType()).getId());
82 Long categoryId = Long.valueOf(m_msgColl.getCategory(bug.getCategory()).getId());
83 Location[] locs = computeLocations(bug);
84 Location firstLoc = (locs.length > 0) ? locs[0] : null;
85 Location secondLoc = (locs.length > 1) ? locs[1] : null;
86 Location thirdLoc = (locs.length > 2) ? locs[2] : null;
88 values[row][0] = foundId;
89 values[row][1] = bugId;
90 values[row][2] = categoryId;
91 values[row][3] = getLocId(firstLoc);
92 values[row][4] = getLocId(secondLoc);
93 values[row][5] = getLocId(thirdLoc);
94 values[row][6] = getVarId(bug);
98 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
99 return (bugs.size() == count);
102 Location[] computeLocations(BugInstance bug)
104 ArrayList<Location> locs = new ArrayList<Location>();
107 Somewhat unfortunate special case.
108 The primary "location" for a bug instance is split between tags.
109 Most bugs have a pattern like this:
119 The primary location for a bug is given by the <Method> with no role attribute,
120 but the <SourceLine/> inside that method describes the whole range of lines
121 covered by that Method, not the spot where the bug is located--that is given
122 by the <SourceLine/> that is a direct child fo the <BugInstance/>.
125 BugMethod primaryMethod = null;
126 SourceLine primaryLine = null;
128 for (BugMethod method : bug.getMethods()) {
129 if (null != method.getRole()) {
130 primaryMethod = method;
134 if (bug.getLines().size() > 0) {
135 primaryLine = bug.getLines().get(0);
138 if ((null != primaryMethod) && (null != primaryLine)) {
139 locs.add(new Location(primaryMethod, primaryLine));
142 for (BugMethod method : bug.getMethods()) {
143 if (primaryMethod != method) {
144 locs.add(new Location(method));
147 for (SourceLine line : bug.getLines()) {
148 if (primaryLine != line) {
149 locs.add(new Location(line));
152 for (BugClass clazz : bug.getClasses()) {
153 locs.add(new Location(clazz));
156 return locs.toArray(new Location[locs.size()]);
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 Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
234 Long result = findVarId(var);
236 if (null != result) {
240 return storeVar(var);
243 Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
245 Column[] columns = { CfbSchema.VARID_PK };
246 Table[] tables = { CfbSchema.VARIABLES };
248 Condition[] conditions = {
249 new Condition( CfbSchema.NAME, var.getName(), Operation.EQUAL ),
250 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
252 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
253 if (rows.size() > 0) {
254 assert(1 == rows.size()); // should only have one match
256 return rows.get(0).getLong(0);
259 return null; // not found
262 Long storeVar(LocalVariable var) throws SQLException
264 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
266 Object[][] values = { {
271 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
276 return Long.valueOf(varId);
279 Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
281 Column[] columns = { CfbSchema.RUNID };
282 Table[] tables = { CfbSchema.RUNS };
283 Condition[] conditions = { new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN ) };
284 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
287 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
288 if (rows.size() < 1) {
291 return rows.get(0).getLong(0);
294 Analysis getAnalysis(Long priorId) throws SQLException, TypeMismatchException
296 Column[] columns = { CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
297 Table[] tables = { CfbSchema.RUNS };
298 Condition[] conditions = { new Condition( CfbSchema.RUNID, priorId, Operation.EQUAL ) };
300 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
301 if (rows.size() < 1) {
305 Row row = rows.get(0);
307 String version = row.getString(0);
308 java.util.Date start= row.getDate(1);
309 java.util.Date end = row.getDate(2);
311 Analysis prior = new Analysis(version);
312 prior.setId(priorId.longValue());
313 prior.setStart(start);
316 prior.setBugCollection(getBugCollection(priorId));
321 BugCollection getBugCollection(Long priorId) throws SQLException, TypeMismatchException
323 throw new UnsupportedOperationException("Not yet implemented");