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.Table;
15 import net.jaekl.cfb.db.TypeMismatchException;
16 import net.jaekl.cfb.db.driver.DbDriver;
17 import net.jaekl.cfb.xml.BugClass;
18 import net.jaekl.cfb.xml.BugInstance;
19 import net.jaekl.cfb.xml.BugMethod;
20 import net.jaekl.cfb.xml.LocalVariable;
21 import net.jaekl.cfb.xml.SourceLine;
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 boolean put(Analysis analysis) throws SQLException, TypeMismatchException {
36 if (null == analysis) {
40 // ----------------------------------
41 // Add a run record for this analysis
43 long runId = m_driver.nextVal(m_con, CfbSchema.RUN_SEQ);
47 analysis.getBuildNumber(),
52 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
57 // -------------------------------------
58 // Add a found record for each bug found
60 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
61 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
64 for (BugInstance bug : bugs)
66 Long foundId = Long.valueOf(m_driver.nextVal(m_con, CfbSchema.FOUND_SEQ));
67 Long bugId = Long.valueOf(m_msgColl.getPattern(bug.getType()).getId());
68 Long categoryId = Long.valueOf(m_msgColl.getCategory(bug.getCategory()).getId());
69 Location[] locs = computeLocations(bug);
70 Location firstLoc = (locs.length > 0) ? locs[0] : null;
71 Location secondLoc = (locs.length > 1) ? locs[1] : null;
72 Location thirdLoc = (locs.length > 2) ? locs[2] : null;
74 values[row][0] = foundId;
75 values[row][1] = bugId;
76 values[row][2] = categoryId;
77 values[row][3] = getLocId(firstLoc);
78 values[row][4] = getLocId(secondLoc);
79 values[row][5] = getLocId(thirdLoc);
80 values[row][6] = getVarId(bug);
84 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
85 return (bugs.size() == count);
88 Location[] computeLocations(BugInstance bug)
90 ArrayList<Location> locs = new ArrayList<Location>();
93 Somewhat unfortunate special case.
94 The primary "location" for a bug instance is split between tags.
95 Most bugs have a pattern like this:
105 The primary location for a bug is given by the <Method> with no role attribute,
106 but the <SourceLine/> inside that method describes the whole range of lines
107 covered by that Method, not the spot where the bug is located--that is given
108 by the <SourceLine/> that is a direct child fo the <BugInstance/>.
111 BugMethod primaryMethod = null;
112 SourceLine primaryLine = null;
114 for (BugMethod method : bug.getMethods()) {
115 if (null != method.getRole()) {
116 primaryMethod = method;
120 if (bug.getLines().size() > 0) {
121 primaryLine = bug.getLines().get(0);
124 if ((null != primaryMethod) && (null != primaryLine)) {
125 locs.add(new Location(primaryMethod, primaryLine));
128 for (BugMethod method : bug.getMethods()) {
129 if (primaryMethod != method) {
130 locs.add(new Location(method));
133 for (SourceLine line : bug.getLines()) {
134 if (primaryLine != line) {
135 locs.add(new Location(line));
138 for (BugClass clazz : bug.getClasses()) {
139 locs.add(new Location(clazz));
142 return locs.toArray(new Location[locs.size()]);
145 Long getLocId(Location loc) throws SQLException, TypeMismatchException
150 Long locId = findLocId(loc);
155 return storeLoc(loc);
158 Long findLocId(Location loc) throws SQLException, TypeMismatchException
160 Column[] columns = { CfbSchema.LOCID };
161 Table[] tables = { CfbSchema.LOCATIONS };
163 Condition[] conditions = {
164 new Condition( CfbSchema.CLASSNAME, loc.getClassName(), Operation.EQUAL ),
165 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
166 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
167 new Condition( CfbSchema.STARTLINE, loc.getStart(), Operation.EQUAL ),
168 new Condition( CfbSchema.ENDLINE, loc.getEnd(), Operation.EQUAL )
170 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
171 if (rows.size() > 0) {
172 assert(1 == rows.size()); // should only have one match
174 return rows.get(0).getLong(0);
177 return null; // not found
180 Long storeLoc(Location loc) throws SQLException
182 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
184 Object[][] values = { {
189 Long.valueOf(loc.getStart()),
190 Long.valueOf(loc.getEnd())
192 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
197 return Long.valueOf(locId);
200 Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
206 List<LocalVariable> vars = bug.getVariables();
207 if ((null == vars) || (0 == vars.size())) {
211 return getVarId(vars.get(0));
214 Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
220 Long result = findVarId(var);
222 if (null != result) {
226 return storeVar(var);
229 Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
231 Column[] columns = { CfbSchema.VARID_PK };
232 Table[] tables = { CfbSchema.VARIABLES };
234 Condition[] conditions = {
235 new Condition( CfbSchema.NAME, var.getName(), Operation.EQUAL ),
236 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
238 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
239 if (rows.size() > 0) {
240 assert(1 == rows.size()); // should only have one match
242 return rows.get(0).getLong(0);
245 return null; // not found
248 Long storeVar(LocalVariable var) throws SQLException
250 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
252 Object[][] values = { {
257 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
262 return Long.valueOf(varId);