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