001    package com.mockrunner.mock.jdbc;
002    
003    import java.io.InputStream;
004    import java.io.Reader;
005    import java.math.BigDecimal;
006    import java.net.URL;
007    import java.sql.Array;
008    import java.sql.BatchUpdateException;
009    import java.sql.Blob;
010    import java.sql.Clob;
011    import java.sql.Connection;
012    import java.sql.Date;
013    import java.sql.ParameterMetaData;
014    import java.sql.PreparedStatement;
015    import java.sql.Ref;
016    import java.sql.ResultSet;
017    import java.sql.ResultSetMetaData;
018    import java.sql.SQLException;
019    import java.sql.Time;
020    import java.sql.Timestamp;
021    import java.util.ArrayList;
022    import java.util.Calendar;
023    import java.util.Collections;
024    import java.util.HashMap;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Map;
028    
029    import com.mockrunner.jdbc.AbstractParameterResultSetHandler;
030    import com.mockrunner.jdbc.ParameterUtil;
031    import com.mockrunner.util.common.StringUtil;
032    
033    /**
034     * Mock implementation of <code>PreparedStatement</code>.
035     */
036    public class MockPreparedStatement extends MockStatement implements PreparedStatement
037    {
038        private AbstractParameterResultSetHandler resultSetHandler;
039        private Map paramObjects = new HashMap();
040        private List batchParameters = new ArrayList();
041        private String sql;
042        private MockParameterMetaData parameterMetaData;
043        
044        public MockPreparedStatement(Connection connection, String sql)
045        {
046            super(connection);
047            this.sql = sql;
048            prepareParameterMetaData();
049        }
050        
051        public MockPreparedStatement(Connection connection, String sql, int resultSetType, int resultSetConcurrency)
052        {
053            super(connection, resultSetType, resultSetConcurrency);
054            this.sql = sql;
055            prepareParameterMetaData();
056        }
057    
058        public MockPreparedStatement(Connection connection, String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
059        {
060            super(connection, resultSetType, resultSetConcurrency, resultSetHoldability);
061            this.sql = sql;
062            prepareParameterMetaData();
063        }
064        
065        public void setPreparedStatementResultSetHandler(AbstractParameterResultSetHandler resultSetHandler)
066        {
067            super.setResultSetHandler(resultSetHandler);
068            this.resultSetHandler = resultSetHandler;
069        }
070        
071        private void prepareParameterMetaData()
072        {
073            int number = StringUtil.countMatches(sql, "?");
074            parameterMetaData = new MockParameterMetaData();
075            parameterMetaData.setParameterCount(number);
076        }
077      
078        public String getSQL()
079        {
080            return sql;
081        }
082        
083        public Map getIndexedParameterMap()
084        {
085            return Collections.unmodifiableMap(paramObjects);
086        }
087        
088            public Map getParameterMap()
089            {
090                    return getIndexedParameterMap();
091            }
092        
093        public Object getParameter(int index)
094        {
095            return paramObjects.get(new Integer(index));
096        }
097        
098        public void setObject(int index, Object object) throws SQLException 
099        {
100            paramObjects.put(new Integer(index), object);
101        }
102        
103        public void setObject(int parameterIndex, Object object, int targetSqlType, int scale) throws SQLException
104        {
105            setObject(parameterIndex, object);
106        }
107    
108        public void setObject(int parameterIndex, Object object, int targetSqlType) throws SQLException
109        {
110            setObject(parameterIndex, object);
111        }
112        
113        public void addBatch() throws SQLException
114        {
115            batchParameters.add(new HashMap(paramObjects));
116        }
117    
118        public void clearParameters() throws SQLException
119        {
120            paramObjects.clear();
121        }
122    
123        public boolean execute() throws SQLException
124        {
125            boolean callExecuteQuery = isQuery(getSQL());
126            if(callExecuteQuery)
127            {
128                executeQuery();
129            }
130            else
131            {
132                executeUpdate();
133            }
134            return callExecuteQuery;
135        }
136        
137        public ResultSet executeQuery() throws SQLException
138        {
139            return executeQuery(paramObjects);
140        }
141        
142        protected ResultSet executeQuery(Map params) throws SQLException
143        {
144            if(resultSetHandler.getThrowsSQLException(getSQL(), params))
145            {
146                throw new SQLException("Statement " + getSQL() + " was specified to throw an exception");
147            }
148            if(resultSetHandler.getThrowsSQLException(getSQL()))
149            {
150                throw new SQLException("Statement " + getSQL() + " was specified to throw an exception");
151            }
152            MockResultSet result = resultSetHandler.getResultSet(getSQL(), params);
153                    resultSetHandler.addParameterMapForExecutedStatement(getSQL(), getParameterMapCopy(params));
154            if(null != result)
155            {
156                resultSetHandler.addExecutedStatement(getSQL());
157                result = cloneResultSet(result);
158                resultSetHandler.addReturnedResultSet(result);
159                setNextResultSet(result);
160                return result;
161            }
162            return super.executeQuery(getSQL());
163        }
164    
165        public int executeUpdate() throws SQLException
166        {
167            return executeUpdate(paramObjects);
168        }
169        
170        protected int executeUpdate(Map params) throws SQLException
171        {
172            if(resultSetHandler.getThrowsSQLException(getSQL(), params))
173            {
174                throw new SQLException("Statement " + getSQL() + " was specified to throw an exception");
175            }
176            if(resultSetHandler.getThrowsSQLException(getSQL()))
177            {
178                throw new SQLException("Statement " + getSQL() + " was specified to throw an exception");
179            }
180            Integer updateCount = resultSetHandler.getUpdateCount(getSQL(), params);
181                    resultSetHandler.addParameterMapForExecutedStatement(getSQL(), getParameterMapCopy(params));
182            if(null != updateCount)
183            {
184                resultSetHandler.addExecutedStatement(getSQL());
185                int updateCountInt = updateCount.intValue();
186                setNextUpdateCount(updateCountInt);
187                return updateCountInt;
188            }
189            return super.executeUpdate(getSQL());
190        }
191        
192        public int[] executeBatch() throws SQLException
193        {        
194            return executeBatch(this.batchParameters);
195        }
196        
197        protected int[] executeBatch(List batchParams) throws SQLException
198        {
199            int[] results = new int[batchParams.size()];
200            if(isQuery(getSQL()))
201            {
202                throw new BatchUpdateException("SQL " + getSQL() + " returned a ResultSet.", null);
203            }
204            for(int ii = 0; ii < results.length; ii++)
205            {
206                Map currentParameters = (Map)batchParams.get(ii);
207                results[ii] = executeUpdate(currentParameters);
208            }
209            return results;
210        }
211    
212        public ResultSetMetaData getMetaData() throws SQLException
213        {
214            return new MockResultSetMetaData();
215        }
216    
217        public ParameterMetaData getParameterMetaData() throws SQLException
218        {
219            return parameterMetaData;
220        }
221    
222        public void setArray(int parameterIndex, Array array) throws SQLException
223        {
224            setObject(parameterIndex, array);
225        }
226    
227        public void setAsciiStream(int parameterIndex, InputStream stream, int length) throws SQLException
228        {
229            setObject(parameterIndex, stream);
230        }
231    
232        public void setBigDecimal(int parameterIndex, BigDecimal bigDecimal) throws SQLException
233        {
234            setObject(parameterIndex, bigDecimal);
235        }
236    
237        public void setBinaryStream(int parameterIndex, InputStream stream, int length) throws SQLException
238        {
239            setObject(parameterIndex, stream);
240        }
241    
242        public void setBlob(int parameterIndex, Blob blob) throws SQLException
243        {
244            setObject(parameterIndex, blob);
245        }
246    
247        public void setBoolean(int parameterIndex, boolean bool) throws SQLException
248        {
249            setObject(parameterIndex, new Boolean(bool));
250        }
251    
252        public void setByte(int parameterIndex, byte byteValue) throws SQLException
253        {
254            setObject(parameterIndex, new Byte(byteValue));
255        }
256    
257        public void setBytes(int parameterIndex, byte[] byteArray) throws SQLException
258        {
259            setObject(parameterIndex, byteArray);
260        }
261    
262        public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException
263        {
264            setObject(parameterIndex, reader);
265        }
266    
267        public void setClob(int parameterIndex, Clob clob) throws SQLException
268        {
269            setObject(parameterIndex, clob);
270        }
271    
272        public void setDate(int parameterIndex, Date date, Calendar calendar) throws SQLException
273        {
274            setObject(parameterIndex, date);
275        }
276    
277        public void setDate(int parameterIndex, Date date) throws SQLException
278        {
279            setObject(parameterIndex, date);
280        }
281    
282        public void setDouble(int parameterIndex, double doubleValue) throws SQLException
283        {
284            setObject(parameterIndex, new Double(doubleValue));
285        }
286    
287        public void setFloat(int parameterIndex, float floatValue) throws SQLException
288        {
289            setObject(parameterIndex, new Float(floatValue));
290        }
291    
292        public void setInt(int parameterIndex, int intValue) throws SQLException
293        {
294            setObject(parameterIndex, new Integer(intValue));
295        }
296    
297        public void setLong(int parameterIndex, long longValue) throws SQLException
298        {
299            setObject(parameterIndex, new Long(longValue));
300        }
301    
302        public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException
303        {
304            setObject(parameterIndex, null);
305        }
306    
307        public void setNull(int parameterIndex, int sqlType) throws SQLException
308        {
309            setObject(parameterIndex, null);
310        }
311    
312        public void setRef(int parameterIndex, Ref ref) throws SQLException
313        {
314            setObject(parameterIndex, ref);
315        }
316    
317        public void setShort(int parameterIndex, short shortValue) throws SQLException
318        {
319            setObject(parameterIndex, new Short(shortValue));
320        }
321    
322        public void setString(int parameterIndex, String string) throws SQLException
323        {
324            setObject(parameterIndex, string);
325        }
326    
327        public void setTime(int parameterIndex, Time time, Calendar calendar) throws SQLException
328        {
329            setObject(parameterIndex, time);
330        }
331    
332        public void setTime(int parameterIndex, Time time) throws SQLException
333        {
334            setObject(parameterIndex, time);
335        }
336    
337        public void setTimestamp(int parameterIndex, Timestamp timeStamp, Calendar cal) throws SQLException
338        {
339            setObject(parameterIndex, timeStamp);
340        }
341    
342        public void setTimestamp(int parameterIndex, Timestamp timeStamp) throws SQLException
343        {
344            setObject(parameterIndex, timeStamp);
345        }
346    
347        public void setUnicodeStream(int parameterIndex, InputStream stream, int length) throws SQLException
348        {
349            setObject(parameterIndex, stream);
350        }
351    
352        public void setURL(int parameterIndex, URL url) throws SQLException
353        {
354            setObject(parameterIndex, url);
355        }
356        
357        private Map getParameterMapCopy(Map actualParameters)
358        {
359            Map copyParameters = new HashMap();
360            Iterator keys = actualParameters.keySet().iterator();
361            while(keys.hasNext())
362            {
363                    Object key = keys.next();
364                    Object actualParameter = actualParameters.get(key);
365                    Object copyParameter = ParameterUtil.copyParameter(actualParameter);
366                            copyParameters.put(key, copyParameter);
367            }
368            return copyParameters;
369        }
370    }