Add ability to load previously found bugs back out of the database.
[cfb.git] / prod / net / jaekl / cfb / store / DbStore.java
1 package net.jaekl.cfb.store;
2
3 import java.sql.Connection;
4 import java.sql.SQLException;
5 import java.util.List;
6
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;
21
22 public class DbStore {
23         Connection m_con;
24         DbDriver m_driver;
25         MessageCollection m_msgColl;
26         
27         public DbStore(Connection con, DbDriver driver, MessageCollection msgColl) {
28                 m_con = con;
29                 m_driver = driver;
30                 m_msgColl = msgColl;
31         }
32
33         public Analysis getPrior(Analysis analysis) throws SQLException, TypeMismatchException {
34                 if (null == analysis) {
35                         return null;
36                 }
37                 Long priorId = getPriorId(analysis);
38                 if (null == priorId) {
39                         return null;
40                 }
41                 
42                 return getAnalysis(priorId);
43         }
44         
45         public boolean put(Analysis analysis) throws SQLException, TypeMismatchException {
46                 if (null == analysis) {
47                         return false;
48                 }
49                 
50                 // ----------------------------------
51                 // Add a run record for this analysis
52                 
53                 long runId = m_driver.nextVal(m_con, CfbSchema.RUN_SEQ);
54                 Object[][] values = { 
55                                                                 {
56                                                                         Long.valueOf(runId),
57                                                                         analysis.getBuildNumber(),
58                                                                         analysis.getStart(),
59                                                                         analysis.getEnd() 
60                                                                 } 
61                                                         };
62                 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
63                 if (1 != count) {
64                         return false;
65                 }
66                 
67                 // -------------------------------------
68                 // Add a found record for each bug found
69                 
70                 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
71                 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
72                 
73                 int row = 0;
74                 for (BugInstance bug : bugs)
75                 {
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;
83                         
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);
92                         row++;
93                 }
94                 
95                 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
96                 return (bugs.size() == count);
97         }
98         
99         String getBugType(Long bugPatternId) throws SQLException, TypeMismatchException
100         {
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);
106                 return type;
107         }
108         
109         String getCategoryName(Long categoryId) throws SQLException, TypeMismatchException
110         {
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);
116                 return name;
117         }
118         
119         
120         Location getLoc(Long locId) throws SQLException, TypeMismatchException
121         {
122                 Column[] columns = { CfbSchema.CLASSNAME, CfbSchema.METHODNAME, CfbSchema.METHODROLE, CfbSchema.STARTLINE, CfbSchema.ENDLINE };
123                 Table[] tables = { CfbSchema.LOCATIONS };
124                 Condition[] conditions = { new Condition(CfbSchema.LOCID, locId, Operation.EQUAL) };
125                 
126                 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
127                 
128                 String className = row.getString(0);
129                 String methodName = row.getString(1);
130                 String methodRole = row.getString(2);
131                 long startLine = row.getLong(3);
132                 long endLine = row.getLong(4);
133                 
134                 Location loc = new Location(locId, className, methodName, methodRole, startLine, endLine);
135                 return loc;
136         }
137         
138         Long getLocId(Location loc) throws SQLException, TypeMismatchException 
139         {
140                 if (null == loc) {
141                         return null;
142                 }
143                 Long locId = findLocId(loc);
144                 if (null != locId) {
145                         return locId;
146                 }
147
148                 return storeLoc(loc);
149         }
150         
151         Long findLocId(Location loc) throws SQLException, TypeMismatchException
152         {
153                 Column[] columns = { CfbSchema.LOCID };
154                 Table[] tables = { CfbSchema.LOCATIONS };
155                 
156                 Condition[] conditions = { 
157                                                 new Condition( CfbSchema.CLASSNAME,  loc.getClassName(),  Operation.EQUAL ),
158                                                 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
159                                                 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
160                                                 new Condition( CfbSchema.STARTLINE,  loc.getStart(),      Operation.EQUAL ),
161                                                 new Condition( CfbSchema.ENDLINE,    loc.getEnd(),        Operation.EQUAL )
162                                         };
163                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
164                 if (rows.size() > 0) {
165                         assert(1 == rows.size());       // should only have one match
166                         
167                         return rows.get(0).getLong(0);
168                 }
169                 
170                 return null;    // not found
171         }
172         
173         Long storeLoc(Location loc) throws SQLException
174         {
175                 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
176                 
177                 Object[][] values = { { 
178                                                         Long.valueOf(locId),
179                                                         loc.getClassName(),
180                                                         loc.getMethodName(),
181                                                         loc.getMethodRole(),
182                                                         Long.valueOf(loc.getStart()),
183                                                         Long.valueOf(loc.getEnd())
184                                                 } };
185                 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
186                 if (1 != count) {
187                         return null;
188                 }
189                 
190                 return Long.valueOf(locId);
191         }
192         
193         Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
194         {
195                 if (null == bug) {
196                         return null;
197                 }
198                 
199                 List<LocalVariable> vars = bug.getVariables();
200                 if ((null == vars) || (0 == vars.size())) {
201                         return null;
202                 }
203                 
204                 return getVarId(vars.get(0));
205         }
206         
207         LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException
208         {
209                 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
210                 Table[] tables = { CfbSchema.VARIABLES };
211                 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
212                 
213                 List<Row> result = m_driver.select(m_con, columns, tables, conditions);
214                 if (result.size() < 1) {
215                         throw new SQLException("No variable found for ID " + varId);
216                 }
217                 if (result.size() > 1) {
218                         throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
219                 }
220                 
221                 String varName = result.get(0).getString(0);
222                 String varRole = result.get(0).getString(1);
223                 
224                 return new LocalVariable(varId, varName, varRole);
225         }
226         
227         Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
228         {
229                 if (null == var) {
230                         return null;
231                 }
232                 
233                 Long result = findVarId(var);
234                 
235                 if (null != result) {
236                         return result;
237                 }
238                 
239                 return storeVar(var);
240         }
241         
242         Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
243         {
244                 Column[] columns = { CfbSchema.VARID_PK };
245                 Table[] tables = { CfbSchema.VARIABLES };
246                 
247                 Condition[] conditions = { 
248                                                 new Condition( CfbSchema.NAME,    var.getName(), Operation.EQUAL ),
249                                                 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
250                                         };
251                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
252                 if (rows.size() > 0) {
253                         assert(1 == rows.size());       // should only have one match
254                         
255                         return rows.get(0).getLong(0);
256                 }
257                 
258                 return null;    // not found
259         }
260         
261         Long storeVar(LocalVariable var) throws SQLException
262         {
263                 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
264                 
265                 Object[][] values = { { 
266                                                         Long.valueOf(varId),
267                                                         var.getName(),
268                                                         var.getRole()
269                                                 } };
270                 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
271                 if (1 != count) {
272                         return null;
273                 }
274                 
275                 return Long.valueOf(varId);
276         }
277         
278         Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
279         {
280                 Column[] columns = { CfbSchema.RUNID };
281                 Table[] tables = { CfbSchema.RUNS };
282                 Condition[] conditions = { new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN ) };
283                 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
284                 int limit = 1;
285                 
286                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
287                 if (rows.size() < 1) {
288                         return null;
289                 }
290                 return rows.get(0).getLong(0);
291         }
292         
293         Analysis getAnalysis(Long priorId) throws SQLException, TypeMismatchException
294         {
295                 Column[] columns = { CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
296                 Table[] tables = { CfbSchema.RUNS };
297                 Condition[] conditions = { new Condition( CfbSchema.RUNID, priorId, Operation.EQUAL ) };
298                 
299                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
300                 if (rows.size() < 1) {
301                         return null;
302                 }
303                 
304                 Row row = rows.get(0);
305                 
306                 String version = row.getString(0);
307                 java.util.Date start= row.getDate(1);
308                 java.util.Date end = row.getDate(2);
309                 
310                 Analysis prior = new Analysis(version);
311                 prior.setId(priorId.longValue());
312                 prior.setStart(start);
313                 prior.setEnd(end);
314                 
315                 prior.setBugCollection(getBugCollection(priorId));
316                 
317                 return prior;
318         }
319         
320         BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException 
321         {
322                 Column[] columns = {
323                                 CfbSchema.FOUNDID,
324                                 CfbSchema.BUGID,
325                                 CfbSchema.CATEGORYID,
326                                 CfbSchema.FIRSTLOCID,
327                                 CfbSchema.SECONDLOCID,
328                                 CfbSchema.THIRDLOCID,
329                                 CfbSchema.VARID_FK 
330                 };
331                 Table[] tables = {
332                                 CfbSchema.FOUND
333                 };
334                 Condition[] conditions = {
335                                 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
336                 };
337                 
338                 BugCollection coll = new BugCollection();
339                 
340                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
341                 
342                 for (Row row : rows) {
343                         // long foundId = row.getLong(0);
344                         long bugId = row.getLong(1);
345                         long categoryId = row.getLong(2);
346                         long firstLocId = row.getLong(3);
347                         long secondLocId = row.getLong(4);
348                         long thirdLocId = row.getLong(5);
349                         long varId = row.getLong(6);
350                         
351                         String bugType = getBugType(bugId);
352                         String category = getCategoryName(categoryId);
353                         Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
354                         LocalVariable[] vars = { getVar(Long.valueOf(varId)) };
355
356                         
357                         BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);
358                         coll.getBugs().add(bug);
359                 }
360                 
361                 return coll;
362         }
363 }