View | Details | Raw Unified | Return to bug 40825
Collapse All | Expand All

(-)C:/Documents and Settings/ecerulm/workspace32jmeter/JMeter2_2/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources_es.properties (+6 lines)
Lines 8-10 Link Here
8
queryType.shortDescription=is true, se lanzar\u00E1 como una query y no como un update/inser. Si no, se lanza como update.
8
queryType.shortDescription=is true, se lanzar\u00E1 como una query y no como un update/inser. Si no, se lanza como update.
9
sql.displayName=Query SQL
9
sql.displayName=Query SQL
10
varName.displayName=Nombre de Variable Ligada al Pool
10
varName.displayName=Nombre de Variable Ligada al Pool
11
queryArguments.displayName=Argumentos
12
queryArguments.shortDescription=los valores de los argumentos separados por comas
13
queryArgumentsTypes.displayName=Tipos de los argumentos
14
queryArgumentsTypes.shortDescription=los valores de los argumentos separados por comas
15
16
(-)C:/Documents and Settings/ecerulm/workspace32jmeter/JMeter2_2/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSampler.java (-28 / +211 lines)
Lines 17-28 Link Here
17
17
18
package org.apache.jmeter.protocol.jdbc.sampler;
18
package org.apache.jmeter.protocol.jdbc.sampler;
19
19
20
import java.lang.reflect.Field;
20
import java.sql.CallableStatement;
21
import java.sql.CallableStatement;
21
import java.sql.Connection;
22
import java.sql.Connection;
23
import java.sql.PreparedStatement;
22
import java.sql.ResultSet;
24
import java.sql.ResultSet;
23
import java.sql.ResultSetMetaData;
25
import java.sql.ResultSetMetaData;
24
import java.sql.SQLException;
26
import java.sql.SQLException;
25
import java.sql.Statement;
27
import java.sql.Statement;
28
import java.util.Collection;
29
import java.util.HashMap;
30
import java.util.Iterator;
31
import java.util.LinkedHashMap;
32
import java.util.Map;
26
33
27
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
34
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
28
import org.apache.jmeter.samplers.AbstractSampler;
35
import org.apache.jmeter.samplers.AbstractSampler;
Lines 40-57 Link Here
40
 * @author <a href="mailto:jeremy_a@bigfoot.com">Jeremy Arnold</a>
47
 * @author <a href="mailto:jeremy_a@bigfoot.com">Jeremy Arnold</a>
41
 */
48
 */
42
public class JDBCSampler extends AbstractSampler implements TestBean {
49
public class JDBCSampler extends AbstractSampler implements TestBean {
50
	private static final int MAX_ENTRIES = 200;
51
43
	private static final Logger log = LoggingManager.getLoggerForClass();
52
	private static final Logger log = LoggingManager.getLoggerForClass();
53
    static Map mapJdbcNameToInt;
44
54
45
    // Query types (used to communicate with GUI)
55
    // Query types (used to communicate with GUI)
46
	static final String SELECT   = "Select Statement";
56
	static final String SELECT   = "Select Statement";
47
	static final String UPDATE   = "Update Statement";
57
	static final String UPDATE   = "Update Statement";
48
	static final String CALLABLE = "Callable Statement";
58
	static final String CALLABLE = "Callable Statement";
59
	static final String PREPARED_SELECT = "Prepared Select Statement";
60
	static final String PREPARED_UPDATE = "Prepared Update Statement";
49
61
50
	private String query = "";
62
	private String query = "";
51
63
52
	private String dataSource = "";
64
	private String dataSource = "";
53
65
54
	private String queryType = SELECT;
66
	private String queryType = SELECT;
67
	private String queryArguments = "";
68
	private String queryArgumentsTypes = "";
69
	
70
	/**
71
	 *  Cache of PreparedStatements stored in a per-connection basis. Each entry of this 
72
	 *  cache is another Map mapping the statemente string to the actual PreparedStatement.
73
	 *  The cache has a fixed size of MAX_ENTRIES and it will throw aways all PreparedStatements 
74
	 *  from the least recently used connections.  
75
	 */
76
	private static Map perConnCache = new LinkedHashMap(MAX_ENTRIES){
77
		protected boolean removeEldestEntry(java.util.Map.Entry arg0) {
78
			if (size() > MAX_ENTRIES) {
79
				final Object value = arg0.getValue();
80
				if (value instanceof Map) {
81
					closeAllStatements(((Map)value).values());
82
				}
83
				return true;
84
			}
85
			return false;
86
		}
87
	};
55
88
56
	/**
89
	/**
57
	 * Creates a JDBCSampler.
90
	 * Creates a JDBCSampler.
Lines 78-84 Link Here
78
		log.debug("DataSourceComponent: " + pool);
111
		log.debug("DataSourceComponent: " + pool);
79
		Connection conn = null;
112
		Connection conn = null;
80
		Statement stmt = null;
113
		Statement stmt = null;
81
		CallableStatement cs = null;
114
		
82
115
83
		try {
116
		try {
84
117
Lines 88-98 Link Here
88
			// TODO: Consider creating a sub-result with the time to get the
121
			// TODO: Consider creating a sub-result with the time to get the
89
			// connection.
122
			// connection.
90
			conn = pool.getConnection();
123
			conn = pool.getConnection();
91
			stmt = conn.createStatement();
92
124
93
            // Based on query return value, get results
125
            // Based on query return value, get results
94
            String _queryType = getQueryType();
126
            String _queryType = getQueryType();
95
            if (SELECT.equals(_queryType)) {
127
            if (SELECT.equals(_queryType)) {
128
            	stmt = conn.createStatement();
96
				ResultSet rs = null;
129
				ResultSet rs = null;
97
				try {
130
				try {
98
					rs = stmt.executeQuery(getQuery());
131
					rs = stmt.executeQuery(getQuery());
Lines 101-125 Link Here
101
				} finally {
134
				} finally {
102
					close(rs);
135
					close(rs);
103
				}
136
				}
104
			} else if (CALLABLE.equals(_queryType)) {
137
            } else if (CALLABLE.equals(_queryType)) {
105
					cs = conn.prepareCall(getQuery());
138
            	CallableStatement cstmt = getCallableStatement(conn);
106
					boolean hasResultSet = cs.execute();
139
            	setArguments(cstmt);
107
					if (hasResultSet){
140
            	// A CallableStatement can return more than 1 ResultSets
108
						ResultSet rs=cs.getResultSet();
141
            	// plus a number of update counts. 
109
						Data data = getDataFromResultSet(rs);
142
            	boolean hasResultSet = cstmt.execute();
110
						res.setResponseData(data.toString().getBytes());
143
            	String sb = resultSetsToString(cstmt,hasResultSet);
111
					} else {
144
            	res.setResponseData(sb.toString().getBytes());       	
112
						int updateCount = cs.getUpdateCount();
113
						String results = updateCount + " updates";
114
						res.setResponseData(results.getBytes());
115
					}
116
					//TODO process additional results (if any) using getMoreResults()
117
            } else if (UPDATE.equals(_queryType)) {
145
            } else if (UPDATE.equals(_queryType)) {
118
				stmt.execute(getQuery());
146
            	stmt = conn.createStatement();
147
            	stmt.executeUpdate(getQuery());
119
				int updateCount = stmt.getUpdateCount();
148
				int updateCount = stmt.getUpdateCount();
120
				String results = updateCount + " updates";
149
				String results = updateCount + " updates";
121
				res.setResponseData(results.getBytes());
150
				res.setResponseData(results.getBytes());
122
            // TODO add support for PreparedStatments
151
            } else if (PREPARED_SELECT.equals(_queryType)) {
152
            	PreparedStatement pstmt = getPreparedStatement(conn);
153
            	setArguments(pstmt);
154
            	pstmt.executeQuery();
155
            	String sb = resultSetsToString(pstmt,true);
156
            	res.setResponseData(sb.toString().getBytes());
157
            } else if (PREPARED_UPDATE.equals(_queryType)) {
158
            	PreparedStatement pstmt = getPreparedStatement(conn);
159
            	setArguments(pstmt);
160
            	pstmt.executeUpdate();
161
				String sb = resultSetsToString(pstmt,false);
162
            	res.setResponseData(sb.toString().getBytes());
123
            } else { // User provided incorrect query type
163
            } else { // User provided incorrect query type
124
                String results="Unexpected query type: "+_queryType;
164
                String results="Unexpected query type: "+_queryType;
125
                res.setResponseMessage(results);
165
                res.setResponseMessage(results);
Lines 131-137 Link Here
131
			res.setResponseMessage(ex.toString());
171
			res.setResponseMessage(ex.toString());
132
			res.setSuccessful(false);
172
			res.setSuccessful(false);
133
		} finally {
173
		} finally {
134
			close(cs);
135
			close(stmt);
174
			close(stmt);
136
			close(conn);
175
			close(conn);
137
		}
176
		}
Lines 140-145 Link Here
140
		return res;
179
		return res;
141
	}
180
	}
142
181
182
	private String resultSetsToString(PreparedStatement pstmt, boolean result) throws SQLException {
183
		StringBuffer sb = new StringBuffer();
184
		sb.append("\n");
185
		int updateCount = 0;
186
		if (!result) {
187
			updateCount = pstmt.getUpdateCount();
188
		}
189
		do {
190
			if (result) {
191
				ResultSet rs = null;
192
				try {
193
					rs = pstmt.getResultSet();
194
					Data data = getDataFromResultSet(rs);
195
					sb.append(data.toString()).append("\n");
196
				} finally {
197
					close(rs);
198
				}
199
			} else {
200
				sb.append(updateCount).append(" updates.\n");
201
			}
202
			result = pstmt.getMoreResults();
203
			if (!result) {
204
				updateCount = pstmt.getUpdateCount();
205
			}
206
		} while (result || (updateCount != -1));
207
		return sb.toString();
208
	}
209
210
211
	private void setArguments(PreparedStatement pstmt) throws SQLException {
212
		if ("".equals(getQueryArguments().trim())) {
213
			return;
214
		}
215
		String[] arguments = getQueryArguments().split(",");
216
		String[] argumentsTypes = getQueryArgumentsTypes().split(",");
217
		if (arguments.length != argumentsTypes.length) {
218
			throw new SQLException("number of arguments ("+arguments.length+") and number of types ("+argumentsTypes.length+") are not equal");
219
		}
220
		for (int i = 0; i < arguments.length; i++) {
221
			String argument = arguments[i];
222
			String argumentType = argumentsTypes[i];
223
			//TODO should be a more elegant way to do it
224
		    int targetSqlType = getJdbcType(argumentType);
225
		    pstmt.setObject(i+1, argument, targetSqlType);
226
		}
227
	}
228
    
229
    public static int getJdbcType(String jdbcType) {
230
        // based on e291. Getting the Name of a JDBC Type from javaalmanac.com
231
        // http://javaalmanac.com/egs/java.sql/JdbcInt2Str.html
232
    	if (mapJdbcNameToInt == null) {
233
    		mapJdbcNameToInt = new HashMap();
234
    		
235
    		//Get all field in java.sql.Types
236
    		Field[] fields = java.sql.Types.class.getFields();
237
            for (int i=0; i<fields.length; i++) {
238
                try {
239
                    // Get field name
240
                    String name = fields[i].getName();
241
    
242
                    // Get field value
243
                    Integer value = (Integer)fields[i].get(null);
244
    
245
                    // Add to map
246
                    mapJdbcNameToInt.put(name.toLowerCase(),value);
247
                } catch (IllegalAccessException e) {
248
                	throw new RuntimeException(e);
249
                }
250
            }
251
    		
252
    	}
253
    	return ((Integer)mapJdbcNameToInt.get(jdbcType.toLowerCase())).intValue();
254
    }
255
	
256
257
	private CallableStatement getCallableStatement(Connection conn) throws SQLException {
258
		return (CallableStatement) getPreparedStatement(conn,true);
259
		
260
	}
261
	private PreparedStatement getPreparedStatement(Connection conn) throws SQLException {
262
		return getPreparedStatement(conn,false);
263
	}
264
265
	private PreparedStatement getPreparedStatement(Connection conn, boolean callable) throws SQLException {
266
		Map preparedStatementMap = (Map) perConnCache.get(conn);
267
		if (null == preparedStatementMap ) {
268
		    // MRU PreparedStatements cache. 
269
			preparedStatementMap = new LinkedHashMap(MAX_ENTRIES) {
270
				protected boolean removeEldestEntry(java.util.Map.Entry arg0) {
271
					final int theSize = size();
272
					if (theSize > MAX_ENTRIES) {
273
						Object value = arg0.getValue();
274
						if (value instanceof PreparedStatement) {
275
							PreparedStatement pstmt = (PreparedStatement) value;
276
							try {
277
								pstmt.close();
278
							} catch (SQLException e) {
279
								// ignore this exception
280
								e.printStackTrace();
281
							}
282
						}
283
						return true;
284
					}
285
					return false;
286
				}
287
			};
288
			perConnCache.put(conn, preparedStatementMap);
289
		}
290
		PreparedStatement pstmt = (PreparedStatement) preparedStatementMap.get(getQuery());
291
		if (null == pstmt) {
292
			if (callable) {
293
				pstmt = conn.prepareCall(getQuery());
294
			} else {
295
				pstmt = conn.prepareStatement(getQuery());
296
			}
297
			preparedStatementMap.put(getQuery(), pstmt);
298
		}
299
		pstmt.clearParameters();
300
		return pstmt;
301
	}
302
303
	private static void closeAllStatements(Collection collection) {
304
		Iterator iterator = collection.iterator();
305
		while (iterator.hasNext()) {
306
			PreparedStatement pstmt = (PreparedStatement) iterator.next();
307
			try {
308
				pstmt.close();
309
			} catch (SQLException e) {
310
				// ignore this exception
311
				e.printStackTrace();
312
			}
313
		}
314
		
315
	}
316
143
	/**
317
	/**
144
	 * Gets a Data object from a ResultSet.
318
	 * Gets a Data object from a ResultSet.
145
	 * 
319
	 * 
Lines 171-177 Link Here
171
		}
345
		}
172
		return data;
346
		return data;
173
	}
347
	}
174
348
	
175
	public static void close(Connection c) {
349
	public static void close(Connection c) {
176
		try {
350
		try {
177
			if (c != null) c.close();
351
			if (c != null) c.close();
Lines 184-201 Link Here
184
		try {
358
		try {
185
			if (s != null) s.close();
359
			if (s != null) s.close();
186
		} catch (SQLException e) {
360
		} catch (SQLException e) {
187
			log.warn("Error closing Statement", e);
361
			log.warn("Error closing Statement " + s.toString(), e);
188
		}
362
		}
189
	}
363
	}
190
364
191
	public static void close(CallableStatement cs) {
365
	
192
		try {
193
			if (cs != null) cs.close();
194
		} catch (SQLException e) {
195
			log.warn("Error closing CallableStatement", e);
196
		}
197
	}
198
199
	public static void close(ResultSet rs) {
366
	public static void close(ResultSet rs) {
200
		try {
367
		try {
201
			if (rs != null) rs.close();
368
			if (rs != null) rs.close();
Lines 253-256 Link Here
253
	public void setQueryType(String queryType) {
420
	public void setQueryType(String queryType) {
254
		this.queryType = queryType;
421
		this.queryType = queryType;
255
	}
422
	}
423
424
	public String getQueryArguments() {
425
		return queryArguments;
426
	}
427
428
	public void setQueryArguments(String queryArguments) {
429
		this.queryArguments = queryArguments;
430
	}
431
432
	public String getQueryArgumentsTypes() {
433
		return queryArgumentsTypes;
434
	}
435
436
	public void setQueryArgumentsTypes(String queryArgumentsType) {
437
		this.queryArgumentsTypes = queryArgumentsType;
438
	}
256
}
439
}
(-)C:/Documents and Settings/ecerulm/workspace32jmeter/JMeter2_2/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerBeanInfo.java (-2 / +13 lines)
Lines 40-61 Link Here
40
40
41
		createPropertyGroup("varName", new String[] { "dataSource" });
41
		createPropertyGroup("varName", new String[] { "dataSource" });
42
42
43
		createPropertyGroup("sql", new String[] { "queryType", "query" });
43
		createPropertyGroup("sql", new String[] { "queryType", "query", "queryArguments","queryArgumentsTypes" });
44
44
45
		PropertyDescriptor p = property("dataSource");
45
		PropertyDescriptor p = property("dataSource");
46
		p.setValue(NOT_UNDEFINED, Boolean.TRUE);
46
		p.setValue(NOT_UNDEFINED, Boolean.TRUE);
47
		p.setValue(DEFAULT, "");
47
		p.setValue(DEFAULT, "");
48
48
49
		p = property("queryArguments");
50
		p.setValue(NOT_UNDEFINED, Boolean.TRUE);
51
		p.setValue(DEFAULT, "");
52
		
53
		p = property("queryArgumentsTypes");
54
		p.setValue(NOT_UNDEFINED, Boolean.TRUE);
55
		p.setValue(DEFAULT, "");
56
		
57
49
		p = property("queryType");
58
		p = property("queryType");
50
		p.setValue(NOT_UNDEFINED, Boolean.TRUE);
59
		p.setValue(NOT_UNDEFINED, Boolean.TRUE);
51
		p.setValue(DEFAULT, JDBCSampler.SELECT);
60
		p.setValue(DEFAULT, JDBCSampler.SELECT);
52
		p.setValue(NOT_OTHER,Boolean.TRUE);
61
		p.setValue(NOT_OTHER,Boolean.TRUE);
53
		p.setValue(TAGS,new String[]{JDBCSampler.SELECT,JDBCSampler.UPDATE,JDBCSampler.CALLABLE});
62
		p.setValue(TAGS,new String[]{JDBCSampler.SELECT,JDBCSampler.UPDATE,JDBCSampler.CALLABLE, JDBCSampler.PREPARED_SELECT, JDBCSampler.PREPARED_UPDATE});
54
63
55
		p = property("query");
64
		p = property("query");
56
		p.setValue(NOT_UNDEFINED, Boolean.TRUE);
65
		p.setValue(NOT_UNDEFINED, Boolean.TRUE);
57
		p.setValue(DEFAULT, "");
66
		p.setValue(DEFAULT, "");
58
		p.setPropertyEditorClass(TextAreaEditor.class);
67
		p.setPropertyEditorClass(TextAreaEditor.class);
68
		
69
//		
59
70
60
	}
71
	}
61
}
72
}
(-)C:/Documents and Settings/ecerulm/workspace32jmeter/JMeter2_2/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/sampler/JDBCSamplerResources.properties (-1 / +7 lines)
Lines 6-9 Link Here
6
queryType.displayName=Query Type
6
queryType.displayName=Query Type
7
queryType.shortDescription=Determines if the SQL statement should be run as a select statement or an update statement.
7
queryType.shortDescription=Determines if the SQL statement should be run as a select statement or an update statement.
8
dataSource.displayName=Variable Name
8
dataSource.displayName=Variable Name
9
dataSource.shortDescription=Name of the JMeter variable that the connection pool is bound to.
9
dataSource.shortDescription=Name of the JMeter variable that the connection pool is bound to.
10
queryArguments.displayName=Parameters
11
queryArguments.shortDescription=SQL parameter values
12
queryArgumentsTypes.displayName=Parameter JDBC Type
13
queryArgumentsTypes.shortDescription=JDBC Type names form java.sql.Types. VARCHAR, INTEGER, etc. 
14
15

Return to bug 40825