Author: fschumacher
Date: Tue Sep 20 18:55:08 2016
New Revision: 1761614

URL: http://svn.apache.org/viewvc?rev=1761614&view=rev
Log:
Handle CLOBs and BLOBs and limit them if necessary when storing them in result 
sampler.

Bugzilla Id: 60085

Modified:
    jmeter/trunk/bin/jmeter.properties
    
jmeter/trunk/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/AbstractJDBCTestElement.java
    jmeter/trunk/xdocs/changes.xml
    jmeter/trunk/xdocs/usermanual/component_reference.xml
    jmeter/trunk/xdocs/usermanual/properties_reference.xml

Modified: jmeter/trunk/bin/jmeter.properties
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/bin/jmeter.properties?rev=1761614&r1=1761613&r2=1761614&view=diff
==============================================================================
--- jmeter/trunk/bin/jmeter.properties (original)
+++ jmeter/trunk/bin/jmeter.properties Tue Sep 20 18:55:08 2016
@@ -829,6 +829,9 @@ wmlParser.types=text/vnd.wap.wml
 
 # String used to indicate a null value
 #jdbcsampler.nullmarker=]NULL[
+#
+# Max size of BLOBs and CLOBs to store in JDBC sampler. Result will be cut off
+#jdbcsampler.max_retain_result_size=65536
 
 #---------------------------------------------------------------------------
 # OS Process Sampler configuration

Modified: 
jmeter/trunk/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/AbstractJDBCTestElement.java
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/AbstractJDBCTestElement.java?rev=1761614&r1=1761613&r2=1761614&view=diff
==============================================================================
--- 
jmeter/trunk/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/AbstractJDBCTestElement.java
 (original)
+++ 
jmeter/trunk/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/AbstractJDBCTestElement.java
 Tue Sep 20 18:55:08 2016
@@ -23,7 +23,9 @@ import java.io.UnsupportedEncodingExcept
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
+import java.sql.Blob;
 import java.sql.CallableStatement;
+import java.sql.Clob;
 import java.sql.Connection;
 import java.sql.Date;
 import java.sql.PreparedStatement;
@@ -35,11 +37,11 @@ import java.sql.Time;
 import java.sql.Timestamp;
 import java.sql.Types;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.jmeter.samplers.SampleResult;
 import org.apache.jmeter.save.CSVSaveService;
 import org.apache.jmeter.testelement.AbstractTestElement;
@@ -124,6 +126,8 @@ public abstract class AbstractJDBCTestEl
     private String resultVariable = ""; // $NON-NLS-1$
     private String queryTimeout = ""; // $NON-NLS-1$
 
+    private static final int MAX_RETAIN_SIZE = 
JMeterUtils.getPropDefault("jdbcsampler.max_retain_result_size", 64 * 1024);
+
     /**
      * Creates a JDBCSampler.
      */
@@ -283,16 +287,11 @@ public abstract class AbstractJDBCTestEl
                     if (name.length()>0){ // Save the value in the variable if 
present
                         Object o = outputValues.get(i);
                         if( o instanceof java.sql.ResultSet ) { 
-                            ResultSet resultSet = (ResultSet) o;
-                            if(RS_STORE_AS_OBJECT.equals(resultSetHandler)) {
-                                jmvars.putObject(name, o);
-                            }
-                            else if( 
RS_COUNT_RECORDS.equals(resultSetHandler)) {
-                                jmvars.put(name,o.toString()+" 
"+countRows(resultSet)+" rows");
-                            }
-                            else {
-                                jmvars.put(name, o.toString());
-                            }
+                            putIntoVar(jmvars, name, (java.sql.ResultSet) o);
+                        } else if (o instanceof java.sql.Clob) {
+                            putIntoVar(jmvars, name, (java.sql.Clob) o);
+                        } else if (o instanceof java.sql.Blob) {
+                            putIntoVar(jmvars, name, (java.sql.Blob) o);
                         }
                         else {
                             jmvars.put(name, o == null ? null : o.toString());
@@ -303,7 +302,59 @@ public abstract class AbstractJDBCTestEl
         }
         return sb.toString();
     }
-    
+
+    private void putIntoVar(final JMeterVariables jmvars, final String name,
+            final ResultSet resultSet) throws SQLException {
+        if (RS_STORE_AS_OBJECT.equals(resultSetHandler)) {
+            jmvars.putObject(name, resultSet);
+        } else if (RS_COUNT_RECORDS.equals(resultSetHandler)) {
+            jmvars.put(name, resultSet.toString() + " " + countRows(resultSet)
+                    + " rows");
+        } else {
+            jmvars.put(name, resultSet.toString());
+        }
+    }
+
+    private void putIntoVar(final JMeterVariables jmvars, final String name,
+            final Clob clob) throws SQLException {
+        try {
+            if (clob.length() > MAX_RETAIN_SIZE) {
+                jmvars.put(
+                        name,
+                        IOUtils.toString(clob.getCharacterStream(0,
+                                MAX_RETAIN_SIZE))
+                                + "<result cut off, it is too big>");
+            } else {
+                jmvars.put(name, IOUtils.toString(clob.getCharacterStream()));
+            }
+        } catch (IOException e) {
+            log.warn("Could not read CLOB into " + name, e);
+        }
+    }
+
+    private void putIntoVar(final JMeterVariables jmvars, final String name,
+            final Blob blob) throws SQLException {
+        if (RS_STORE_AS_OBJECT.equals(resultSetHandler)) {
+            try {
+                long length = Math.max(blob.length(), MAX_RETAIN_SIZE);
+                jmvars.putObject(name,
+                        IOUtils.toByteArray(blob.getBinaryStream(0, length)));
+            } catch (IOException e) {
+                log.warn("Could not read BLOB into " + name + " as object.", 
e);
+            }
+        } else if (RS_COUNT_RECORDS.equals(resultSetHandler)) {
+            jmvars.put(name, blob.length() + " bytes");
+        } else {
+            try {
+                long length = Math.max(blob.length(), MAX_RETAIN_SIZE);
+                jmvars.put(name, IOUtils.toString(
+                        blob.getBinaryStream(0, length), ENCODING));
+            } catch (IOException e) {
+                log.warn("Can't convert BLOB to String using " + ENCODING, e);
+            }
+        }
+    }
+
     /**
      * Count rows in result set
      * @param resultSet {@link ResultSet}

Modified: jmeter/trunk/xdocs/changes.xml
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1761614&r1=1761613&r2=1761614&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Tue Sep 20 18:55:08 2016
@@ -93,6 +93,7 @@ Summary
 <ul>
     <li><pr>211</pr>Differentiate the timing for JDBC Sampler. Use latency and 
connect time. Contributed by Thomas Peyrard (thomas.peyrard at murex.com)</li>
     <li><bug>59620</bug>Fix button action in "JMS Publisher -> Random File 
from folder specified below" to allow to select a directory</li>
+    <li><bug>60085</bug>Handle CLOBs and BLOBs and limit them if necessary 
when storing them in result sampler.</li>
 </ul>
 
 <h3>Controllers</h3>

Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1761614&r1=1761613&r2=1761614&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/component_reference.xml Tue Sep 20 18:55:08 
2016
@@ -593,9 +593,9 @@ the additional variables for rows four,
         </property>
         <property name="Handle ResultSet" required="No">Defines how ResultSet 
returned from callable statements be handled:
             <ul>
-                <li><code>Store As String</code> (default) - All variables on 
Variable Names list are stored as strings, will not iterate through a 
<code>ResultSet</code> when present on the list.</li>
-                <li><code>Store As Object</code> - Variables of 
<code>ResultSet</code> type on Variables Names list will be stored as Object 
and can be accessed in subsequent tests/scripts and iterated, will not iterate 
through the <code>ResultSet</code>.</li>
-                <li><code>Count Records</code> - Variables of 
<code>ResultSet</code> types will be iterated through showing the count of 
records as result. Variables will be stored as Strings.</li>
+                <li><code>Store As String</code> (default) - All variables on 
Variable Names list are stored as strings, will not iterate through a 
<code>ResultSet</code> when present on the list. <code>CLOB</code>s will be 
converted to Strings. <code>BLOB</code>s will be converted to Strings as if 
they were an UTF-8 encoded byte-array. Both <code>CLOB</code>s and 
<code>BLOB</code>s will be cut off after 
<code>jdbcsampler.max_retain_result_size</code> bytes.</li>
+                <li><code>Store As Object</code> - Variables of 
<code>ResultSet</code> type on Variables Names list will be stored as Object 
and can be accessed in subsequent tests/scripts and iterated, will not iterate 
through the <code>ResultSet</code>. <code>CLOB</code>s will be handled as if 
<code>Store As String</code> was selected. <code>BLOBs</code> will be stored as 
a byte array. Both <code>CLOB</code>s and <code>BLOB</code>s will be cut off 
after <code>jdbcsampler.max_retain_result_size</code> bytes.</li>
+                <li><code>Count Records</code> - Variables of 
<code>ResultSet</code> types will be iterated through showing the count of 
records as result. Variables will be stored as Strings. For <code>BLOB</code>s 
the size of the object will be stored.</li>
             </ul>
         </property>
 </properties>

Modified: jmeter/trunk/xdocs/usermanual/properties_reference.xml
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/properties_reference.xml?rev=1761614&r1=1761613&r2=1761614&view=diff
==============================================================================
--- jmeter/trunk/xdocs/usermanual/properties_reference.xml (original)
+++ jmeter/trunk/xdocs/usermanual/properties_reference.xml Tue Sep 20 18:55:08 
2016
@@ -488,6 +488,7 @@ Other parsers:<br/>
 <section name="&sect-num;.26 JDBC Request configuration" anchor="jdbc_request">
 <properties>
 <property name="jdbcsampler.nullmarker"> String used to indicate a null 
value<br/>, defaults to:]NULL[</property>
+<property name="jdbcsampler.max_retain_result_size">Max bytes to store from a 
CLOB or BLOB in the sampler<br/>, defaults to: 65536 (bytes)</property>
 </properties>
 </section>
 <section name="&sect-num;.27 OS Process Sampler configuration" 
anchor="os_sampler">


Reply via email to