[Fb-contrib-commit] SF.net SVN: fb-contrib: [516] trunk/fb-contrib/etc
Brought to you by:
dbrosius
From: <dbr...@us...> - 2006-05-05 05:52:05
|
Revision: 516 Author: dbrosius Date: 2006-05-04 22:51:49 -0700 (Thu, 04 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=516&view=rev Log Message: ----------- Initial checkin: SIL detector Modified Paths: -------------- trunk/fb-contrib/etc/findbugs.xml trunk/fb-contrib/etc/messages.xml Added Paths: ----------- trunk/fb-contrib/samples/SIL_Sample.java trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/SQLInLoop.java Modified: trunk/fb-contrib/etc/findbugs.xml =================================================================== --- trunk/fb-contrib/etc/findbugs.xml 2006-05-02 02:24:14 UTC (rev 515) +++ trunk/fb-contrib/etc/findbugs.xml 2006-05-05 05:51:49 UTC (rev 516) @@ -191,6 +191,10 @@ speed="fast" reports="UEC_USE_ENUM_COLLECTIONS" /> + <Detector class="com.mebigfatguy.fbcontrib.detect.SQLInLoop" + speed="fast" + reports="SIL_SQL_IN_LOOP" /> + <!-- BugPattern --> <BugPattern abbrev="ISB" type="ISB_INEFFICIENT_STRING_BUFFERING" category="PERFORMANCE" /> @@ -232,13 +236,14 @@ <BugPattern abbrev="JVR" type="JVR_JDBC_VENDOR_RELIANCE" category="CORRECTNESS" /> <BugPattern abbrev="PMB" type="PMB_POSSIBLE_MEMORY_BLOAT" category="CORRECTNESS" /> <BugPattern abbrev="LSYC" type="LSYC_LOCAL_SYNCHRONIZED_COLLECTION" category="CORRECTNESS" /> - <BugPattern abbrev="FCBL" type="FCBL_FIELD_COULD_BE_LOCAL" category="CORRECTNESS" experimental="true" /> - <BugPattern abbrev="NOS" type="NOS_NON_OWNED_SYNCHRONIZATION" category="STYLE" experimental="true" /> - <BugPattern abbrev="NRTL" type="NRTL_NON_RECYCLEABLE_TAG_LIB" category="CORRECTNESS" experimental="true" /> - <BugPattern abbrev="S508C" type="S508C_NULL_LAYOUT" category="CORRECTNESS" experimental="true" /> - <BugPattern abbrev="S508C" type="S508C_NO_SETLABELFOR" category="CORRECTNESS" experimental="true" /> - <BugPattern abbrev="S508C" type="S508C_NO_SETSIZE" category="CORRECTNESS" experimental="true" /> - <BugPattern abbrev="S508C" type="S508C_NON_ACCESSIBLE_JCOMPONENT" category="CORRECTNESS" experimental="true"/> - <BugPattern abbrev="S508C" type="S508C_SET_COMP_COLOR" category="CORRECTNESS" experimental="true" /> - <BugPattern abbrev="UEC" type="UEC_USE_ENUM_COLLECTIONS" category="PERFORMANCE" experimental="true" /> + <BugPattern abbrev="FCBL" type="FCBL_FIELD_COULD_BE_LOCAL" category="CORRECTNESS" /> + <BugPattern abbrev="NOS" type="NOS_NON_OWNED_SYNCHRONIZATION" category="STYLE" /> + <BugPattern abbrev="NRTL" type="NRTL_NON_RECYCLEABLE_TAG_LIB" category="CORRECTNESS" /> + <BugPattern abbrev="S508C" type="S508C_NULL_LAYOUT" category="CORRECTNESS" /> + <BugPattern abbrev="S508C" type="S508C_NO_SETLABELFOR" category="CORRECTNESS" /> + <BugPattern abbrev="S508C" type="S508C_NO_SETSIZE" category="CORRECTNESS" /> + <BugPattern abbrev="S508C" type="S508C_NON_ACCESSIBLE_JCOMPONENT" category="CORRECTNESS" /> + <BugPattern abbrev="S508C" type="S508C_SET_COMP_COLOR" category="CORRECTNESS" /> + <BugPattern abbrev="UEC" type="UEC_USE_ENUM_COLLECTIONS" category="PERFORMANCE" /> + <BugPattern abbrev="SIL" type="SIL_SQL_IN_LOOP" category="PERFORMANCE" experimental="true" /> </FindbugsPlugin> \ No newline at end of file Modified: trunk/fb-contrib/etc/messages.xml =================================================================== --- trunk/fb-contrib/etc/messages.xml 2006-05-02 02:24:14 UTC (rev 515) +++ trunk/fb-contrib/etc/messages.xml 2006-05-05 05:51:49 UTC (rev 516) @@ -546,6 +546,17 @@ ]]> </Details> </Detector> + + <Detector class="com.mebigfatguy.fbcontrib.detect.SQLInLoop"> + <Details> + <![CDATA[ + <p>looks for the execution of sql queries inside a loop. This pattern tends to be inefficient, + and often can be improved upon, by collecting all the keys needed for the query and issuing just + one query using an in clause with all the keys for all the queries previously needed in the loop.</p> + <p>It is a fast detector</p> + ]]> + </Details> + </Detector> <!-- BugPattern --> @@ -1173,6 +1184,20 @@ </Details> </BugPattern> + <BugPattern type="SIL_SQL_IN_LOOP"> + <ShortDescription>Method executes sql queries inside of loops</ShortDescription> + <LongDescription>Method {1} executes sql queries inside of loops</LongDescription> + <Details> + <![CDATA[ + <p>This method executes sql queries inside of a loop. This pattern is often inefficient + as the number of queries may mushroom in fencepost cases. It is probably more performant + to loop over the input and collect the key data needed for the query for all items, and + issue one query using an in clause, or similar construct, and then loop over this result + set, and fetch all the data at once. + ]]> + </Details> + </BugPattern> + <!-- BugCode --> <BugCode abbrev="ISB">Inefficient String Buffering</BugCode> @@ -1219,4 +1244,5 @@ <BugCode abbrev="NRTL">Non Recycleable Taglib</BugCode> <BugCode abbrev="S508C">Section 508 Compliance Violations</BugCode> <BugCode abbrev="UEC">Use Enum Collections</BugCode> + <BugCode abbrev="SIL">SQL In Loop</BugCode> </MessageCollection> \ No newline at end of file Added: trunk/fb-contrib/samples/SIL_Sample.java =================================================================== --- trunk/fb-contrib/samples/SIL_Sample.java (rev 0) +++ trunk/fb-contrib/samples/SIL_Sample.java 2006-05-05 05:51:49 UTC (rev 516) @@ -0,0 +1,20 @@ +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class SIL_Sample +{ + public void test(ResultSet rs) throws SQLException + { + Connection c = rs.getStatement().getConnection(); + PreparedStatement ps = c.prepareStatement("select foo from boo where moo = ?"); + + while (rs.next()) + { + int key = rs.getInt(1); + ps.setInt(1, key); + ResultSet mrs = ps.executeQuery(); + } + } +} Added: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/SQLInLoop.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/SQLInLoop.java (rev 0) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/SQLInLoop.java 2006-05-05 05:51:49 UTC (rev 516) @@ -0,0 +1,97 @@ +package com.mebigfatguy.fbcontrib.detect; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.bcel.classfile.Code; + +import edu.umd.cs.findbugs.BugInstance; +import edu.umd.cs.findbugs.BugReporter; +import edu.umd.cs.findbugs.BytecodeScanningDetector; +import edu.umd.cs.findbugs.ba.ClassContext; + +public class SQLInLoop extends BytecodeScanningDetector +{ + private static final Set<String> queryClasses = new HashSet<String>(); + static { + queryClasses.add("java/sql/Statement"); + queryClasses.add("java/sql/PreparedStatement"); + queryClasses.add("java/sql/CallableStatement"); + } + private static final Set<String> queryMethods = new HashSet<String>(); + static { + queryMethods.add("execute"); + queryMethods.add("executeQuery"); + }; + + private BugReporter bugReporter; + List<Integer> queryLocations; + List<LoopLocation> loops; + + public SQLInLoop(BugReporter bugReporter) { + this.bugReporter = bugReporter; + } + + @Override + public void visitClassContext(ClassContext classContext) { + try { + queryLocations = new ArrayList<Integer>(); + loops = new ArrayList<LoopLocation>(); + super.visitClassContext(classContext); + } finally { + queryLocations = null; + loops = null; + } + } + + @Override + public void visitCode(Code obj) { + queryLocations.clear(); + loops.clear(); + super.visitCode(obj); + for (Integer qLoc : queryLocations) { + for (LoopLocation lLoc : loops) { + if (lLoc.isInLoop(qLoc.intValue())) { + bugReporter.reportBug(new BugInstance(this, "SIL_SQL_IN_LOOP", NORMAL_PRIORITY) + .addClass(this) + .addMethod(this) + .addSourceLine(this, qLoc.intValue())); + break; + } + } + } + } + + @Override + public void sawOpcode(int seen) { + if (seen == INVOKEINTERFACE) { + String clsName = getClassConstantOperand(); + String methodName = getNameConstantOperand(); + + if (queryClasses.contains(clsName) && queryMethods.contains(methodName)) + queryLocations.add(new Integer(getPC())); + } else if ((seen == GOTO) || (seen == GOTO_W)) { + int branchTarget = getBranchTarget(); + int pc = getPC(); + if (branchTarget < pc) { + loops.add(new LoopLocation(branchTarget, pc)); + } + } + } + + private static class LoopLocation { + private int startPC; + private int endPC; + + public LoopLocation(int start, int end) { + startPC = start; + endPC = end; + } + + public boolean isInLoop(int pc) { + return (pc >= startPC) && (pc <= endPC); + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |