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