Add the concept of "Project Name" to the RUNS table in 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.getProjectName(),
58                                                                         analysis.getBuildNumber(),
59                                                                         analysis.getStart(),
60                                                                         analysis.getEnd() 
61                                                                 } 
62                                                         };
63                 int count = m_driver.insert(m_con, CfbSchema.RUNS, values);
64                 if (1 != count) {
65                         return false;
66                 }
67                 
68                 // -------------------------------------
69                 // Add a found record for each bug found
70                 
71                 List<BugInstance> bugs = analysis.getBugCollection().getBugs();
72                 values = new Object[bugs.size()][CfbSchema.FOUND.getNumColumns()];
73                 
74                 int row = 0;
75                 for (BugInstance bug : bugs)
76                 {
77                         Long foundId = Long.valueOf(m_driver.nextVal(m_con, CfbSchema.FOUND_SEQ));
78                         Long bugId = Long.valueOf(m_msgColl.getPattern(bug.getType()).getId());
79                         Long categoryId = Long.valueOf(m_msgColl.getCategory(bug.getCategory()).getId());
80                         List<Location> locs = bug.getLocations();
81                         Location firstLoc  = (locs.size() > 0) ? locs.get(0) : null;
82                         Location secondLoc = (locs.size() > 1) ? locs.get(1) : null;
83                         Location thirdLoc  = (locs.size() > 2) ? locs.get(2) : null;
84                         
85                         values[row][0] = foundId;
86                         values[row][1] = runId;
87                         values[row][2] = bugId;
88                         values[row][3] = categoryId;
89                         values[row][4] = getLocId(firstLoc);
90                         values[row][5] = getLocId(secondLoc);
91                         values[row][6] = getLocId(thirdLoc);
92                         values[row][7] = getVarId(bug);
93                         row++;
94                 }
95                 
96                 count = m_driver.insert(m_con, CfbSchema.FOUND, values);
97                 return (bugs.size() == count);
98         }
99         
100         String getBugType(Long bugPatternId) throws SQLException, TypeMismatchException
101         {
102                 Column[] columns = { CfbSchema.TYPE };
103                 Table[] tables = { CfbSchema.BUGS };
104                 Condition[] conditions = { new Condition(CfbSchema.BUGID, bugPatternId, Operation.EQUAL) }; 
105                 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
106                 String type = row.getString(0);
107                 return type;
108         }
109         
110         String getCategoryName(Long categoryId) throws SQLException, TypeMismatchException
111         {
112                 Column[] columns = { CfbSchema.CATEGORY };
113                 Table[] tables = { CfbSchema.CATEGORIES };
114                 Condition[] conditions = { new Condition(CfbSchema.CATEGORYID, categoryId, Operation.EQUAL) };
115                 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
116                 String name = row.getString(0);
117                 return name;
118         }
119         
120         
121         Location getLoc(Long locId) throws SQLException, TypeMismatchException
122         {
123                 if (null == locId) {
124                         return null;
125                 }
126                 
127                 Column[] columns = { CfbSchema.CLASSNAME, CfbSchema.METHODNAME, CfbSchema.METHODROLE, CfbSchema.STARTLINE, CfbSchema.ENDLINE };
128                 Table[] tables = { CfbSchema.LOCATIONS };
129                 Condition[] conditions = { new Condition(CfbSchema.LOCID, locId, Operation.EQUAL) };
130                 
131                 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
132                 
133                 String className = row.getString(0);
134                 String methodName = row.getString(1);
135                 String methodRole = row.getString(2);
136                 Integer startLine = row.getInt(3);
137                 Integer endLine = row.getInt(4);
138                 
139                 Location loc = new Location(locId, className, methodName, methodRole, startLine, endLine);
140                 return loc;
141         }
142         
143         Long getLocId(Location loc) throws SQLException, TypeMismatchException 
144         {
145                 if (null == loc) {
146                         return null;
147                 }
148                 Long locId = findLocId(loc);
149                 if (null != locId) {
150                         return locId;
151                 }
152
153                 return storeLoc(loc);
154         }
155         
156         Long findLocId(Location loc) throws SQLException, TypeMismatchException
157         {
158                 Column[] columns = { CfbSchema.LOCID };
159                 Table[] tables = { CfbSchema.LOCATIONS };
160                 
161                 Condition[] conditions = { 
162                                                 new Condition( CfbSchema.CLASSNAME,  loc.getClassName(),  Operation.EQUAL ),
163                                                 new Condition( CfbSchema.METHODNAME, loc.getMethodName(), Operation.EQUAL ),
164                                                 new Condition( CfbSchema.METHODROLE, loc.getMethodRole(), Operation.EQUAL ),
165                                                 new Condition( CfbSchema.STARTLINE,  loc.getStart(),      Operation.EQUAL ),
166                                                 new Condition( CfbSchema.ENDLINE,    loc.getEnd(),        Operation.EQUAL )
167                                         };
168                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
169                 if (rows.size() > 0) {
170                         assert(1 == rows.size());       // should only have one match
171                         
172                         return rows.get(0).getLong(0);
173                 }
174                 
175                 return null;    // not found
176         }
177         
178         Long storeLoc(Location loc) throws SQLException
179         {
180                 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
181                 
182                 Object[][] values = { { 
183                                                         Long.valueOf(locId),
184                                                         loc.getClassName(),
185                                                         loc.getMethodName(),
186                                                         loc.getMethodRole(),
187                                                         Long.valueOf(loc.getStart()),
188                                                         Long.valueOf(loc.getEnd())
189                                                 } };
190                 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
191                 if (1 != count) {
192                         return null;
193                 }
194                 
195                 return Long.valueOf(locId);
196         }
197         
198         Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
199         {
200                 if (null == bug) {
201                         return null;
202                 }
203                 
204                 List<LocalVariable> vars = bug.getVariables();
205                 if ((null == vars) || (0 == vars.size())) {
206                         return null;
207                 }
208                 
209                 return getVarId(vars.get(0));
210         }
211         
212         LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException
213         {
214                 if (null == varId) {
215                         return null;
216                 }
217                 
218                 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
219                 Table[] tables = { CfbSchema.VARIABLES };
220                 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
221                 
222                 List<Row> result = m_driver.select(m_con, columns, tables, conditions);
223                 if (result.size() < 1) {
224                         throw new SQLException("No variable found for ID " + varId);
225                 }
226                 if (result.size() > 1) {
227                         throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
228                 }
229                 
230                 String varName = result.get(0).getString(0);
231                 String varRole = result.get(0).getString(1);
232                 
233                 return new LocalVariable(varId, varName, varRole);
234         }
235         
236         Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
237         {
238                 if (null == var) {
239                         return null;
240                 }
241                 
242                 Long result = findVarId(var);
243                 
244                 if (null != result) {
245                         return result;
246                 }
247                 
248                 return storeVar(var);
249         }
250         
251         Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
252         {
253                 Column[] columns = { CfbSchema.VARID_PK };
254                 Table[] tables = { CfbSchema.VARIABLES };
255                 
256                 Condition[] conditions = { 
257                                                 new Condition( CfbSchema.NAME,    var.getName(), Operation.EQUAL ),
258                                                 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
259                                         };
260                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
261                 if (rows.size() > 0) {
262                         assert(1 == rows.size());       // should only have one match
263                         
264                         return rows.get(0).getLong(0);
265                 }
266                 
267                 return null;    // not found
268         }
269         
270         Long storeVar(LocalVariable var) throws SQLException
271         {
272                 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
273                 
274                 Object[][] values = { { 
275                                                         Long.valueOf(varId),
276                                                         var.getName(),
277                                                         var.getRole()
278                                                 } };
279                 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
280                 if (1 != count) {
281                         return null;
282                 }
283                 
284                 return Long.valueOf(varId);
285         }
286         
287         Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
288         {
289                 Column[] columns = { CfbSchema.RUNID };
290                 Table[] tables = { CfbSchema.RUNS };
291                 Condition[] conditions = {
292                         new Condition( CfbSchema.PROJNAME, analysis.getProjectName(), Operation.EQUAL ),
293                         new Condition( CfbSchema.STARTTIME, analysis.getStart(), Operation.LESS_THAN ) 
294                 };
295                 Sort[] sorts = { new Sort( CfbSchema.STARTTIME, Sort.Direction.DESCENDING ) };
296                 int limit = 1;
297                 
298                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
299                 if (rows.size() < 1) {
300                         return null;
301                 }
302                 return rows.get(0).getLong(0);
303         }
304         
305         Analysis getAnalysis(Long analysisId) throws SQLException, TypeMismatchException
306         {
307                 Column[] columns = { CfbSchema.PROJNAME, CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
308                 Table[] tables = { CfbSchema.RUNS };
309                 Condition[] conditions = { new Condition( CfbSchema.RUNID, analysisId, Operation.EQUAL ) };
310                 
311                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
312                 if (rows.size() < 1) {
313                         return null;
314                 }
315                 
316                 Row row = rows.get(0);
317                 
318                 String projName = row.getString(0);
319                 String version = row.getString(1);
320                 java.util.Date start= row.getDate(2);
321                 java.util.Date end = row.getDate(3);
322                 
323                 Analysis prior = new Analysis(projName, version);
324                 prior.setId(analysisId.longValue());
325                 prior.setStart(start);
326                 prior.setEnd(end);
327                 
328                 prior.setBugCollection(getBugCollection(analysisId));
329                 
330                 return prior;
331         }
332         
333         BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException 
334         {
335                 Column[] columns = {
336                                 CfbSchema.FOUNDID,
337                                 CfbSchema.BUGID,
338                                 CfbSchema.CATEGORYID,
339                                 CfbSchema.FIRSTLOCID,
340                                 CfbSchema.SECONDLOCID,
341                                 CfbSchema.THIRDLOCID,
342                                 CfbSchema.VARID_FK 
343                 };
344                 Table[] tables = {
345                                 CfbSchema.FOUND
346                 };
347                 Condition[] conditions = {
348                                 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
349                 };
350                 
351                 BugCollection coll = new BugCollection();
352                 
353                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
354                 
355                 for (Row row : rows) {
356                         // long foundId = row.getLong(0);
357                         Long bugId = row.getLong(1);
358                         Long categoryId = row.getLong(2);
359                         Long firstLocId = row.getLong(3);
360                         Long secondLocId = row.getLong(4);
361                         Long thirdLocId = row.getLong(5);
362                         Long varId = row.getLong(6);
363                         
364                         String bugType = getBugType(bugId);
365                         String category = getCategoryName(categoryId);
366                         Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
367                         LocalVariable[] vars = { getVar(varId) };
368
369                         
370                         BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);
371                         coll.add(bug);
372                 }
373                 
374                 return coll;
375         }
376 }