1 56 package org.objectstyle.cayenne.dba.oracle; 57 58 import java.io.OutputStream ; 59 import java.io.Writer ; 60 import java.lang.reflect.InvocationTargetException ; 61 import java.lang.reflect.Method ; 62 import java.sql.Blob ; 63 import java.sql.Clob ; 64 import java.sql.Connection ; 65 import java.sql.PreparedStatement ; 66 import java.sql.ResultSet ; 67 import java.sql.SQLException ; 68 import java.sql.Types ; 69 import java.util.Collections ; 70 import java.util.List ; 71 72 import org.apache.log4j.Level; 73 import org.objectstyle.cayenne.CayenneException; 74 import org.objectstyle.cayenne.CayenneRuntimeException; 75 import org.objectstyle.cayenne.access.OperationObserver; 76 import org.objectstyle.cayenne.access.QueryLogger; 77 import org.objectstyle.cayenne.access.trans.LOBBatchQueryBuilder; 78 import org.objectstyle.cayenne.access.trans.LOBBatchQueryWrapper; 79 import org.objectstyle.cayenne.access.trans.LOBInsertBatchQueryBuilder; 80 import org.objectstyle.cayenne.access.trans.LOBUpdateBatchQueryBuilder; 81 import org.objectstyle.cayenne.dba.DbAdapter; 82 import org.objectstyle.cayenne.map.DbAttribute; 83 import org.objectstyle.cayenne.query.BatchQuery; 84 import org.objectstyle.cayenne.query.InsertBatchQuery; 85 import org.objectstyle.cayenne.query.SQLAction; 86 import org.objectstyle.cayenne.query.UpdateBatchQuery; 87 import org.objectstyle.cayenne.util.Util; 88 89 93 class OracleLOBBatchAction implements SQLAction { 94 95 BatchQuery query; 96 DbAdapter adapter; 97 98 OracleLOBBatchAction(BatchQuery query, DbAdapter adapter) { 99 this.adapter = adapter; 100 this.query = query; 101 } 102 103 DbAdapter getAdapter() { 104 return adapter; 105 } 106 107 public void performAction( 108 Connection connection, 109 OperationObserver observer) throws SQLException , Exception { 110 111 LOBBatchQueryBuilder queryBuilder; 112 if (query instanceof InsertBatchQuery) { 113 queryBuilder = new LOBInsertBatchQueryBuilder(getAdapter()); 114 } 115 else if (query instanceof UpdateBatchQuery) { 116 queryBuilder = new LOBUpdateBatchQueryBuilder(getAdapter()); 117 } 118 else { 119 throw new CayenneException( 120 "Unsupported batch type for special LOB processing: " + query); 121 } 122 123 queryBuilder.setTrimFunction(OracleAdapter.TRIM_FUNCTION); 124 queryBuilder.setNewBlobFunction(OracleAdapter.NEW_BLOB_FUNCTION); 125 queryBuilder.setNewClobFunction(OracleAdapter.NEW_CLOB_FUNCTION); 126 127 131 LOBBatchQueryWrapper selectQuery = new LOBBatchQueryWrapper(query); 132 List qualifierAttributes = selectQuery.getDbAttributesForLOBSelectQualifier(); 133 134 Level logLevel = query.getLoggingLevel(); 135 boolean isLoggable = QueryLogger.isLoggable(logLevel); 136 137 query.reset(); 138 while (selectQuery.next()) { 139 int updated = 0; 140 String updateStr = queryBuilder.createSqlString(query); 141 142 QueryLogger.logQuery(logLevel, updateStr, Collections.EMPTY_LIST); 144 PreparedStatement statement = connection.prepareStatement(updateStr); 145 try { 146 147 if (isLoggable) { 148 List bindings = queryBuilder.getValuesForLOBUpdateParameters(query); 149 QueryLogger.logQueryParameters(logLevel, "bind", bindings); 150 } 151 152 queryBuilder.bindParameters(statement, query); 153 updated = statement.executeUpdate(); 154 QueryLogger.logUpdateCount(logLevel, updated); 155 } 156 finally { 157 try { 158 statement.close(); 159 } 160 catch (Exception e) { 161 } 162 } 163 164 processLOBRow(connection, queryBuilder, selectQuery, qualifierAttributes); 166 167 observer.nextCount(query, updated); 169 } 170 } 171 172 void processLOBRow( 173 Connection con, 174 LOBBatchQueryBuilder queryBuilder, 175 LOBBatchQueryWrapper selectQuery, 176 List qualifierAttributes) throws SQLException , Exception { 177 178 List lobAttributes = selectQuery.getDbAttributesForUpdatedLOBColumns(); 179 if (lobAttributes.size() == 0) { 180 return; 181 } 182 183 Level logLevel = selectQuery.getLoggingLevel(); 184 boolean isLoggable = QueryLogger.isLoggable(logLevel); 185 186 List qualifierValues = selectQuery.getValuesForLOBSelectQualifier(); 187 List lobValues = selectQuery.getValuesForUpdatedLOBColumns(); 188 int parametersSize = qualifierValues.size(); 189 int lobSize = lobAttributes.size(); 190 191 String selectStr = queryBuilder.createLOBSelectString( 192 selectQuery.getQuery(), 193 lobAttributes, 194 qualifierAttributes); 195 196 if (isLoggable) { 197 QueryLogger.logQuery(logLevel, selectStr, qualifierValues); 198 QueryLogger.logQueryParameters(logLevel, "write LOB", lobValues); 199 } 200 201 PreparedStatement selectStatement = con.prepareStatement(selectStr); 202 try { 203 for (int i = 0; i < parametersSize; i++) { 204 Object value = qualifierValues.get(i); 205 DbAttribute attribute = (DbAttribute) qualifierAttributes.get(i); 206 207 adapter.bindParameter( 208 selectStatement, 209 value, 210 i + 1, 211 attribute.getType(), 212 attribute.getPrecision()); 213 } 214 215 ResultSet result = selectStatement.executeQuery(); 216 217 try { 218 if (!result.next()) { 219 throw new CayenneRuntimeException("Missing LOB row."); 220 } 221 222 224 for (int i = 0; i < lobSize; i++) { 225 DbAttribute attribute = (DbAttribute) lobAttributes.get(i); 226 int type = attribute.getType(); 227 228 if (type == Types.CLOB) { 229 Clob clob = result.getClob(i + 1); 230 Object clobVal = lobValues.get(i); 231 232 if (clobVal instanceof char[]) { 233 writeClob(clob, (char[]) clobVal); 234 } 235 else { 236 writeClob(clob, clobVal.toString()); 237 } 238 } 239 else if (type == Types.BLOB) { 240 Blob blob = result.getBlob(i + 1); 241 242 Object blobVal = lobValues.get(i); 243 if (blobVal instanceof byte[]) { 244 writeBlob(blob, (byte[]) blobVal); 245 } 246 else { 247 String className = (blobVal != null) ? blobVal 248 .getClass() 249 .getName() : null; 250 throw new CayenneRuntimeException( 251 "Unsupported class of BLOB value: " + className); 252 } 253 } 254 else { 255 throw new CayenneRuntimeException( 256 "Only BLOB or CLOB is expected here, got: " + type); 257 } 258 } 259 260 if (result.next()) { 261 throw new CayenneRuntimeException("More than one LOB row found."); 262 } 263 } 264 finally { 265 try { 266 result.close(); 267 } 268 catch (Exception e) { 269 } 270 } 271 } 272 finally { 273 try { 274 selectStatement.close(); 275 } 276 catch (Exception e) { 277 } 278 } 279 } 280 281 285 private void writeBlob(Blob blob, byte[] value) { 286 287 Method getBinaryStreamMethod = OracleAdapter.getOutputStreamFromBlobMethod(); 288 try { 289 OutputStream out = (OutputStream ) getBinaryStreamMethod.invoke(blob, null); 290 try { 291 out.write(value); 292 out.flush(); 293 } 294 finally { 295 out.close(); 296 } 297 } 298 catch (InvocationTargetException e) { 299 throw new CayenneRuntimeException("Error processing BLOB.", Util 300 .unwindException(e)); 301 } 302 catch (Exception e) { 303 throw new CayenneRuntimeException("Error processing BLOB.", Util 304 .unwindException(e)); 305 } 306 } 307 308 312 private void writeClob(Clob clob, char[] value) { 313 Method getWriterMethod = OracleAdapter.getWriterFromClobMethod(); 315 try { 316 317 Writer out = (Writer ) getWriterMethod.invoke(clob, null); 318 try { 319 out.write(value); 320 out.flush(); 321 } 322 finally { 323 out.close(); 324 } 325 326 } 327 catch (InvocationTargetException e) { 328 throw new CayenneRuntimeException("Error processing BLOB.", Util 329 .unwindException(e)); 330 } 331 catch (Exception e) { 332 throw new CayenneRuntimeException("Error processing BLOB.", Util 333 .unwindException(e)); 334 } 335 } 336 337 341 private void writeClob(Clob clob, String value) { 342 Method getWriterMethod = OracleAdapter.getWriterFromClobMethod(); 344 try { 345 346 Writer out = (Writer ) getWriterMethod.invoke(clob, null); 347 try { 348 out.write(value); 349 out.flush(); 350 } 351 finally { 352 out.close(); 353 } 354 355 } 356 catch (InvocationTargetException e) { 357 throw new CayenneRuntimeException("Error processing BLOB.", Util 358 .unwindException(e)); 359 } 360 catch (Exception e) { 361 throw new CayenneRuntimeException("Error processing BLOB.", Util 362 .unwindException(e)); 363 } 364 } 365 } | Popular Tags |