001: /*
002: * Created on Jun 24, 2004
003: */
004: package net.sourceforge.orbroker;
005:
006: import java.sql.CallableStatement;
007: import java.sql.Connection;
008: import java.sql.ParameterMetaData;
009: import java.sql.ResultSet;
010: import java.sql.SQLException;
011:
012: /**
013: * @author Nils Kilden-Pedersen
014: */
015: final class StoredProcedureCall extends StaticStatement {
016:
017: /**
018: * Is statement a stored procedure call?
019: * @param statement
020: * @return true, if it's a CALL
021: */
022: static boolean isProcedureCall(String statement) {
023: if (statement.length() > 4) {
024: statement = statement.substring(0, 4).toUpperCase();
025: }
026: return statement.startsWith("CALL")
027: || statement.startsWith("{")
028: || statement.startsWith(":")
029: || statement.startsWith("}");
030: }
031:
032: /**
033: * Constructor.
034: * @param id
035: * @param statement
036: * @param resultObjectDef
037: */
038: StoredProcedureCall(String id, String statement,
039: ResultObjectDefinition resultObjectDef) {
040: super (id, statement, resultObjectDef);
041: }
042:
043: /**
044: * For stored procedure calls.
045: * @param context
046: * @param cs
047: * @param parsed
048: * @return Parameter OUTPUT status
049: * @throws SQLException
050: */
051: private boolean[] attachParameterValues(ConnectionContext context,
052: CallableStatement cs, ImmutableSQL parsed)
053: throws SQLException {
054:
055: ParameterMetaData metaData = cs.getParameterMetaData();
056: int parmCount = metaData.getParameterCount();
057: if (parmCount != parsed.getParameterCount()) {
058: throw new BrokerException("Metadata parameter count of "
059: + parmCount + " does not match actual count of "
060: + parsed.getParameterCount());
061: }
062:
063: boolean[] isParameterOutput = new boolean[parmCount];
064: for (int i = 0, parameterIndex = 1; i < parmCount; i++, parameterIndex++) {
065: String treePath = parsed.getParameterName(i);
066: int mode = metaData.getParameterMode(parameterIndex);
067: if (mode == ParameterMetaData.parameterModeIn
068: || mode == ParameterMetaData.parameterModeInOut) {
069: Object parmValue = context.getParameterValue(treePath);
070: setColumnValue(cs, parmValue, parameterIndex);
071: }
072: isParameterOutput[i] = (mode == ParameterMetaData.parameterModeInOut || mode == ParameterMetaData.parameterModeOut);
073: if (isParameterOutput[i]) {
074: cs.registerOutParameter(parameterIndex, metaData
075: .getParameterType(parameterIndex));
076: }
077: }
078: return isParameterOutput;
079: }
080:
081: private CallableStatement buildCallableStatement(Connection con,
082: boolean scrollableSupport, ImmutableSQL parsedSQL)
083: throws SQLException {
084:
085: String statement = parsedSQL.getSqlStatement();
086: logSqlStatement(statement);
087: return con.prepareCall(statement, Broker
088: .getResultSetType(scrollableSupport),
089: ResultSet.CONCUR_READ_ONLY);
090: }
091:
092: /**
093: * @param context
094: * @param cs
095: * @param parsedSQL
096: * @param isParameterOutput
097: * @throws SQLException
098: */
099: private void setOutputParameters(ConnectionContext context,
100: CallableStatement cs, ImmutableSQL parsedSQL,
101: boolean[] isParameterOutput) throws SQLException {
102: ResultSet resultSet = new ResultParameters(cs,
103: isParameterOutput, parsedSQL.copyParameterNames());
104: ResultRow row = new ResultRow(resultSet, context, cs
105: .getConnection());
106: setValuesOnMap(context.getParametersAsMap(), row);
107: }
108:
109: /**
110: * @inheritDoc
111: * @throws SQLException
112: */
113: int[] executeBatch(Connection con, ConnectionContext context,
114: String batchParameterName, Object[] batchParameters)
115: throws SQLException {
116:
117: ImmutableSQL sql = getRunnableSQL(context);
118:
119: CallableStatement cs = buildCallableStatement(con, false, sql);
120: try {
121: for (int i = 0; i < batchParameters.length; i++) {
122: context.setParameter(batchParameterName,
123: batchParameters[i]);
124: attachParameterValues(context, cs, sql);
125: cs.addBatch();
126: }
127: context.removeParameter(batchParameterName);
128: return cs.executeBatch();
129: } finally {
130: closeStatement(cs);
131: }
132: }
133:
134: /**
135: *
136: * @inheritDoc
137: * @throws SQLException
138: */
139: QueryResult executeQuery(Connection con, boolean scrollableSupport,
140: ConnectionContext context) throws SQLException {
141:
142: ImmutableSQL parsedSQL = getRunnableSQL(context);
143: CallableStatement cs = buildCallableStatement(con,
144: scrollableSupport, parsedSQL);
145: boolean[] isParameterOutput = attachParameterValues(context,
146: cs, parsedSQL);
147: ResultSet resultSet;
148: cs.execute();
149:
150: try {
151: resultSet = cs.getResultSet();
152: } catch (SQLException e) {
153: resultSet = null;
154: }
155:
156: ResultSet outputParameters = new ResultParameters(cs,
157: isParameterOutput, parsedSQL.copyParameterNames());
158:
159: if (resultSet == null) {
160: resultSet = outputParameters;
161: outputParameters = null;
162: }
163: return new QueryResult(cs, resultSet, context, outputParameters);
164: }
165:
166: /**
167: * @inheritDoc
168: * @see net.sourceforge.orbroker.Statement#executeUpdate(java.sql.Connection, net.sourceforge.orbroker.ConnectionContext)
169: */
170: int executeUpdate(Connection con, ConnectionContext context)
171: throws SQLException {
172:
173: ImmutableSQL parsedSql = getRunnableSQL(context);
174: CallableStatement cs = buildCallableStatement(con, false,
175: parsedSql);
176: try {
177: boolean[] isParameterOutput = attachParameterValues(
178: context, cs, parsedSql);
179: int rowsAffected = cs.executeUpdate();
180: setOutputParameters(context, cs, parsedSql,
181: isParameterOutput);
182: return rowsAffected;
183: } finally {
184: closeStatement(cs);
185: }
186: }
187: }
|