1 18 19 package org.apache.beehive.controls.system.jdbc.parser; 20 21 import org.apache.beehive.controls.api.ControlException; 22 import org.apache.beehive.controls.api.context.ControlBeanContext; 23 import org.apache.beehive.controls.system.jdbc.JdbcControl; 24 import org.apache.beehive.controls.system.jdbc.TypeMappingsFactory; 25 26 import javax.sql.RowSet ; 27 import java.io.Serializable ; 28 import java.lang.reflect.Method ; 29 import java.sql.CallableStatement ; 30 import java.sql.Connection ; 31 import java.sql.DatabaseMetaData ; 32 import java.sql.PreparedStatement ; 33 import java.sql.SQLException ; 34 import java.sql.Statement ; 35 import java.sql.Types ; 36 import java.util.Calendar ; 37 38 41 public final class SqlStatement extends SqlFragmentContainer implements Serializable { 42 43 private static final TypeMappingsFactory _tmf = TypeMappingsFactory.getInstance(); 44 private boolean _callableStatement = false; 45 private boolean _cacheableStatement = true; 46 47 private boolean _batchUpdate; 51 private boolean _getGeneratedKeys; 52 private String [] _genKeyColumnNames; 53 private int _fetchSize; 54 private int _maxArray; 55 private int _maxRows; 56 private int[] _genKeyColumnIndexes; 57 private JdbcControl.ScrollType _scrollType; 58 private JdbcControl.FetchDirection _fetchDirection; 59 private JdbcControl.HoldabilityType _holdability; 60 61 64 SqlStatement() { 65 super(); 66 } 67 68 73 void addChild(SqlFragment frag) { 74 super.addChild(frag); 75 76 if (frag.isDynamicFragment()) { 77 _cacheableStatement = false; 78 } 79 } 80 81 82 87 boolean isCacheable() { return _cacheableStatement; } 88 89 90 95 public boolean isCallableStatement() { return _callableStatement; } 96 97 102 public boolean isBatchUpdate() { return _batchUpdate; } 103 104 109 public boolean getsGeneratedKeys() { return _getGeneratedKeys; } 110 111 122 public PreparedStatement createPreparedStatement(ControlBeanContext context, Connection connection, 123 Calendar calendar, Method method, Object [] arguments) 124 throws SQLException { 125 126 PreparedStatement preparedStatement = null; 127 loadSQLAnnotationStatmentOptions(context, method); 128 checkJdbcSupport(connection.getMetaData()); 129 130 _callableStatement = setCallableStatement(arguments); 131 132 try { 133 final String sql = getPreparedStatementText(context, method, arguments); 134 135 if (_getGeneratedKeys) { 139 140 if (_callableStatement) { 141 throw new ControlException("getGeneratedKeys not supported for CallableStatements"); 142 } 143 144 if (_genKeyColumnNames.length > 0) { 145 preparedStatement = connection.prepareStatement(sql, _genKeyColumnNames); 146 } else if (_genKeyColumnIndexes.length > 0) { 147 preparedStatement = connection.prepareStatement(sql, _genKeyColumnIndexes); 148 } else { 149 preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); 150 } 151 152 } else { 153 154 if (_holdability == JdbcControl.HoldabilityType.DRIVER_DEFAULT) { 155 if (_scrollType == JdbcControl.ScrollType.DRIVER_DEFAULT) { 156 preparedStatement = (_callableStatement) ? connection.prepareCall(sql) : connection.prepareStatement(sql); 157 } else { 158 preparedStatement = (_callableStatement) 159 ? connection.prepareCall(sql, _scrollType.getType(), _scrollType.getConcurrencyType()) 160 : connection.prepareStatement(sql, _scrollType.getType(), _scrollType.getConcurrencyType()); 161 } 162 } else { 163 preparedStatement = (_callableStatement) 164 ? connection.prepareCall(sql, _scrollType.getType(), _scrollType.getConcurrencyType(), _holdability.getHoldability()) 165 : connection.prepareStatement(sql, _scrollType.getType(), _scrollType.getConcurrencyType(), _holdability.getHoldability()); 166 } 167 } 168 169 if (_callableStatement) { 173 for (SqlFragment sf : _children) { 174 if (sf.hasParamValue()) { 175 throw new ControlException("Cannot use parameter substution and SQLParameter array in the same method."); 176 } 177 } 178 JdbcControl.SQLParameter[] params = (JdbcControl.SQLParameter[]) arguments[0]; 179 if (params == null) { 180 return preparedStatement; 181 } 182 for (int i = 0; i < params.length; i++) { 183 JdbcControl.SQLParameter p = params[i]; 184 if (p.dir != JdbcControl.SQLParameter.OUT) { 185 Object value = params[i].value; 186 setPreparedStatementParameter(preparedStatement, i + 1, value, params[i].type, calendar); 187 } 188 189 if (p.dir != JdbcControl.SQLParameter.IN) { 190 ((CallableStatement ) preparedStatement).registerOutParameter(i + 1, params[i].type); 191 } 192 } 193 194 195 } else if (_batchUpdate) { 199 doBatchUpdate(preparedStatement, arguments, calendar); 200 201 202 } else { 206 int pIndex = 1; 207 for (SqlFragment sf : _children) { 208 if (sf.hasParamValue()) { 209 Object values[] = sf.getParameterValues(context, method, arguments); 210 for (Object value : values) { 211 setPreparedStatementParameter(preparedStatement, pIndex++, value, sf.getParamSqlDataType(), calendar); 212 } 213 } 214 } 215 } 216 } catch (SQLException e) { 217 if (preparedStatement != null) preparedStatement.close(); 218 throw e; 219 } 220 221 preparedStatement.setFetchDirection(_fetchDirection.getDirection()); 222 preparedStatement.setFetchSize(_fetchSize); 223 preparedStatement.setMaxRows(computeMaxRows(method)); 224 225 return preparedStatement; 226 } 227 228 237 public String createPreparedStatementString(ControlBeanContext context, Connection connection, 238 Method method, Object [] arguments) { 239 240 final boolean callableStatement = setCallableStatement(arguments); 241 StringBuilder sqlString = new StringBuilder (getPreparedStatementText(context, method, arguments)); 242 243 if (callableStatement) { 244 JdbcControl.SQLParameter[] params = (JdbcControl.SQLParameter[]) arguments[0]; 245 if (params == null) { 246 return sqlString.toString(); 247 } 248 249 sqlString.append(" Params: {"); 250 for (int i = 0; i < params.length; i++) { 251 if (i > 0) { sqlString.append(params[i].value.toString()); } 252 } 253 sqlString.append("}"); 254 255 } else if (_batchUpdate) { 256 sqlString.append(" Params: batch update."); 257 258 } else { 259 sqlString.append(" Params: {"); 260 boolean first = true; 261 for (SqlFragment sf : _children) { 262 if (sf.hasParamValue()) { 263 Object values[] = sf.getParameterValues(context, method, arguments); 264 for (Object value : values) { 265 266 if (!first) sqlString.append(", "); else first = false; 267 sqlString.append(value); 268 } 269 } 270 } 271 sqlString.append("}"); 272 } 273 return sqlString.toString(); 274 } 275 276 277 279 289 private void setPreparedStatementParameter(PreparedStatement ps, int i, Object value, int sqlType, Calendar cal) 290 throws SQLException { 291 292 if (sqlType == Types.NULL) { 293 sqlType = _tmf.getSqlType(value); 294 } 295 296 if (value == null) { 297 ps.setNull(i, Types.NULL == sqlType ? Types.VARCHAR : sqlType); 298 return; 299 } 300 301 switch (sqlType) { 302 303 case Types.VARCHAR: 304 if (!(value instanceof String )) value = value.toString(); 305 break; 306 307 case Types.BOOLEAN: 308 if (value instanceof Boolean ) { 309 ps.setBoolean(i, ((Boolean ) value).booleanValue()); 310 return; 311 } 312 break; 313 314 case Types.TIMESTAMP: 315 if (value instanceof java.util.Calendar ) { 316 Calendar calValue = (Calendar ) value; 317 318 value = new java.sql.Timestamp (calValue.getTimeInMillis()); 335 } else if (java.util.Date .class.equals(value.getClass())) { 337 value = new java.sql.Timestamp (((java.util.Date ) value).getTime()); 339 } 340 341 if (value instanceof java.sql.Timestamp ) { 342 if (cal == null) 343 ps.setTimestamp(i, (java.sql.Timestamp ) value); 344 else 345 ps.setTimestamp(i, (java.sql.Timestamp ) value, cal); 346 return; 347 } 348 break; 349 350 case Types.DATE: 351 if (value instanceof java.util.Calendar ) { 352 358 Calendar calValue = (Calendar ) value; 359 360 value = new java.sql.Date (calValue.getTimeInMillis()); 367 } else if (value.getClass() == java.util.Date .class) { 369 value = new java.sql.Date (((java.util.Date ) value).getTime()); 371 } 372 373 if (value instanceof java.sql.Date ) { 374 if (cal == null) { 375 ps.setDate(i, (java.sql.Date ) value); 376 } else { 377 ps.setDate(i, (java.sql.Date ) value, cal); 378 } 379 return; 380 } 381 break; 382 383 case Types.TIME: 384 if (value instanceof java.sql.Time ) { 385 if (cal == null) { 386 ps.setTime(i, (java.sql.Time ) value); 387 } else { 388 ps.setTime(i, (java.sql.Time ) value, cal); 389 } 390 return; 391 } 392 break; 393 } 394 395 if (sqlType == Types.NULL) { 396 ps.setObject(i, value); 397 } else { 398 ps.setObject(i, value, sqlType); 399 } 400 } 401 402 408 private boolean setCallableStatement(Object [] args) { 409 410 if (args != null && args.length == 1 && args[0] != null) { 412 Class argClass = args[0].getClass(); 413 if (argClass.isArray() && JdbcControl.SQLParameter.class.isAssignableFrom(argClass.getComponentType())) { 414 return true; 415 } 416 } 417 return false; 418 } 419 420 428 private void doBatchUpdate(PreparedStatement ps, Object [] args, Calendar cal) throws SQLException { 429 430 final int[] sqlTypes = new int[args.length]; 431 final Object [] objArrays = new Object [args.length]; 432 433 for (int i = 0; i < args.length; i++) { 435 sqlTypes[i] = _tmf.getSqlType(args[i].getClass().getComponentType()); 436 objArrays[i] = TypeMappingsFactory.toObjectArray(args[i]); 437 } 438 439 final int rowCount = ((Object []) objArrays[0]).length; 440 for (int i = 0; i < rowCount; i++) { 441 for (int j = 0; j < args.length; j++) { 442 setPreparedStatementParameter(ps, j + 1, ((Object []) objArrays[j])[i], sqlTypes[j], cal); 443 } 444 ps.addBatch(); 445 } 446 } 447 448 454 private void loadSQLAnnotationStatmentOptions(ControlBeanContext context, Method method) { 455 456 final JdbcControl.SQL methodSQL = (JdbcControl.SQL) context.getMethodPropertySet(method, JdbcControl.SQL.class); 457 458 _batchUpdate = methodSQL.batchUpdate(); 459 _getGeneratedKeys = methodSQL.getGeneratedKeys(); 460 _genKeyColumnNames = methodSQL.generatedKeyColumnNames(); 461 _genKeyColumnIndexes = methodSQL.generatedKeyColumnIndexes(); 462 _scrollType = methodSQL.scrollableResultSet(); 463 _fetchDirection = methodSQL.fetchDirection(); 464 _fetchSize = methodSQL.fetchSize(); 465 _maxRows = methodSQL.maxRows(); 466 _maxArray = methodSQL.arrayMaxLength(); 467 468 _holdability = methodSQL.resultSetHoldabilityOverride(); 469 } 470 471 477 private void checkJdbcSupport(DatabaseMetaData metaData) throws SQLException { 478 479 if (_getGeneratedKeys && !metaData.supportsGetGeneratedKeys()) { 480 throw new ControlException("The database does not support getGeneratedKeys."); 481 } 482 483 if (_batchUpdate && !metaData.supportsBatchUpdates()) { 484 throw new ControlException("The database does not support batchUpdates."); 485 } 486 487 if (_scrollType != JdbcControl.ScrollType.DRIVER_DEFAULT 488 && !metaData.supportsResultSetConcurrency(_scrollType.getType(), _scrollType.getConcurrencyType())) { 489 throw new ControlException("The database does not support the ResultSet concurrecy type: " + _scrollType.toString()); 490 } 491 492 if (_holdability != JdbcControl.HoldabilityType.DRIVER_DEFAULT 493 && !metaData.supportsResultSetHoldability(_holdability.getHoldability())) { 494 throw new ControlException("The database does not support the ResultSet holdability type: " + _holdability.toString()); 495 } 496 } 497 498 506 private int computeMaxRows(Method method) { 507 508 Class returnType = method.getReturnType(); 509 510 final boolean isArray = returnType.isArray(); 511 final boolean isRowSet = returnType.equals(RowSet .class); 512 513 int maxSet = _maxRows; 514 if (isArray && _maxArray != JdbcControl.MAXROWS_ALL) { 515 maxSet = _maxRows == JdbcControl.MAXROWS_ALL ? _maxArray + 1 : Math.min(_maxArray + 1, _maxRows); 516 } else if (isRowSet && _maxRows > 0) { 517 maxSet = _maxRows + 1; 518 } 519 520 return maxSet; 521 } 522 } 523 | Popular Tags |