6c2097925f3d78a3c14fb91e6325643d66578be1
[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                 if (null == locId) {
123                         return null;
124                 }
125                 
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) };
129                 
130                 Row row = m_driver.selectExactlyOne(m_con, columns, tables, conditions);
131                 
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);
137                 
138                 Location loc = new Location(locId, className, methodName, methodRole, startLine, endLine);
139                 return loc;
140         }
141         
142         Long getLocId(Location loc) throws SQLException, TypeMismatchException 
143         {
144                 if (null == loc) {
145                         return null;
146                 }
147                 Long locId = findLocId(loc);
148                 if (null != locId) {
149                         return locId;
150                 }
151
152                 return storeLoc(loc);
153         }
154         
155         Long findLocId(Location loc) throws SQLException, TypeMismatchException
156         {
157                 Column[] columns = { CfbSchema.LOCID };
158                 Table[] tables = { CfbSchema.LOCATIONS };
159                 
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 )
166                                         };
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
170                         
171                         return rows.get(0).getLong(0);
172                 }
173                 
174                 return null;    // not found
175         }
176         
177         Long storeLoc(Location loc) throws SQLException
178         {
179                 long locId = m_driver.nextVal(m_con, CfbSchema.LOC_SEQ);
180                 
181                 Object[][] values = { { 
182                                                         Long.valueOf(locId),
183                                                         loc.getClassName(),
184                                                         loc.getMethodName(),
185                                                         loc.getMethodRole(),
186                                                         Long.valueOf(loc.getStart()),
187                                                         Long.valueOf(loc.getEnd())
188                                                 } };
189                 int count = m_driver.insert(m_con, CfbSchema.LOCATIONS, values);
190                 if (1 != count) {
191                         return null;
192                 }
193                 
194                 return Long.valueOf(locId);
195         }
196         
197         Long getVarId(BugInstance bug) throws SQLException, TypeMismatchException
198         {
199                 if (null == bug) {
200                         return null;
201                 }
202                 
203                 List<LocalVariable> vars = bug.getVariables();
204                 if ((null == vars) || (0 == vars.size())) {
205                         return null;
206                 }
207                 
208                 return getVarId(vars.get(0));
209         }
210         
211         LocalVariable getVar(Long varId) throws SQLException, TypeMismatchException
212         {
213                 if (null == varId) {
214                         return null;
215                 }
216                 
217                 Column[] columns = { CfbSchema.NAME, CfbSchema.VARROLE };
218                 Table[] tables = { CfbSchema.VARIABLES };
219                 Condition[] conditions = { new Condition(CfbSchema.VARID_PK, varId, Operation.EQUAL) };
220                 
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);
224                 }
225                 if (result.size() > 1) {
226                         throw new SQLException("Too many matches (" + result.size() + ") found for variable ID " + varId);
227                 }
228                 
229                 String varName = result.get(0).getString(0);
230                 String varRole = result.get(0).getString(1);
231                 
232                 return new LocalVariable(varId, varName, varRole);
233         }
234         
235         Long getVarId(LocalVariable var) throws SQLException, TypeMismatchException
236         {
237                 if (null == var) {
238                         return null;
239                 }
240                 
241                 Long result = findVarId(var);
242                 
243                 if (null != result) {
244                         return result;
245                 }
246                 
247                 return storeVar(var);
248         }
249         
250         Long findVarId(LocalVariable var) throws SQLException, TypeMismatchException
251         {
252                 Column[] columns = { CfbSchema.VARID_PK };
253                 Table[] tables = { CfbSchema.VARIABLES };
254                 
255                 Condition[] conditions = { 
256                                                 new Condition( CfbSchema.NAME,    var.getName(), Operation.EQUAL ),
257                                                 new Condition( CfbSchema.VARROLE, var.getRole(), Operation.EQUAL )
258                                         };
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
262                         
263                         return rows.get(0).getLong(0);
264                 }
265                 
266                 return null;    // not found
267         }
268         
269         Long storeVar(LocalVariable var) throws SQLException
270         {
271                 long varId = m_driver.nextVal(m_con, CfbSchema.VARIABLE_SEQ);
272                 
273                 Object[][] values = { { 
274                                                         Long.valueOf(varId),
275                                                         var.getName(),
276                                                         var.getRole()
277                                                 } };
278                 int count = m_driver.insert(m_con, CfbSchema.VARIABLES, values);
279                 if (1 != count) {
280                         return null;
281                 }
282                 
283                 return Long.valueOf(varId);
284         }
285         
286         Long getPriorId(Analysis analysis) throws SQLException, TypeMismatchException
287         {
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 ) };
292                 int limit = 1;
293                 
294                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions, sorts, limit);
295                 if (rows.size() < 1) {
296                         return null;
297                 }
298                 return rows.get(0).getLong(0);
299         }
300         
301         Analysis getAnalysis(Long analysisId) throws SQLException, TypeMismatchException
302         {
303                 Column[] columns = { CfbSchema.VERSION, CfbSchema.STARTTIME, CfbSchema.ENDTIME };
304                 Table[] tables = { CfbSchema.RUNS };
305                 Condition[] conditions = { new Condition( CfbSchema.RUNID, analysisId, Operation.EQUAL ) };
306                 
307                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
308                 if (rows.size() < 1) {
309                         return null;
310                 }
311                 
312                 Row row = rows.get(0);
313                 
314                 String version = row.getString(0);
315                 java.util.Date start= row.getDate(1);
316                 java.util.Date end = row.getDate(2);
317                 
318                 Analysis prior = new Analysis(version);
319                 prior.setId(analysisId.longValue());
320                 prior.setStart(start);
321                 prior.setEnd(end);
322                 
323                 prior.setBugCollection(getBugCollection(analysisId));
324                 
325                 return prior;
326         }
327         
328         BugCollection getBugCollection(Long runId) throws SQLException, TypeMismatchException 
329         {
330                 Column[] columns = {
331                                 CfbSchema.FOUNDID,
332                                 CfbSchema.BUGID,
333                                 CfbSchema.CATEGORYID,
334                                 CfbSchema.FIRSTLOCID,
335                                 CfbSchema.SECONDLOCID,
336                                 CfbSchema.THIRDLOCID,
337                                 CfbSchema.VARID_FK 
338                 };
339                 Table[] tables = {
340                                 CfbSchema.FOUND
341                 };
342                 Condition[] conditions = {
343                                 new Condition(CfbSchema.RUNID, runId, Operation.EQUAL)
344                 };
345                 
346                 BugCollection coll = new BugCollection();
347                 
348                 List<Row> rows = m_driver.select(m_con, columns, tables, conditions);
349                 
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);
358                         
359                         String bugType = getBugType(bugId);
360                         String category = getCategoryName(categoryId);
361                         Location[] locations = { getLoc(firstLocId), getLoc(secondLocId), getLoc(thirdLocId) };
362                         LocalVariable[] vars = { getVar(varId) };
363
364                         
365                         BugInstance bug = new BugInstance(bugId, category, bugType, locations, vars);
366                         coll.add(bug);
367                 }
368                 
369                 return coll;
370         }
371 }