1 21 22 package org.apache.derby.impl.sql.execute; 23 24 import org.apache.derby.iapi.services.loader.GeneratedMethod; 25 26 import org.apache.derby.iapi.services.monitor.Monitor; 27 28 import org.apache.derby.iapi.services.sanity.SanityManager; 29 30 import org.apache.derby.iapi.sql.execute.CursorResultSet; 31 import org.apache.derby.iapi.sql.execute.ExecRow; 32 import org.apache.derby.iapi.sql.execute.ExecutionContext; 33 import org.apache.derby.iapi.sql.execute.NoPutResultSet; 34 35 import org.apache.derby.iapi.sql.Activation; 36 import org.apache.derby.iapi.sql.Row; 37 38 import org.apache.derby.iapi.store.access.ConglomerateController; 39 import org.apache.derby.iapi.store.access.ScanController; 40 import org.apache.derby.iapi.store.access.TransactionController; 41 42 import org.apache.derby.iapi.types.RowLocation; 43 import org.apache.derby.iapi.types.DataValueDescriptor; 44 45 import org.apache.derby.iapi.error.StandardException; 46 import org.apache.derby.iapi.reference.SQLState; 47 48 import org.apache.derby.iapi.store.access.BackingStoreHashtable; 49 import org.apache.derby.iapi.services.io.FormatableBitSet; 50 51 import org.apache.derby.iapi.types.SQLBoolean; 52 import org.apache.derby.iapi.types.SQLInteger; 53 54 91 92 public class ScrollInsensitiveResultSet extends NoPutResultSetImpl 93 implements CursorResultSet 94 { 95 98 99 public NoPutResultSet source; 100 101 102 103 private int sourceRowWidth; 104 105 private BackingStoreHashtable ht; 106 private ExecRow resultRow; 107 108 private int positionInSource; 110 private int currentPosition; 111 private int lastPosition; 112 private boolean seenFirst; 113 private boolean seenLast; 114 private boolean beforeFirst = true; 115 private boolean afterLast; 116 117 public int numFromHashTable; 118 public int numToHashTable; 119 120 private int maxRows; 121 122 private boolean keepAfterCommit; 123 124 130 private int extraColumns; 131 132 135 private SQLInteger positionInHashTable; 136 137 141 private CursorResultSet target; 142 143 147 private boolean needsRepositioning; 148 149 152 private static final int POS_ROWLOCATION = 1; 153 private static final int POS_ROWDELETED = 2; 154 private static final int POS_ROWUPDATED = 3; 155 private static final int LAST_EXTRA_COLUMN = 3; 156 157 168 169 public ScrollInsensitiveResultSet(NoPutResultSet source, 170 Activation activation, int resultSetNumber, 171 int sourceRowWidth, 172 double optimizerEstimatedRowCount, 173 double optimizerEstimatedCost) throws StandardException 174 { 175 super(activation, resultSetNumber, 176 optimizerEstimatedRowCount, optimizerEstimatedCost); 177 this.source = source; 178 this.sourceRowWidth = sourceRowWidth; 179 keepAfterCommit = activation.getResultSetHoldability(); 180 maxRows = activation.getMaxRows(); 181 if (SanityManager.DEBUG) 182 { 183 SanityManager.ASSERT(maxRows != -1, 184 "maxRows not expected to be -1"); 185 } 186 187 constructorTime += getElapsedMillis(beginTime); 188 189 positionInHashTable = new SQLInteger(); 190 needsRepositioning = false; 191 if (isForUpdate()) { 192 target = ((CursorActivation)activation).getTargetResultSet(); 193 extraColumns = LAST_EXTRA_COLUMN + 1; 194 } else { 195 target = null; 196 extraColumns = 1; 197 } 198 } 199 200 201 205 212 public void openCore() throws StandardException 213 { 214 beginTime = getCurrentTimeMillis(); 215 if (SanityManager.DEBUG) 216 SanityManager.ASSERT( ! isOpen, "ScrollInsensitiveResultSet already open"); 217 218 source.openCore(); 219 isOpen = true; 220 numOpens++; 221 222 229 final int[] keyCols = new int[] { 0 }; 230 231 238 ht = new BackingStoreHashtable(getTransactionController(), 239 null, 240 keyCols, 241 false, 242 -1, HashScanResultSet.DEFAULT_MAX_CAPACITY, 244 HashScanResultSet.DEFAULT_INITIAL_CAPACITY, 245 HashScanResultSet.DEFAULT_MAX_CAPACITY, 246 false, 247 keepAfterCommit); 248 249 openTime += getElapsedMillis(beginTime); 250 setBeforeFirstRow(); 251 } 252 253 260 public void reopenCore() throws StandardException 261 { 262 boolean constantEval = true; 263 264 beginTime = getCurrentTimeMillis(); 265 266 if (SanityManager.DEBUG) 267 { 268 SanityManager.ASSERT(isOpen, "ScrollInsensitiveResultSet already open"); 269 SanityManager.THROWASSERT( 270 "reopenCore() not expected to be called"); 271 } 272 setBeforeFirstRow(); 273 } 274 275 290 public ExecRow getAbsoluteRow(int row) throws StandardException 291 { 292 if ( ! isOpen ) 293 { 294 throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "absolute"); 295 } 296 297 attachStatementContext(); 298 299 if (SanityManager.DEBUG) 300 { 301 if (!isTopResultSet) 302 { 303 SanityManager.THROWASSERT( 304 this + "expected to be the top ResultSet"); 305 } 306 } 307 308 if (row == 0) 310 { 311 setBeforeFirstRow(); 312 return null; 313 } 314 315 if (seenLast && row > lastPosition) { 316 return setAfterLastRow(); 317 } 318 319 if (row > 0) 320 { 321 if (row <= positionInSource) 323 { 324 return getRowFromHashTable(row); 326 } 327 328 331 int diff = row - positionInSource; 332 ExecRow result = null; 333 while (diff > 0) 334 { 335 if ((result = getNextRowFromSource()) != null) 336 { 337 diff--; 338 } 339 else 340 { 341 break; 342 } 343 } 344 if (result != null) { 345 result = getRowFromHashTable(row); 346 } 347 currentRow = result; 348 return result; 349 } 350 else if (row < 0) 351 { 352 354 if (!seenLast) 356 { 357 getLastRow(); 358 } 359 360 int beyondResult = lastPosition + 1; 363 if (beyondResult + row > 0) 364 { 365 return getRowFromHashTable(beyondResult + row); 367 } 368 else 369 { 370 return setBeforeFirstRow(); 372 } 373 } 374 375 currentRow = null; 376 return null; 377 } 378 379 396 public ExecRow getRelativeRow(int row) throws StandardException 397 { 398 if ( ! isOpen ) 399 { 400 throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "relative"); 401 } 402 403 attachStatementContext(); 404 405 if (SanityManager.DEBUG) 406 { 407 if (!isTopResultSet) 408 { 409 SanityManager.THROWASSERT( 410 this + "expected to be the top ResultSet"); 411 } 412 } 413 414 if (row == 0) 416 { 417 if (beforeFirst || afterLast || currentPosition==0) { 418 return null; 419 } else { 420 return getRowFromHashTable(currentPosition); 421 } 422 } 423 else if (row > 0) 424 { 425 return getAbsoluteRow(currentPosition + row); 426 } 427 else 428 { 429 if (currentPosition + row < 0) 431 { 432 return setBeforeFirstRow(); 433 } 434 return getAbsoluteRow(currentPosition + row); 435 } 436 } 437 438 446 public ExecRow setBeforeFirstRow() 447 { 448 currentPosition = 0; 449 beforeFirst = true; 450 afterLast = false; 451 currentRow = null; 452 return null; 453 } 454 455 464 public ExecRow getFirstRow() 465 throws StandardException 466 { 467 if ( ! isOpen ) 468 { 469 throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "first"); 470 } 471 472 475 if (seenFirst) 476 { 477 return getRowFromHashTable(1); 478 } 479 480 attachStatementContext(); 481 482 if (SanityManager.DEBUG) 483 { 484 if (!isTopResultSet) 485 { 486 SanityManager.THROWASSERT( 487 this + "expected to be the top ResultSet"); 488 } 489 } 490 491 return getNextRowCore(); 492 } 493 494 498 public ExecRow getNextRowCore() throws StandardException 499 { 500 ExecRow result = null; 501 502 beginTime = getCurrentTimeMillis(); 503 if (!isOpen) 504 throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "next"); 505 506 if (seenLast && currentPosition == lastPosition) { 507 return setAfterLastRow(); 508 } 509 510 511 if (currentPosition == positionInSource) 512 { 513 516 result = getNextRowFromSource(); 517 if (result !=null) { 518 result = getRowFromHashTable(currentPosition); 519 } 520 } 521 else if (currentPosition < positionInSource) 522 { 523 526 result = getRowFromHashTable(currentPosition + 1); 527 } 528 else 529 { 530 result = null; 531 } 532 533 if (result != null) 534 { 535 rowsSeen++; 536 afterLast = false; 537 } 538 539 currentRow = result; 540 setCurrentRow(currentRow); 541 beforeFirst = false; 542 543 nextTime += getElapsedMillis(beginTime); 544 545 return result; 546 } 547 548 557 public ExecRow getPreviousRow() 558 throws StandardException 559 { 560 if ( ! isOpen ) 561 { 562 throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "next"); 563 } 564 565 if (SanityManager.DEBUG) 566 { 567 if (!isTopResultSet) 568 { 569 SanityManager.THROWASSERT( 570 this + "expected to be the top ResultSet"); 571 } 572 } 573 574 577 if (beforeFirst || currentPosition == 0) 578 { 579 currentRow = null; 580 return null; 581 } 582 583 if (afterLast) 585 { 586 if (lastPosition == 0) 588 { 589 afterLast = false; 590 beforeFirst = false; 591 currentRow = null; 592 return null; 593 } 594 else 595 { 596 return getRowFromHashTable(lastPosition); 597 } 598 } 599 600 currentPosition--; 602 if (currentPosition == 0) 603 { 604 setBeforeFirstRow(); 605 return null; 606 } 607 return getRowFromHashTable(currentPosition); 608 } 609 610 619 public ExecRow getLastRow() 620 throws StandardException 621 { 622 if ( ! isOpen ) 623 { 624 throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "next"); 625 } 626 627 if (!seenLast) 628 { 629 attachStatementContext(); 630 631 if (SanityManager.DEBUG) 632 { 633 if (!isTopResultSet) 634 { 635 SanityManager.THROWASSERT( 636 this + "expected to be the top ResultSet"); 637 } 638 } 639 640 643 ExecRow result = null; 644 while ((result = getNextRowFromSource()) != null); 645 } 646 647 if (SanityManager.DEBUG && !seenLast) 648 { 649 SanityManager.THROWASSERT(this + "expected to have seen last"); 650 } 651 652 beforeFirst = false; 653 afterLast = false; 654 655 if (lastPosition == 0) 657 { 658 currentRow = null; 659 return null; 660 } 661 else 662 { 663 return getRowFromHashTable(lastPosition); 664 } 665 } 666 667 676 public ExecRow setAfterLastRow() 677 throws StandardException 678 { 679 if (! seenLast) 680 { 681 getLastRow(); 682 } 683 if (lastPosition == 0) { 684 currentPosition = 0; 686 afterLast = false; 687 } else { 688 currentPosition = lastPosition + 1; 689 afterLast = true; 690 } 691 692 beforeFirst = false; 693 currentRow = null; 694 return null; 695 } 696 697 705 public boolean checkRowPosition(int isType) throws StandardException 706 { 707 switch (isType) { 708 case ISBEFOREFIRST: 709 710 if (! beforeFirst) 711 { 712 return false; 713 } 714 715 if (seenFirst) 717 { 718 return true; 719 } 720 else 721 { 722 ExecRow firstRow = getFirstRow(); 723 if (firstRow == null) 724 { 725 return false; 727 } 728 else 729 { 730 getPreviousRow(); 732 return true; 733 } 734 } 735 case ISFIRST: 736 return (currentPosition == 1); 737 case ISLAST: 738 if (beforeFirst || afterLast || currentPosition==0 || 739 currentPosition<positionInSource) 740 { 741 return false; 742 } 743 744 748 if (seenLast) 749 { 750 return (currentPosition == lastPosition); 751 } 752 else 753 { 754 final int savePosition = currentPosition; 755 final boolean retval = (getNextRowFromSource() == null); 756 getRowFromHashTable(savePosition); 757 return retval; 758 } 759 case ISAFTERLAST: 760 return afterLast; 761 default: 762 return false; 763 } 764 } 765 766 775 public int getRowNumber() 776 { 777 return currentRow == null ? 0 : currentPosition; 778 } 779 780 781 private ExecRow getNextRowFromSource() throws StandardException 782 { 783 ExecRow sourceRow = null; 784 ExecRow result = null; 785 786 787 if (maxRows > 0 && maxRows == positionInSource) 788 { 789 seenLast = true; 790 lastPosition = positionInSource; 791 afterLast = true; 792 return null; 793 } 794 795 796 if (needsRepositioning) { 797 positionInLastFetchedRow(); 798 needsRepositioning = false; 799 } 800 sourceRow = source.getNextRowCore(); 801 802 if (sourceRow != null) 803 { 804 seenFirst = true; 805 beforeFirst = false; 806 807 long beginTCTime = getCurrentTimeMillis(); 808 811 if (resultRow == null) 812 { 813 resultRow = activation.getExecutionFactory().getValueRow(sourceRowWidth); 814 } 815 816 positionInSource++; 817 currentPosition = positionInSource; 818 819 RowLocation rowLoc = null; 820 if (source.isForUpdate()) { 821 rowLoc = ((CursorResultSet)source).getRowLocation(); 822 } 823 824 addRowToHashTable(sourceRow, currentPosition, rowLoc, false); 825 826 } 827 else 829 { 830 if (! seenLast) 831 { 832 lastPosition = positionInSource; 833 } 834 seenLast = true; 835 if (positionInSource == 0) 837 { 838 afterLast = false; 839 } 840 else 841 { 842 afterLast = true; 843 currentPosition = positionInSource + 1; 844 } 845 } 846 847 return sourceRow; 848 } 849 850 856 public void close() throws StandardException 857 { 858 beginTime = getCurrentTimeMillis(); 859 if ( isOpen ) 860 { 861 currentRow = null; 862 source.close(); 863 864 if (ht != null) 865 { 866 ht.close(); 867 ht = null; 868 } 869 870 super.close(); 871 } 872 else 873 if (SanityManager.DEBUG) 874 SanityManager.DEBUG("CloseRepeatInfo","Close of ScrollInsensitiveResultSet repeated"); 875 setBeforeFirstRow(); 876 877 closeTime += getElapsedMillis(beginTime); 878 } 879 880 public void finish() throws StandardException 881 { 882 source.finish(); 883 finishAndRTS(); 884 } 885 886 894 public long getTimeSpent(int type) 895 { 896 long totTime = constructorTime + openTime + nextTime + closeTime; 897 898 if (type == NoPutResultSet.CURRENT_RESULTSET_ONLY) 899 { 900 return totTime - source.getTimeSpent(ENTIRE_RESULTSET_TREE); 901 } 902 else 903 { 904 return totTime; 905 } 906 } 907 908 912 923 public RowLocation getRowLocation() throws StandardException 924 { 925 if (SanityManager.DEBUG) 926 SanityManager.ASSERT(source instanceof CursorResultSet, "source not CursorResultSet"); 927 return ( (CursorResultSet)source ).getRowLocation(); 928 } 929 930 937 940 public ExecRow getCurrentRow() throws StandardException 941 { 942 if (isForUpdate() && isDeleted()) { 943 return null; 944 } else { 945 return currentRow; 946 } 947 } 948 949 953 968 private void addRowToHashTable(ExecRow sourceRow, int position, 969 RowLocation rowLoc, boolean rowUpdated) 970 throws StandardException 971 { 972 DataValueDescriptor[] hashRowArray = new 973 DataValueDescriptor[sourceRowWidth + extraColumns]; 974 hashRowArray[0] = new SQLInteger(position); 976 if (isForUpdate()) { 977 hashRowArray[POS_ROWLOCATION] = rowLoc.getClone(); 978 hashRowArray[POS_ROWDELETED] = new SQLBoolean(false); 979 hashRowArray[POS_ROWUPDATED] = new SQLBoolean(rowUpdated); 980 } 981 982 987 DataValueDescriptor[] sourceRowArray = sourceRow.getRowArray(); 988 989 System.arraycopy(sourceRowArray, 0, hashRowArray, extraColumns, 990 sourceRowArray.length); 991 992 ht.put(true, hashRowArray); 993 994 numToHashTable++; 995 } 996 997 1007 private ExecRow getRowFromHashTable(int position) 1008 throws StandardException 1009 { 1010 1011 positionInHashTable.setValue(position); 1013 DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) 1014 ht.get(positionInHashTable); 1015 1016 1017 if (SanityManager.DEBUG) 1018 { 1019 SanityManager.ASSERT(hashRowArray != null, 1020 "hashRowArray expected to be non-null"); 1021 } 1022 DataValueDescriptor[] resultRowArray = new 1024 DataValueDescriptor[hashRowArray.length - extraColumns]; 1025 System.arraycopy(hashRowArray, extraColumns, resultRowArray, 0, 1026 resultRowArray.length); 1027 1028 resultRow.setRowArray(resultRowArray); 1029 1030 currentPosition = position; 1032 1033 numFromHashTable++; 1034 1035 if (resultRow != null) 1036 { 1037 beforeFirst = false; 1038 afterLast = false; 1039 } 1040 1041 if (isForUpdate()) { 1042 RowLocation rowLoc = (RowLocation) hashRowArray[POS_ROWLOCATION]; 1043 ((NoPutResultSet)target).setCurrentRow(resultRow); 1045 ((NoPutResultSet)target).positionScanAtRowLocation(rowLoc); 1046 needsRepositioning = true; 1047 } 1048 1049 setCurrentRow(resultRow); 1050 1051 return resultRow; 1052 } 1053 1054 1064 private DataValueDescriptor[] getRowArrayFromHashTable(int position) 1065 throws StandardException 1066 { 1067 positionInHashTable.setValue(position); 1068 final DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) 1069 ht.get(positionInHashTable); 1070 1071 final DataValueDescriptor[] resultRowArray = new 1073 DataValueDescriptor[hashRowArray.length - extraColumns]; 1074 System.arraycopy(hashRowArray, extraColumns, resultRowArray, 0, 1075 resultRowArray.length); 1076 return resultRowArray; 1077 } 1078 1079 1084 private void positionInLastFetchedRow() throws StandardException { 1085 if (positionInSource > 0) { 1086 positionInHashTable.setValue(positionInSource); 1087 DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) 1088 ht.get(positionInHashTable); 1089 RowLocation rowLoc = (RowLocation) hashRowArray[POS_ROWLOCATION]; 1090 ((NoPutResultSet)target).positionScanAtRowLocation(rowLoc); 1091 currentPosition = positionInSource; 1092 } 1093 } 1094 1095 1101 public void updateRow(ExecRow row) throws StandardException { 1102 ExecRow newRow = row; 1103 boolean undoProjection = false; 1104 1105 if (source instanceof ProjectRestrictResultSet) { 1106 newRow = ((ProjectRestrictResultSet)source). 1107 doBaseRowProjection(row); 1108 undoProjection = true; 1109 } 1110 positionInHashTable.setValue(currentPosition); 1111 DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) 1112 ht.get(positionInHashTable); 1113 RowLocation rowLoc = (RowLocation) hashRowArray[POS_ROWLOCATION]; 1114 ht.remove(new SQLInteger(currentPosition)); 1115 addRowToHashTable(newRow, currentPosition, rowLoc, true); 1116 1117 if (undoProjection) { 1123 1124 final DataValueDescriptor[] newRowData = newRow.getRowArray(); 1125 1126 final int[] origPos =((ProjectRestrictResultSet)source). 1128 getBaseProjectMapping(); 1129 1130 final DataValueDescriptor[] backedData = 1132 getRowArrayFromHashTable(currentPosition); 1133 1134 for (int i=0; i<origPos.length; i++) { 1135 if (origPos[i]>=0) { 1136 row.setColumn(origPos[i], backedData[i]); 1137 } 1138 } 1139 } else { 1140 row.setRowArray(getRowArrayFromHashTable(currentPosition)); 1141 } 1142 } 1143 1144 1149 public void markRowAsDeleted() throws StandardException { 1150 positionInHashTable.setValue(currentPosition); 1151 DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) 1152 ht.get(positionInHashTable); 1153 RowLocation rowLoc = (RowLocation) hashRowArray[POS_ROWLOCATION]; 1154 ht.remove(new SQLInteger(currentPosition)); 1155 ((SQLBoolean)hashRowArray[POS_ROWDELETED]).setValue(true); 1156 for (int i=extraColumns; i<hashRowArray.length; i++) { 1158 hashRowArray[i].setToNull(); 1159 } 1160 1161 ht.put(true, hashRowArray); 1162 } 1163 1164 1172 public boolean isDeleted() throws StandardException { 1173 if (currentPosition <= positionInSource && currentPosition > 0) { 1174 positionInHashTable.setValue(currentPosition); 1175 DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) 1176 ht.get(positionInHashTable); 1177 return hashRowArray[POS_ROWDELETED].getBoolean(); 1178 } 1179 return false; 1180 } 1181 1182 1190 public boolean isUpdated() throws StandardException { 1191 if (currentPosition <= positionInSource && currentPosition > 0) { 1192 positionInHashTable.setValue(currentPosition); 1193 DataValueDescriptor[] hashRowArray = (DataValueDescriptor[]) 1194 ht.get(positionInHashTable); 1195 return hashRowArray[POS_ROWUPDATED].getBoolean(); 1196 } 1197 return false; 1198 } 1199 1200 public boolean isForUpdate() { 1201 return source.isForUpdate(); 1202 } 1203 1204} 1205 | Popular Tags |