1 23 24 package org.continuent.sequoia.controller.backend.result; 25 26 import java.io.IOException ; 27 import java.io.Serializable ; 28 import java.sql.ResultSet ; 29 import java.sql.SQLException ; 30 import java.sql.SQLWarning ; 31 import java.sql.Statement ; 32 import java.util.ArrayList ; 33 import java.util.Iterator ; 34 35 import org.continuent.sequoia.common.exceptions.NotImplementedException; 36 import org.continuent.sequoia.common.exceptions.driver.protocol.BackendDriverException; 37 import org.continuent.sequoia.common.protocol.Field; 38 import org.continuent.sequoia.common.protocol.SQLDataSerialization; 39 import org.continuent.sequoia.common.protocol.TypeTag; 40 import org.continuent.sequoia.common.stream.DriverBufferedOutputStream; 41 import org.continuent.sequoia.controller.cache.metadata.MetadataCache; 42 import org.continuent.sequoia.controller.core.ControllerConstants; 43 import org.continuent.sequoia.controller.requests.AbstractRequest; 44 45 54 public class ControllerResultSet extends AbstractResult implements Serializable 55 { 56 private static final long serialVersionUID = 4109773059200535129L; 57 58 59 private ArrayList data = null; 60 61 private Field[] fields = null; 62 63 private String cursorName = null; 64 65 private int fetchSize = 0; 66 67 private transient ResultSet dbResultSet = null; 68 72 private transient Statement owningStatement = null; 73 74 private boolean dbResultSetClosed = true; 75 76 private boolean hasMoreData = false; 77 78 private int maxRows = 0; 79 80 private SQLDataSerialization.Serializer[] serializers; 81 82 private SQLWarning warnings = null; 83 84 103 public ControllerResultSet(AbstractRequest request, java.sql.ResultSet rs, 104 MetadataCache metadataCache, Statement s, boolean isPartOfMultipleResults) 105 throws SQLException 106 { 107 this.owningStatement = s; 108 try 109 { 110 if (rs == null) 111 throw new SQLException ( 112 "Cannot build a ControllerResultSet with a null java.sql.ResultSet"); 113 114 118 if ((metadataCache != null) && !isPartOfMultipleResults) 120 fields = metadataCache.getMetadata(request); 121 122 if (fields == null) 123 { java.sql.ResultSetMetaData metaData = rs.getMetaData(); 126 fields = ControllerConstants.CONTROLLER_FACTORY 127 .getResultSetMetaDataFactory().copyResultSetMetaData(metaData, 128 metadataCache); 129 if ((metadataCache != null) && !isPartOfMultipleResults) 130 metadataCache.addMetadata(request, fields); 131 } 132 warnings = null; 134 if (request.getRetrieveSQLWarnings()) 135 { 136 warnings = rs.getWarnings(); 137 } 138 139 data = new ArrayList (); 141 if (rs.next()) { 143 cursorName = request.getCursorName(); 144 fetchSize = request.getFetchSize(); 145 maxRows = request.getMaxRows(); 146 if (maxRows == 0) 147 maxRows = Integer.MAX_VALUE; 149 dbResultSet = rs; 151 fetchData(); 152 if (hasMoreData && (cursorName == null)) 153 cursorName = String.valueOf(dbResultSet.hashCode()); 156 } 157 else 158 { 160 hasMoreData = false; 161 dbResultSet = null; 162 dbResultSetClosed = true; 163 rs.close(); 164 if (owningStatement != null) 165 { 166 try 167 { 168 owningStatement.close(); 169 } 170 catch (SQLException ignore) 171 { 172 } 173 owningStatement = null; 174 } 175 } 176 } 177 catch (SQLException e) 178 { 179 throw (SQLException ) new SQLException ( 180 "Error while building Sequoia ResultSet (" + e.getLocalizedMessage() 181 + ")", e.getSQLState(), e.getErrorCode()).initCause(e); 182 } 183 } 184 185 193 public ControllerResultSet(Field[] fields, ArrayList data) 194 { 195 if (data == null) 196 throw new IllegalArgumentException ( 197 "Cannot build a ControllerResultSet with null data ArrayList"); 198 199 this.fields = fields; 200 this.data = data; 201 warnings = null; 202 } 203 204 208 public void closeResultSet() 209 { 210 if ((dbResultSet != null) && !dbResultSetClosed) 211 { 212 try 213 { 214 dbResultSet.close(); 215 } 216 catch (SQLException ignore) 217 { 218 } 219 dbResultSet = null; 221 if (owningStatement != null) 224 { 225 try 226 { 227 owningStatement.close(); 228 } 229 catch (SQLException ignore) 230 { 231 } 232 owningStatement = null; 233 } 234 } 235 } 236 237 244 public void fetchData(int fetchSizeParam) throws SQLException 245 { 246 this.fetchSize = fetchSizeParam; 247 fetchData(); 248 if (!hasMoreData) 249 { 250 if (owningStatement != null) 251 { 252 try 253 { 254 owningStatement.close(); 255 } 256 catch (SQLException ignore) 257 { 258 } 259 owningStatement = null; 260 } 261 } 262 } 263 264 272 public void fetchData() throws SQLException 273 { 274 if (dbResultSet == null) 275 throw new SQLException ("Backend ResultSet is closed"); 276 277 Object [] row; 278 280 data.clear(); 283 int toFetch; 284 if (fetchSize > 0) 285 { 286 toFetch = fetchSize < maxRows ? fetchSize : maxRows; 287 maxRows -= toFetch; 290 } 291 else 292 toFetch = maxRows; 293 int nbColumn = fields.length; 294 Object object; 295 do 296 { 297 row = new Object [nbColumn]; 298 for (int i = 0; i < nbColumn; i++) 299 { 300 object = ControllerConstants.CONTROLLER_FACTORY 301 .getBackendObjectConverter().convertResultSetObject(dbResultSet, i, 302 fields[i]); 303 row[i] = object; 304 } 305 data.add(row); 306 toFetch--; 307 hasMoreData = dbResultSet.next(); 308 } 309 while (hasMoreData && (toFetch > 0)); 310 if (hasMoreData && (fetchSize > 0) && (maxRows > 0)) 311 { maxRows += toFetch; 313 dbResultSetClosed = false; 314 } 315 else 316 { 317 hasMoreData = false; 318 dbResultSet.close(); 319 if (owningStatement != null) 320 owningStatement.close(); 321 dbResultSet = null; 322 dbResultSetClosed = true; 323 } 324 } 325 326 331 public String getCursorName() 332 { 333 return cursorName; 334 } 335 336 341 public ArrayList getData() 342 { 343 return data; 344 } 345 346 351 public Field[] getFields() 352 { 353 return fields; 354 } 355 356 361 public boolean hasMoreData() 362 { 363 return hasMoreData; 364 } 365 366 370 380 381 public void sendToStream( 382 org.continuent.sequoia.common.stream.DriverBufferedOutputStream output) 383 throws IOException 384 { 385 if (warnings != null) 388 { 389 output.writeBoolean(true); 390 new BackendDriverException(warnings).sendToStream(output); 391 } 392 else 393 output.writeBoolean(false); 394 395 int nbOfColumns = fields.length; 396 int nbOfRows = data.size(); 397 output.writeInt(nbOfColumns); 399 for (int f = 0; f < nbOfColumns; f++) 400 this.fields[f].sendToStream(output); 401 402 TypeTag.COL_TYPES.sendToStream(output); 403 404 output.writeInt(nbOfRows); 407 408 if (nbOfRows > 0) 410 { 411 if (null == this.serializers) 412 throw new IllegalStateException ( 413 "Bug: forgot to initialize serializers of a non empty ControllerResultSet"); 414 415 for (int col = 0; col < nbOfColumns; col++) 416 serializers[col].getTypeTag().sendToStream(output); 417 } 418 419 sendRowsToStream(output); 421 422 if (this.hasMoreData) 423 { output.writeLongUTF(this.cursorName); 425 } 426 output.flush(); 427 } 428 429 437 public void initSerializers() throws NotImplementedException 438 { 439 440 if (this.serializers != null) 441 return; 442 443 if (data.size() == 0) 444 return; 445 446 final int nbOfColumns = fields.length; 447 this.serializers = new SQLDataSerialization.Serializer[nbOfColumns]; 448 449 for (int col = 0; col < nbOfColumns; col++) 450 { 451 int rowIdx = -1; 452 while (serializers[col] == null) 453 { 454 rowIdx++; 455 456 if (rowIdx >= data.size()) break; 459 460 final Object [] row = (Object []) data.get(rowIdx); 461 final Object sqlObj = row[col]; 462 463 467 if (sqlObj == null) 468 continue; 469 470 try 471 { 472 serializers[col] = SQLDataSerialization.getSerializer(sqlObj); 473 } 474 catch (NotImplementedException nie) 475 { 476 if (sqlObj instanceof Short ) 477 { 478 488 489 serializers[col] = SQLDataSerialization 496 .getSerializer(TypeTag.INTEGER); 497 498 } else 500 { 501 NotImplementedException betterNIE = new NotImplementedException( 502 "Backend driver gave an object of an unsupported java type:" 503 + sqlObj.getClass().getName() + ", at colum number " + col 504 + " of name " + fields[col].getFieldName()); 505 509 throw betterNIE; 511 } 512 } 513 514 } 516 if (serializers[col] == null) { 518 521 529 534 535 final TypeTag javaObjectType = TypeTag.jdbcToJavaObjectType(fields[col] 536 .getSqlType()); 537 538 if (!TypeTag.TYPE_ERROR.equals(javaObjectType)) 539 540 serializers[col] = SQLDataSerialization.getSerializer(javaObjectType); 541 542 else 543 { 544 serializers[col] = SQLDataSerialization.getSerializer(null); 546 547 551 } 556 557 } 559 } } 561 562 570 public void sendRowsToStream(DriverBufferedOutputStream output) 571 throws IOException 572 { 573 574 output.writeInt(data.size()); 575 576 boolean[] nulls = new boolean[fields.length]; 577 578 Iterator rowsIter = this.data.iterator(); 579 while (rowsIter.hasNext()) 580 { 581 Object [] row = (Object []) rowsIter.next(); 582 TypeTag.ROW.sendToStream(output); 583 584 for (int col = 0; col < row.length; col++) 586 { 587 if (null == row[col]) 588 nulls[col] = true; 589 else 590 nulls[col] = false; 591 output.writeBoolean(nulls[col]); 593 } 594 595 for (int col = 0; col < row.length; col++) 596 if (!nulls[col]) { 598 try 599 { 600 610 serializers[col].sendToStream(row[col], output); 611 } 612 catch (ClassCastException cce1) 613 { 614 ClassCastException cce2 = new ClassCastException ("Serializer " 615 + serializers[col] + " failed on Java object: " + row[col] 616 + " found in column: " + col + ", because of unexpected type " 617 + row[col].getClass().getName()); 618 cce2.initCause(cce1); 619 throw cce2; 620 } 621 } 623 } 625 output.writeBoolean(this.hasMoreData); 626 output.flush(); 627 } 628 629 } | Popular Tags |