View Javadoc

1   /***
2    * License Agreement.
3    * 
4    * JSPA (POJO-SP)
5    * 
6    * Copyright (C) 2009 HRX Pty Ltd
7    * 
8    * This file is part of JSPA.
9    * 
10   * JSPA is free software: you can redistribute it and/or modify it under the
11   * terms of the GNU Lesser General Public License version 3 as published by the
12   * Free Software Foundation.
13   * 
14   * JSPA is distributed in the hope that it will be useful, but WITHOUT ANY
15   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16   * A PARTICULAR PURPOSE. See the Lesser General Public License for more details.
17   * 
18   * You should have received a copy of the GNU Lesser General Public License
19   * along with JSPA. If not, see <http://www.gnu.org/licenses/>.
20   */
21  package com.hrx.rasp.util.dao.operation;
22  
23  import java.io.InputStream;
24  import java.lang.reflect.Field;
25  import java.lang.reflect.InvocationTargetException;
26  import java.sql.Array;
27  import java.sql.Blob;
28  import java.sql.CallableStatement;
29  import java.sql.Clob;
30  import java.sql.Connection;
31  import java.sql.SQLException;
32  import java.sql.Timestamp;
33  import java.sql.Types;
34  import java.util.Collection;
35  import java.util.Set;
36  
37  import org.apache.log4j.Logger;
38  
39  import com.hrx.rasp.util.dao.ExpressionBuilder;
40  import com.hrx.rasp.util.dao.NullValue;
41  import com.hrx.rasp.util.dao.OracleHelper;
42  import com.hrx.rasp.util.dao.StoredProcUtility;
43  import com.hrx.rasp.util.dao.annotations.IN;
44  import com.hrx.rasp.util.dao.annotations.INOUT;
45  import com.hrx.rasp.util.dao.annotations.OUT;
46  import com.hrx.rasp.util.dao.annotations.Secret;
47  import com.hrx.rasp.util.dao.exception.StoredProcedureException;
48  import com.hrx.rasp.util.dao.exception.StoredProcedurePrepareException;
49  import com.hrx.rasp.util.dao.exception.StoredProcedureReservedIndexException;
50  import com.hrx.rasp.util.dao.metadata.MetadataHelper;
51  import com.hrx.rasp.util.dao.metadata.StoredProcField;
52  import com.hrx.rasp.util.dao.metadata.StoredProcMetaDataImpl;
53  import com.hrx.rasp.util.dao.metadata.StoredProcPkMetaData;
54  
55  /***
56   * @author dan.stoica <dan.stoica@acslink.net.au>
57   *
58   * Description for StatementBuilder class
59   * 
60   */
61  public final class StatementBuilder {
62  	private final static Logger log = Logger.getLogger(StatementBuilder.class);
63  
64  	public static final String PK_NOT_FOUND = "Primary key not found";
65  	public static final String IN_PARAMETERS_OR_PK_NOT_FOUND = "IN parameters or Primary key not found";
66  	static final String PARAMETER_INDEX_IS_RESERVED = "Parameter index is reserved. Parameter name:";
67  	public static final String IN_PARAM_NOT_FOUND_FOR_SELECT_SP = "Parameters IN not found for Select Stored Procedure";
68  
69  	/***
70  	 * Description for setObject method
71  	 * 
72  	 * @param st
73  	 *            CallableStatement
74  	 * @param index
75  	 *            int
76  	 * @param arg
77  	 *            Object
78  	 * @throws SQLException
79  	 */
80  	protected static void setObject(final CallableStatement st, int index,
81  			final Object arg) throws SQLException {
82  		if (arg instanceof NullValue)
83  			setNullValue(st, index, (NullValue) arg);
84  		else
85  			st.setObject(index, arg);
86  	}
87  
88  	/***
89  	 * Register a given list of DAO properties as stored procedure OUT
90  	 * parameters
91  	 * 
92  	 * @param st
93  	 * @param allFields
94  	 * @throws SQLException
95  	 */
96  	protected static void registerOutParameters(final CallableStatement st,
97  			final Collection<StoredProcField<OUT>> outFields)
98  			throws SQLException {
99  		for (StoredProcField<OUT> field : outFields) {
100 			OUT parameter = field.getParameter();
101 			registerOutParameters(st, parameter.index(), parameter.sqlType(),
102 					field.getField(), parameter.sqlArrayName());
103 		}
104 	}
105 
106 	/***
107 	 * Register a given list of DAO properties as stored procedure OUT
108 	 * parameters
109 	 * 
110 	 * @param st
111 	 * @param allFields
112 	 * @throws SQLException
113 	 */
114 	protected static void registerInOutParameters(final CallableStatement st,
115 			final Collection<StoredProcField<INOUT>> outFields)
116 			throws SQLException {
117 		for (StoredProcField<INOUT> field : outFields) {
118 			INOUT parameter = field.getParameter();
119 			registerOutParameters(st, parameter.index(), parameter.sqlType(),
120 					field.getField(), parameter.sqlArrayName());
121 		}
122 	}
123 
124 	/***
125 	 * Register a DAO property as OUT stored procedure parameter
126 	 * 
127 	 * @param st
128 	 * @param index
129 	 * @param sqlType
130 	 * @param field
131 	 * @param sqlArrayName
132 	 * @throws SQLException
133 	 */
134 	private static void registerOutParameters(final CallableStatement st,
135 			int index, int sqlType, Field field, String sqlArrayName)
136 			throws SQLException {
137 		Class<?> javaType = field.getType();
138 
139 		if (sqlType == Types.NULL) {
140 			// try the guess the type
141 			sqlType = StoredProcUtility.getSQLType(javaType);
142 		}
143 
144 		if (sqlType == Types.ARRAY) {
145 			if (log.isDebugEnabled()) {
146 				log.debug("PREPARE: RegisterOutParameter parameter; index="
147 						+ index + ", type: 'ARRAY', arrayName=" + sqlArrayName);
148 			}
149 			st.registerOutParameter(index, Types.ARRAY, sqlArrayName);
150 		} else {
151 			// The Oracle JDBC drivers do not support the BOOLEAN parameters for
152 			// PL/SQL stored procedures.
153 			if (sqlType == Types.BOOLEAN
154 					&& st.getClass().toString().toLowerCase()
155 							.contains("oracle")) {
156 				if (log.isDebugEnabled()) {
157 					log
158 							.debug("PREPARE: RegisterOutParameter BOOLEAN parameter for Oracle; index="
159 									+ index + ", as type:'Types.VARCHAR'");
160 				}
161 				st.registerOutParameter(index, Types.VARCHAR);
162 			} else {
163 				if (log.isDebugEnabled()) {
164 					log.debug("RegisterOutParameter parameter; index=" + index
165 							+ ", type:'" + sqlType + "'");
166 				}
167 				st.registerOutParameter(index, sqlType);
168 			}
169 		}
170 	}
171 
172 	/***
173 	 * Description for setObject method
174 	 * 
175 	 * @param st
176 	 *            CallableStatement
177 	 * @param inParameters
178 	 * @param inoutParameters
179 	 * @param reservedIndex
180 	 *            - the first parameters can be reserved for error code , result
181 	 *            set, etc...
182 	 * @throws SQLException
183 	 * @throws StoredProcedureReservedIndexException
184 	 * @throws StoredProcedurePrepareException
185 	 */
186 	protected static void setInParameters(final CallableStatement st,
187 			Object spBean, int reservedIndex,
188 			final Collection<StoredProcField<IN>> inParameters)
189 			throws SQLException, StoredProcedureReservedIndexException,
190 			StoredProcedurePrepareException {
191 		for (StoredProcField<IN> param : inParameters) {
192 			try {
193 				Object value = MetadataHelper.getPropertyValue(
194 						param.getField(), spBean);
195 				int index = param.getParameter().index();
196 				String arrayName = param.getParameter().sqlArrayName();
197 
198 				if (log.isDebugEnabled()) {
199 					StringBuilder msg = new StringBuilder(
200 							"PREPARE: Set IN parameter. Field name="
201 									+ param.getName() + ", SP index=" + index
202 									+ ", value=");
203 					msg = param.getField().isAnnotationPresent(Secret.class) ? msg
204 							.append("*****")
205 							: msg.append(value);
206 					if (value instanceof Collection<?>)
207 						msg.append(", arrayName=" + arrayName);
208 					log.debug(msg);
209 				}
210 
211 				setInParameter(st, param, value, arrayName, index,
212 						reservedIndex);
213 			} catch (StoredProcedureReservedIndexException e) {
214 				throw e;
215 			} catch (Throwable e) {
216 				throw new StoredProcedurePrepareException(e);
217 			}
218 		}
219 	}
220 
221 	protected static void setInOutParameters(final CallableStatement st,
222 			Object spBean, int reservedIndex,
223 			final Collection<StoredProcField<INOUT>> inParameters)
224 			throws SQLException, StoredProcedureReservedIndexException,
225 			StoredProcedurePrepareException {
226 		for (StoredProcField<INOUT> param : inParameters) {
227 			try {
228 				Object value = MetadataHelper.getPropertyValue(
229 						param.getField(), spBean);
230 				int index = param.getParameter().index();
231 				String arrayName = param.getParameter().sqlArrayName();
232 
233 				if (log.isDebugEnabled()) {
234 					StringBuilder msg = new StringBuilder(
235 							"PREPARE: Set INOUT parameter. Field name="
236 									+ param.getName() + ", SP index=" + index
237 									+ ", value=");
238 					msg = param.getField().isAnnotationPresent(Secret.class) ? msg
239 							.append("*****")
240 							: msg.append(value);
241 					if (value instanceof Collection<?>)
242 						msg.append(", arrayName=" + arrayName);
243 					log.debug(msg);
244 				}
245 
246 				setInParameter(st, param, value, arrayName, index,
247 						reservedIndex);
248 			} catch (StoredProcedureReservedIndexException e) {
249 				throw e;
250 			} catch (Throwable e) {
251 				throw new StoredProcedurePrepareException(e);
252 			}
253 		}
254 	}
255 
256 	/***
257 	 * Description for setObject method
258 	 * 
259 	 * @param st
260 	 *            CallableStatement
261 	 * @param index
262 	 *            int
263 	 * @param arg
264 	 *            Object
265 	 * @throws SQLException
266 	 * @throws StoredProcedureReservedIndexException
267 	 * @throws StoredProcedurePrepareException
268 	 */
269 	protected static void setInParameter(final CallableStatement st,
270 			final StoredProcField<?> parameter, Object value, String arrayName,
271 			int index, int minIndex) throws SQLException,
272 			StoredProcedureReservedIndexException,
273 			StoredProcedurePrepareException {
274 		Class<?> objectType = value.getClass();
275 		// index is 1-based
276 
277 		if (index <= minIndex) {
278 			throw new StoredProcedureReservedIndexException(
279 					StatementBuilder.PARAMETER_INDEX_IS_RESERVED
280 							+ parameter.getName());
281 		}
282 		if (value instanceof NullValue) {
283 			setNullValue(st, index, (NullValue) value);
284 		} else if (value instanceof String) {
285 			st.setString(index, (String) value);
286 		} else if (value instanceof Integer || objectType == Integer.TYPE) {
287 			st.setInt(index, (Integer) value);
288 		} else if (value instanceof Long || objectType == Long.TYPE) {
289 			st.setLong(index, (Long) value);
290 		} else if (value instanceof Double || objectType == Double.TYPE) {
291 			st.setDouble(index, (Double) value);
292 		} else if (value instanceof Float || objectType == Float.TYPE) {
293 			st.setFloat(index, (Float) value);
294 		} else if (value instanceof Short || objectType == Short.TYPE) {
295 			st.setShort(index, (Short) value);
296 		} else if (value instanceof Boolean || objectType == Boolean.TYPE) {
297 			// The Oracle JDBC drivers do not support the BOOLEAN parameters for
298 			// PL/SQL stored procedures.
299 			if (st.getClass().toString().toLowerCase().contains("oracle")) {
300 				st.setString(index, Boolean.toString((Boolean) value));
301 			} else {
302 				st.setBoolean(index, (Boolean) value);
303 			}
304 		} else if (value instanceof Timestamp) {
305 			st.setTimestamp(index, (Timestamp) value);
306 		} else if (value instanceof java.util.Date) {
307 			java.sql.Date date = new java.sql.Date((((java.util.Date) value))
308 					.getTime());
309 			st.setDate(index, date);
310 		} else if (value instanceof java.sql.Date) {
311 			st.setDate(index, (java.sql.Date) value);
312 		} else if (value instanceof Clob) {
313 			st.setClob(index, (Clob) value);
314 		} else if (value instanceof Blob) {
315 			st.setBlob(index, (Blob) value);
316 		} else if (value instanceof Collection<?>) {
317 			setOracleArray(st, index, (Collection<?>) value, arrayName);
318 		} else if (value instanceof InputStream) {
319 			st.setBinaryStream(index, (InputStream) value);
320 		}
321 
322 	}
323 
324 	/***
325 	 * Description for setNullValue method
326 	 * 
327 	 * @param st
328 	 *            CallableStatement
329 	 * @param index
330 	 *            int
331 	 * @param nullValue
332 	 *            NullValue
333 	 * @throws SQLException
334 	 */
335 	public static void setNullValue(final CallableStatement st,
336 			final int index, final NullValue nullValue) throws SQLException {
337 		st.setNull(index, nullValue.getSQLType());
338 	}
339 
340 	private static void setOracleArray(final CallableStatement stmt, int index,
341 			Collection<?> values, String arrayType)
342 			throws StoredProcedurePrepareException, SQLException {
343 		if ("N/A".equals(arrayType)) {
344 			throw new StoredProcedurePrepareException(
345 					"Invalid database ARRAY TYPE name, for IN PARAMETER at index: "
346 							+ index);
347 		}
348 		Connection conn = stmt.getConnection();
349 		Array array = OracleHelper.createOracleARRAY(arrayType, values, conn);
350 		stmt.setArray(index, array);
351 	}
352 	
353 	
354 	/***
355 	 * Build the CallableStatement object for the desired insert query
356 	 * 
357 	 * @param conn
358 	 *            The database connection
359 	 * @param storedProc
360 	 *            The stored procedure
361 	 * @param pkClass
362 	 *            the expected class of the primary key
363 	 * @param args
364 	 *            The input values
365 	 * @return The callable statement that forms the insert query
366 	 * @throws StoredProcedureReservedIndexException
367 	 * @throws StoredProcedureException
368 	 */
369 	protected static CallableStatement getInsertStatement(
370 			final Connection conn, final String storedProc,
371 			final Collection<StoredProcField<IN>> inParameters,
372 			final Collection<StoredProcField<?>> pkParameters, Object spBean,
373 			Object pkBean, boolean isEmbeddedId)
374 			throws StoredProcedurePrepareException,
375 			StoredProcedureReservedIndexException {
376 		try {
377 			inParameters.removeAll(pkParameters);
378 			if (inParameters.size() == 0
379 					|| (isEmbeddedId && pkParameters.size() == 0)) {
380 				throw new StoredProcedurePrepareException(
381 						StatementBuilder.IN_PARAMETERS_OR_PK_NOT_FOUND);
382 			}
383 
384 			int params = pkParameters.size() + inParameters.size();
385 
386 			String stmtExpression = ExpressionBuilder.getInsert(storedProc,
387 					params);
388 			CallableStatement st = conn.prepareCall(stmtExpression);
389 
390 			// register the returned result code and primary key
391 			st.registerOutParameter(1, Types.INTEGER);
392 			st.registerOutParameter(2, Types.VARCHAR);
393 
394 			// index is 1-based and the first two indices are the
395 			// result code. Also there may be some other index used for primary
396 			// key
397 
398 			setInParameters(st, spBean, 2, inParameters);
399 
400 			// // register primary key parameters as INOUT parameters
401 			// registerInOutParameters(st, pkParameters);
402 			for (StoredProcField<?> param : pkParameters) {
403 				try {
404 					if (!isEmbeddedId) {
405 						pkBean = spBean;
406 					}
407 					setAndRegistreParameter(pkBean, st, param);
408 				} catch (StoredProcedureReservedIndexException e) {
409 					throw e;
410 				} catch (Throwable e) {
411 					throw new StoredProcedurePrepareException(e);
412 				}
413 			}
414 			return st;
415 		} catch (SQLException se) {
416 			throw new StoredProcedurePrepareException(se);
417 		}
418 	}
419 
420 	/***
421 	 * @param pkBean
422 	 * @param st
423 	 * @param param
424 	 * @throws NoSuchMethodException
425 	 * @throws IllegalAccessException
426 	 * @throws InvocationTargetException
427 	 * @throws SQLException
428 	 * @throws StoredProcedureReservedIndexException
429 	 */
430 	private static void setAndRegistreParameter(Object pkBean,
431 			CallableStatement st, StoredProcField<?> param)
432 			throws NoSuchMethodException, IllegalAccessException,
433 			InvocationTargetException, SQLException,
434 			StoredProcedureReservedIndexException,
435 			StoredProcedurePrepareException {
436 		Object value = MetadataHelper
437 				.getPropertyValue(param.getField(), pkBean);
438 		if (param.getParameter() instanceof INOUT) {
439 			INOUT p = (INOUT) param.getParameter();
440 			int index = p.index();
441 			setInParameter(st, param, value, p.sqlArrayName(), index, 2);
442 			registerOutParameters(st, index, p.sqlType(), param.getField(), p
443 					.sqlArrayName());
444 		} else if (param.getParameter() instanceof IN) {
445 			IN p = (IN) param.getParameter();
446 			int index = p.index();
447 			setInParameter(st, param, value, p.sqlArrayName(), index, 2);
448 		} else if (param.getParameter() instanceof OUT) {
449 			OUT p = (OUT) param.getParameter();
450 			int index = p.index();
451 			registerOutParameters(st, index, p.sqlType(), param.getField(), p
452 					.sqlArrayName());
453 		}
454 	}
455 
456 	/***
457 	 * Build the CallableStatement object for the desired update query
458 	 * 
459 	 * @param conn
460 	 *            The database connection
461 	 * @param storedProc
462 	 *            The stored procedure
463 	 * @param args
464 	 *            The input values
465 	 * @return The callable statement that forms the update query
466 	 * @throws StoredProcedureReservedIndexException
467 	 * @throws StoredProcedureException
468 	 */
469 	protected static CallableStatement getUpdateStatement(
470 			final Connection conn, final String storedProc,
471 			final Collection<StoredProcField<IN>> inParameters,
472 			final Collection<StoredProcField<IN>> pkParameters,
473 			final Object spBean, final Object pkBean, boolean isEmbeddedId)
474 			throws StoredProcedurePrepareException,
475 			StoredProcedureReservedIndexException {
476 		try {
477 			if (inParameters.size() == 0 || pkParameters.size() == 0) {
478 				throw new StoredProcedurePrepareException(
479 						StatementBuilder.IN_PARAMETERS_OR_PK_NOT_FOUND);
480 			}
481 
482 			int totalParams = inParameters.size();
483 
484 			if (isEmbeddedId) {
485 				totalParams = totalParams + pkParameters.size();
486 			}
487 
488 			String stmtExpression = ExpressionBuilder.getUpdate(storedProc,
489 					totalParams);
490 			CallableStatement st = conn.prepareCall(stmtExpression);
491 
492 			// register the returned result code
493 			st.registerOutParameter(1, Types.INTEGER);
494 			st.registerOutParameter(2, Types.VARCHAR);
495 
496 			// index is 1-based; The first two indices are the
497 			// result code and result info
498 			setInParameters(st, spBean, 2, inParameters);
499 
500 			// Set primary key parameters if there it is a separate PK object
501 			// For not embeddedId the PK parameters are IN parameters too.
502 			if (isEmbeddedId) {
503 				setInParameters(st, pkBean, 2, pkParameters);
504 			}
505 
506 			return st;
507 		} catch (SQLException se) {
508 			throw new StoredProcedurePrepareException(se);
509 		}
510 	}
511 
512 	/***
513 	 * Build the CallableStatement object for the desired update query
514 	 * 
515 	 * @param conn
516 	 *            The database connection
517 	 * @param storedProc
518 	 *            The stored procedure
519 	 * @param args
520 	 *            The input values
521 	 * @return The callable statement that forms the update query
522 	 * @throws StoredProcedureReservedIndexException
523 	 * @throws StoredProcedureException
524 	 */
525 	protected static CallableStatement getDeleteStatement(
526 			final Connection conn, final String storedProc,
527 			final Collection<StoredProcField<IN>> pkParameters,
528 			final Object pkBean) throws StoredProcedurePrepareException,
529 			StoredProcedureReservedIndexException {
530 		try {
531 			if (pkParameters.size() == 0) {
532 				throw new StoredProcedurePrepareException(
533 						StatementBuilder.PK_NOT_FOUND);
534 			}
535 			String stmtExpression = ExpressionBuilder.getUpdate(storedProc,
536 					pkParameters.size());
537 			CallableStatement st = conn.prepareCall(stmtExpression);
538 
539 			// register the returned result code
540 			st.registerOutParameter(1, Types.INTEGER);
541 			st.registerOutParameter(2, Types.VARCHAR);
542 
543 			// index is 1-based; The first two indices are the
544 			// result code and result info
545 			setInParameters(st, pkBean, 2, pkParameters);
546 			return st;
547 		} catch (SQLException se) {
548 			throw new StoredProcedurePrepareException(se);
549 		}
550 	}
551 
552 	/***
553 	 * Build the CallableStatement object for the desired select query
554 	 * 
555 	 * @param conn
556 	 *            The database connection
557 	 * @param storedProc
558 	 *            The stored procedure
559 	 * @param inParameters
560 	 *            The input values
561 	 * @return The CallableStatement that forms the select query
562 	 * @throws StoredProcedureReservedIndexException
563 	 * @throws StoredProcedureException
564 	 */
565 	public static CallableStatement getSelectStatement(final Connection conn,
566 			final String storedProc,
567 			final Set<StoredProcField<IN>> inParameters,
568 			final Set<StoredProcField<IN>> pkInParameters, Object spBean,
569 			Object pkBean, boolean isEmbeddedId)
570 			throws StoredProcedurePrepareException,
571 			StoredProcedureReservedIndexException {
572 		try {
573 			// we have no restriction for in parameter. The Stored procedure can
574 			// have no in parameters for a Select ALL operation.
575 			int argc = inParameters.size();
576 			if (isEmbeddedId) {
577 				argc = argc + pkInParameters.size();
578 			}
579 
580 			String stmtExpression = ExpressionBuilder.getSelect(storedProc,
581 					argc);
582 			CallableStatement st = conn.prepareCall(stmtExpression);
583 
584 			// register the returned cursor and return code
585 			st.registerOutParameter(1, OracleHelper.ORACLE_CURSOR);
586 			st.registerOutParameter(2, Types.INTEGER);
587 			st.registerOutParameter(3, Types.VARCHAR);
588 
589 			// index is 1-based and the first tree indices are the
590 			// returned cursor, result code and the result text
591 			setInParameters(st, spBean, 3, inParameters);
592 			if (isEmbeddedId) {
593 				setInParameters(st, pkBean, 3, pkInParameters);
594 			}
595 			return st;
596 		} catch (SQLException se) {
597 			throw new StoredProcedurePrepareException(se);
598 		}
599 	}
600 
601 	/***
602 	 * Build the CallableStatement object for the desired select query
603 	 * 
604 	 * @param conn
605 	 *            The database connection
606 	 * @param storedProc
607 	 *            The stored procedure
608 	 * @param inParameters
609 	 *            The input values
610 	 * @return The CallableStatement that forms the select query
611 	 * @throws StoredProcedureReservedIndexException
612 	 * @throws StoredProcedureException
613 	 */
614 	public static CallableStatement getFindStatement(final Connection conn,
615 			final String storedProc,
616 			final Set<StoredProcField<IN>> pkParameters,
617 			final Set<StoredProcField<OUT>> outParameters, Object spBean,
618 			Object pkBean, boolean isEmbeddedId)
619 			throws StoredProcedurePrepareException,
620 			StoredProcedureReservedIndexException {
621 		try {
622 			if (pkParameters.size() == 0) {
623 				throw new StoredProcedurePrepareException(
624 						IN_PARAM_NOT_FOUND_FOR_SELECT_SP);
625 			}
626 			int argc = pkParameters.size() + outParameters.size();
627 			String stmtExpression = ExpressionBuilder.getFind(storedProc, argc);
628 			CallableStatement st = conn.prepareCall(stmtExpression);
629 
630 			// register the returned return code and text
631 			st.registerOutParameter(1, Types.INTEGER);
632 			st.registerOutParameter(2, Types.VARCHAR);
633 
634 			// index is 1-based and the first tree indices are the
635 			// returned cursor, result code and the primary key
636 			if (isEmbeddedId) {
637 				setInParameters(st, pkBean, 2, pkParameters);
638 			} else {
639 				setInParameters(st, spBean, 2, pkParameters);
640 			}
641 
642 			registerOutParameters(st, outParameters);
643 
644 			return st;
645 		} catch (SQLException se) {
646 			throw new StoredProcedurePrepareException(se);
647 		}
648 	}
649 
650 	/***
651 	 * Build the CallableStatement object for the desired function call
652 	 * 
653 	 * @param conn
654 	 * @param spBean
655 	 * @param meta
656 	 * @return
657 	 * @throws StoredProcedurePrepareException
658 	 * @throws StoredProcedureReservedIndexException
659 	 */
660 	public static CallableStatement getFunctionCall(final Connection conn,
661 			Object spBean, Object pkBean, final StoredProcMetaDataImpl meta,
662 			final StoredProcPkMetaData embeddedMeta, boolean embedded)
663 			throws StoredProcedurePrepareException,
664 			StoredProcedureReservedIndexException {
665 		return getStoredProcedureCall(conn, spBean, pkBean, meta, embeddedMeta,
666 				embedded, true);
667 	}
668 
669 	public static CallableStatement getStoredProcedureCall(
670 			final Connection conn, Object spBean, Object pkBean,
671 			final StoredProcMetaDataImpl meta,
672 			final StoredProcPkMetaData embeddedMeta, boolean embedded,
673 			boolean isFunction) throws StoredProcedurePrepareException,
674 			StoredProcedureReservedIndexException {
675 		final String storedProc = meta.getStoredProcName();
676 		final Set<StoredProcField<IN>> inParameters = meta.getInParameters();
677 		final Set<StoredProcField<OUT>> ourParams = meta.getOutParameters();
678 		final Set<StoredProcField<INOUT>> inoutParameters = meta
679 				.getInOutParameters();
680 		try {
681 			int argc = inParameters.size() + ourParams.size()
682 					+ inoutParameters.size();
683 			if (embedded) {
684 				argc = argc + embeddedMeta.getInParameters().size()
685 						+ embeddedMeta.getOutParameters().size()
686 						+ embeddedMeta.getOutParameters().size();
687 			}
688 
689 			CallableStatement st = null;
690 			if (isFunction) {
691 				st = conn.prepareCall(ExpressionBuilder.getFunctionCall(
692 						storedProc, argc));
693 			} else {
694 				st = conn.prepareCall(ExpressionBuilder.getStoredProcedureCall(
695 						storedProc, argc));
696 			}
697 
698 			setInParameters(st, spBean, 0, inParameters);
699 			setInOutParameters(st, spBean, 0, inoutParameters);
700 			if (embedded) {
701 				setInParameters(st, pkBean, 0, embeddedMeta.getInParameters());
702 				setInOutParameters(st, pkBean, 0, embeddedMeta
703 						.getInOutParameters());
704 			}
705 			registerOutParameters(st, ourParams);
706 			registerInOutParameters(st, inoutParameters);
707 
708 			return st;
709 
710 		} catch (SQLException se) {
711 			throw new StoredProcedurePrepareException(se);
712 		}
713 	}
714 }