1 21 22 package org.apache.derby.impl.store.raw.data; 23 24 import org.apache.derby.iapi.reference.SQLState; 25 26 import org.apache.derby.impl.store.raw.data.BasePage; 27 28 import org.apache.derby.impl.store.raw.data.LongColumnException; 29 import org.apache.derby.impl.store.raw.data.OverflowInputStream; 30 import org.apache.derby.impl.store.raw.data.PageVersion; 31 import org.apache.derby.impl.store.raw.data.RecordId; 32 import org.apache.derby.impl.store.raw.data.RawField; 33 import org.apache.derby.impl.store.raw.data.ReclaimSpace; 34 import org.apache.derby.impl.store.raw.data.StoredFieldHeader; 35 import org.apache.derby.impl.store.raw.data.StoredRecordHeader; 36 37 import org.apache.derby.iapi.services.io.FormatIdUtil; 38 import org.apache.derby.iapi.services.io.FormatIdInputStream; 39 import org.apache.derby.iapi.services.io.FormatIdOutputStream; 40 import org.apache.derby.iapi.services.io.StoredFormatIds; 41 import org.apache.derby.iapi.services.io.StreamStorable; 42 import org.apache.derby.iapi.services.io.TypedFormat; 43 import org.apache.derby.iapi.services.sanity.SanityManager; 44 45 import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo; 46 import org.apache.derby.iapi.store.access.Qualifier; 47 import org.apache.derby.iapi.store.access.RowUtil; 48 49 import org.apache.derby.iapi.store.raw.ContainerHandle; 50 import org.apache.derby.iapi.store.raw.FetchDescriptor; 51 import org.apache.derby.iapi.store.raw.Page; 52 import org.apache.derby.iapi.store.raw.PageKey; 53 import org.apache.derby.iapi.store.raw.PageTimeStamp; 54 import org.apache.derby.iapi.store.raw.RawStoreFactory; 55 import org.apache.derby.iapi.store.raw.RecordHandle; 56 import org.apache.derby.iapi.store.raw.log.LogInstant; 57 import org.apache.derby.iapi.store.raw.xact.RawTransaction; 58 59 import org.apache.derby.iapi.error.StandardException; 60 61 import org.apache.derby.iapi.types.DataValueDescriptor; 62 63 import org.apache.derby.iapi.types.Orderable; 64 65 import org.apache.derby.iapi.services.io.ArrayInputStream; 66 import org.apache.derby.iapi.services.io.ArrayOutputStream; 67 import org.apache.derby.iapi.services.io.FormatableBitSet; 68 import org.apache.derby.iapi.util.ByteArray; 69 import org.apache.derby.iapi.services.io.CompressedNumber; 70 import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream; 71 import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream; 72 import org.apache.derby.iapi.services.io.LimitObjectInput; 73 import org.apache.derby.iapi.services.io.ErrorObjectInput; 74 75 76 import java.util.zip.CRC32 ; 77 78 import java.io.IOException ; 79 import java.io.EOFException ; 80 import java.io.Externalizable ; 81 import java.io.InvalidClassException ; 82 83 import java.io.ObjectOutput ; 84 import java.io.ObjectInput ; 85 import java.io.DataInput ; 86 import java.io.DataOutput ; 87 import java.io.InputStream ; 88 import java.io.OutputStream ; 89 import java.io.ByteArrayInputStream ; 90 import java.io.ByteArrayOutputStream ; 91 92 93 212 213 214 215 219 220 224 225 public class StoredPage extends CachedPage 226 { 227 231 232 235 236 public static final int FORMAT_NUMBER = 237 StoredFormatIds.RAW_STORE_STORED_PAGE; 238 239 242 public int getTypeFormatId() 243 { 244 return StoredFormatIds.RAW_STORE_STORED_PAGE; 245 } 246 247 248 263 264 265 270 protected static final int PAGE_HEADER_OFFSET = PAGE_FORMAT_ID_SIZE; 271 272 273 276 protected static final int PAGE_HEADER_SIZE = 56; 277 278 279 282 288 protected static final int RECORD_SPACE_OFFSET = 289 PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE; 290 291 294 protected static final int PAGE_VERSION_OFFSET = PAGE_HEADER_OFFSET + 2; 295 296 300 protected static final int SMALL_SLOT_SIZE = 2; 301 protected static final int LARGE_SLOT_SIZE = 4; 302 303 310 protected static final int CHECKSUM_SIZE = 8; 311 312 326 protected static final int OVERFLOW_POINTER_SIZE = 12; 327 328 345 protected static final int OVERFLOW_PTR_FIELD_SIZE = 346 OVERFLOW_POINTER_SIZE + 1 + 1; 347 348 351 ByteHolder bh = null; 352 353 357 358 359 370 protected static final int COLUMN_NONE = 0; 371 protected static final int COLUMN_FIRST = 1; 372 protected static final int COLUMN_LONG = 2; 373 374 375 387 protected int maxFieldSize; 388 389 390 414 private boolean isOverflowPage; private int slotsInUse; private int nextId; private int generation; private int prevGeneration; private long bipLocation; private int deletedRowCount; 422 429 private boolean headerOutOfDate; 430 431 434 private CRC32 checksum; 435 436 466 protected int minimumRecordSize; 467 468 474 private int userRowSize; 475 476 488 private int slotFieldSize; 489 private int slotEntrySize; 490 491 504 private int slotTableOffsetToFirstEntry; 505 506 522 private int slotTableOffsetToFirstRecordLengthField; 523 524 525 541 private int slotTableOffsetToFirstReservedSpaceField; 542 543 549 protected int totalSpace; 551 protected int freeSpace = Integer.MIN_VALUE; private int firstFreeByte = Integer.MIN_VALUE; 555 556 563 protected int spareSpace; 564 565 569 private StoredRecordHeader overflowRecordHeader; 570 571 574 protected ArrayInputStream rawDataIn; 575 protected ArrayOutputStream rawDataOut; 576 protected FormatIdOutputStream logicalDataOut; 577 578 579 583 584 585 588 public StoredPage() 589 { 590 super(); 591 } 592 593 597 598 604 605 private StoredRecordHeader getOverFlowRecordHeader() 606 throws StandardException 607 { 608 return( 609 overflowRecordHeader != null ? 610 overflowRecordHeader : 611 (overflowRecordHeader = new StoredRecordHeader())); 612 } 613 614 621 protected void initialize() 622 { 623 super.initialize(); 624 625 if (rawDataIn == null) 626 { 627 rawDataIn = new ArrayInputStream(); 628 checksum = new CRC32 (); 629 } 630 631 if (pageData != null) 632 rawDataIn.setData(pageData); 633 } 634 635 636 646 private void createOutStreams() 647 { 648 rawDataOut = new ArrayOutputStream(); 649 rawDataOut.setData(pageData); 650 651 logicalDataOut = new FormatIdOutputStream(rawDataOut); 652 } 653 654 660 private void setOutputStream(OutputStream out) 661 { 662 if (rawDataOut == null) 663 createOutStreams(); 664 665 logicalDataOut.setOutput(out); 666 } 667 668 676 private void resetOutputStream() 677 { 678 679 logicalDataOut.setOutput(rawDataOut); 680 } 681 682 686 687 703 protected void usePageBuffer(byte[] pageBuffer) 704 { 705 pageData = pageBuffer; 706 707 int pageSize = pageData.length; 708 if (rawDataIn != null) 709 rawDataIn.setData(pageData); 710 711 initSpace(); 712 713 if (pageSize >= 65536) 714 slotFieldSize = LARGE_SLOT_SIZE; 715 else 716 slotFieldSize = SMALL_SLOT_SIZE; 717 718 slotEntrySize = 3 * slotFieldSize; 719 720 slotTableOffsetToFirstEntry = 722 (pageSize - CHECKSUM_SIZE - slotEntrySize); 723 724 slotTableOffsetToFirstRecordLengthField = 726 slotTableOffsetToFirstEntry + slotFieldSize; 727 728 slotTableOffsetToFirstReservedSpaceField = 730 slotTableOffsetToFirstEntry + (2 * slotFieldSize); 731 732 if (rawDataOut != null) 733 rawDataOut.setData(pageData); 734 } 735 736 737 750 protected void createPage( 751 PageKey newIdentity, 752 int[] args) 753 throws StandardException 754 { 755 758 int pageSize = args[2]; 759 spareSpace = args[3]; 760 minimumRecordSize = args[4]; 761 762 setPageArray(pageSize); 763 764 cleanPage(); 766 setPageVersion(0); 768 nextId = RecordHandle.FIRST_RECORD_ID; generation = 0; 770 prevGeneration = 0; bipLocation = 0L; 772 773 createOutStreams(); 774 } 775 776 791 protected void initFromData( 792 FileContainer myContainer, 793 PageKey newIdentity) 794 throws StandardException 795 { 796 if (myContainer != null) 797 { 798 800 spareSpace = myContainer.getSpareSpace(); 801 minimumRecordSize = myContainer.getMinimumRecordSize(); 802 } 803 804 807 try 808 { 809 readPageHeader(); 810 initSlotTable(); 811 } 812 catch (IOException ioe) 813 { 814 throw dataFactory.markCorrupt( 816 StandardException.newException( 817 SQLState.DATA_CORRUPT_PAGE, ioe, newIdentity)); 818 } 819 820 try 821 { 822 validateChecksum(newIdentity); 823 } 824 catch (StandardException se) 825 { 826 if (se.getMessageId().equals(SQLState.FILE_BAD_CHECKSUM)) 827 { 828 int pagesize = getPageSize(); 832 byte[] corruptPage = pageData; 833 pageData = null; 835 setPageArray(pagesize); 837 838 try 839 { 840 myContainer.readPage(newIdentity.getPageNumber(), pageData); 841 } 842 catch (IOException ioe) 843 { 844 throw dataFactory.markCorrupt( 845 StandardException.newException( 846 SQLState.DATA_CORRUPT_PAGE, ioe, newIdentity)); 847 } 848 849 if (SanityManager.DEBUG) 850 { 851 SanityManager.DEBUG_CLEAR("TEST_BAD_CHECKSUM"); 852 } 853 854 try 856 { 857 validateChecksum(newIdentity); 858 } 859 catch (StandardException sse) 860 { 861 throw dataFactory.markCorrupt(se); 863 } 864 865 String firstImage = pagedataToHexDump(corruptPage); 869 String secondImage = 870 (SanityManager.DEBUG) ? 871 toString() : pagedataToHexDump(corruptPage); 872 873 throw StandardException.newException( 874 SQLState.FILE_IO_GARBLED, se, 875 newIdentity, firstImage, secondImage); 876 } 877 else 878 { 879 throw se; 880 } 881 } 882 883 884 } 885 886 897 protected void validateChecksum(PageKey id) 898 throws StandardException 899 { 900 long onDiskChecksum; 901 902 try 903 { 904 907 rawDataIn.setPosition(getPageSize() - CHECKSUM_SIZE); 908 onDiskChecksum = rawDataIn.readLong(); 909 } 910 catch (IOException ioe) 911 { 912 913 throw dataFactory.markCorrupt( 915 StandardException.newException( 916 SQLState.DATA_CORRUPT_PAGE, ioe, id)); 917 } 918 919 checksum.reset(); 921 checksum.update(pageData, 0, getPageSize() - CHECKSUM_SIZE); 922 923 if (SanityManager.DEBUG) 925 { 926 if (SanityManager.DEBUG_ON("TEST_BAD_CHECKSUM")) 927 { 928 onDiskChecksum = 123456789; 930 } 931 } 932 933 if (onDiskChecksum != checksum.getValue()) 934 { 935 CRC32 newChecksum = new CRC32 (); 937 newChecksum.reset(); 938 newChecksum.update(pageData, 0, getPageSize()-CHECKSUM_SIZE); 939 if (onDiskChecksum != newChecksum.getValue()) 940 { 941 throw StandardException.newException( 942 SQLState.FILE_BAD_CHECKSUM, 943 id, 944 new Long (checksum.getValue()), 945 new Long (onDiskChecksum), 946 pagedataToHexDump(pageData)); 947 } 948 else 949 { 950 if (SanityManager.DEBUG) 952 SanityManager.THROWASSERT("old checksum gets wrong value"); 953 954 checksum = newChecksum; 955 } 956 } 957 } 958 959 967 protected void updateChecksum() throws IOException 968 { 969 checksum.reset(); 970 checksum.update(pageData, 0, getPageSize() - CHECKSUM_SIZE); 971 972 rawDataOut.setPosition(getPageSize() - CHECKSUM_SIZE); 973 logicalDataOut.writeLong(checksum.getValue()); 974 } 975 976 988 protected void writePage(PageKey identity) 989 throws StandardException 990 { 991 if (SanityManager.DEBUG) 992 { 993 996 if ((freeSpace < 0) || 997 (firstFreeByte + freeSpace) != (getSlotOffset(slotsInUse - 1))) 998 { 999 1002 SanityManager.THROWASSERT("slotsInUse = " + slotsInUse 1003 + ", firstFreeByte = " + firstFreeByte 1004 + ", freeSpace = " + freeSpace 1005 + ", slotOffset = " + (getSlotOffset(slotsInUse - 1)) 1006 + ", page = " + this); 1007 } 1008 1009 if ((slotsInUse == 0) && 1010 (firstFreeByte != (getPageSize() - totalSpace - CHECKSUM_SIZE))) 1011 { 1012 SanityManager.THROWASSERT("slotsInUse = " + slotsInUse 1013 + ", firstFreeByte = " + firstFreeByte 1014 + ", freeSpace = " + freeSpace 1015 + ", slotOffset = " + (getSlotOffset(slotsInUse - 1)) 1016 + ", page = " + this); 1017 } 1018 1019 } 1020 1021 try 1022 { 1023 if (headerOutOfDate) 1024 { 1025 updatePageHeader(); 1026 } 1027 else 1028 { 1029 updatePageVersion(); 1032 } 1033 1034 updateChecksum(); 1035 1036 } 1037 catch (IOException ioe) 1038 { 1039 throw dataFactory.markCorrupt( 1041 StandardException.newException( 1042 SQLState.DATA_CORRUPT_PAGE, ioe, identity)); 1043 } 1044 1045 } 1046 1047 1054 protected void writeFormatId(PageKey identity) throws StandardException 1055 { 1056 try 1057 { 1058 if (rawDataOut == null) 1059 createOutStreams(); 1060 1061 rawDataOut.setPosition(0); 1062 1063 FormatIdUtil.writeFormatIdInteger( 1064 logicalDataOut, getTypeFormatId()); 1065 1066 } 1067 catch (IOException ioe) 1068 { 1069 throw dataFactory.markCorrupt( 1071 StandardException.newException( 1072 SQLState.DATA_CORRUPT_PAGE, ioe, identity)); 1073 } 1074 } 1075 1076 1077 1081 1082 1086 1087 1093 protected void releaseExclusive() 1094 { 1095 super.releaseExclusive(); 1096 1097 pageCache.release(this); 1098 } 1099 1100 1101 1118 public int getTotalSpace(int slot) 1119 throws StandardException 1120 { 1121 try 1122 { 1123 1128 rawDataIn.setPosition(getSlotOffset(slot) + slotFieldSize); 1130 1131 1134 return( 1135 ((slotFieldSize == SMALL_SLOT_SIZE) ? 1136 (rawDataIn.readUnsignedShort() + 1137 rawDataIn.readUnsignedShort()) : 1138 (rawDataIn.readInt() + 1139 rawDataIn.readInt()))); 1140 1141 } 1142 catch (IOException ioe) 1143 { 1144 throw dataFactory.markCorrupt( 1145 StandardException.newException( 1146 SQLState.DATA_CORRUPT_PAGE, ioe, getPageId())); 1147 } 1148 } 1149 1150 1165 public boolean spaceForInsert() 1166 throws StandardException 1167 { 1168 if (slotsInUse == 0) 1170 return(true); 1171 1172 if (!allowInsert()) 1173 return(false); 1174 1175 int usedSpace = totalSpace - freeSpace; 1176 int bytesPerRow = usedSpace / slotsInUse; 1177 1178 return(bytesPerRow <= freeSpace); 1179 } 1180 1181 1200 public boolean spaceForInsert( 1201 Object [] row, 1202 FormatableBitSet validColumns, 1203 int overflowThreshold) 1204 throws StandardException 1205 { 1206 1207 if (slotsInUse == 0) 1209 return true; 1210 1211 if (!allowInsert()) 1214 return false; 1215 1216 DynamicByteArrayOutputStream out = new DynamicByteArrayOutputStream(); 1217 1218 try 1219 { 1220 logRow( 1223 0, true, nextId, row, validColumns, out, 1224 0, Page.INSERT_DEFAULT, -1, -1, overflowThreshold); 1225 1226 } 1227 catch (NoSpaceOnPage nsop) 1228 { 1229 return false; 1230 } 1231 catch (IOException ioe) 1232 { 1233 throw StandardException.newException( 1234 SQLState.DATA_UNEXPECTED_EXCEPTION, ioe); 1235 } 1236 1237 return true; 1238 } 1239 1240 1261 private boolean spaceForInsert( 1262 Object [] row, 1263 FormatableBitSet validColumns, 1264 int spaceNeeded, 1265 int startColumn, 1266 int overflowThreshold) 1267 throws StandardException 1268 { 1269 if (!(spaceForInsert() && (freeSpace >= spaceNeeded))) 1270 return false; 1271 1272 DynamicByteArrayOutputStream out = new DynamicByteArrayOutputStream(); 1273 1274 try 1275 { 1276 logRow( 1277 0, true, nextId, row, validColumns, out, startColumn, 1278 Page.INSERT_DEFAULT, -1, -1, overflowThreshold); 1279 1280 } 1281 catch (NoSpaceOnPage nsop) 1282 { 1283 return false; 1284 } 1285 catch (IOException ioe) 1286 { 1287 throw StandardException.newException( 1288 SQLState.DATA_UNEXPECTED_EXCEPTION, ioe); 1289 } 1290 1291 return true; 1292 } 1293 1294 1304 public boolean unfilled() 1305 { 1306 return (allowInsert() && (freeSpace > (getPageSize() / 2))); 1307 } 1308 1309 1319 public boolean allowInsert() 1320 { 1321 if (slotsInUse == 0) 1323 return true; 1324 1325 int spaceAvailable = freeSpace; 1326 1327 spaceAvailable -= slotEntrySize; 1329 if (spaceAvailable < minimumRecordSize) 1330 return false; 1331 1332 if (((spaceAvailable * 100) / totalSpace) < spareSpace) 1334 return false; 1335 1336 return true; 1337 } 1338 1339 1351 public boolean spaceForCopy(int num_rows, int[] spaceNeeded) 1352 { 1353 int bytesNeeded = slotEntrySize * num_rows; 1355 1356 for (int i = 0; i < num_rows; i++) 1357 { 1358 if (spaceNeeded[i] > 0) 1359 { 1360 1363 bytesNeeded += 1364 (spaceNeeded[i] >= minimumRecordSize ? 1365 spaceNeeded[i] : minimumRecordSize); 1366 } 1367 } 1368 1369 return((freeSpace - bytesNeeded) >= 0); 1370 } 1371 1372 protected boolean spaceForCopy(int spaceNeeded) 1373 { 1374 int bytesNeeded = slotEntrySize + 1377 (spaceNeeded >= minimumRecordSize ? 1378 spaceNeeded : minimumRecordSize); 1379 1380 return((freeSpace - bytesNeeded) >= 0); 1381 } 1382 1383 1424 protected boolean restoreRecordFromSlot( 1425 int slot, 1426 Object [] row, 1427 FetchDescriptor fetchDesc, 1428 RecordHandle recordToLock, 1429 StoredRecordHeader recordHeader, 1430 boolean isHeadRow) 1431 throws StandardException 1432 { 1433 try 1434 { 1435 int offset_to_row_data = 1436 getRecordOffset(slot) + recordHeader.size(); 1437 1438 if (SanityManager.DEBUG) 1439 { 1440 if (getRecordOffset(slot) < 1441 (PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE)) 1442 { 1443 SanityManager.THROWASSERT( 1444 "Incorrect offset. offset = " + 1445 getRecordOffset(slot) + 1446 ", offset should be < " + 1447 "(PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE) = " + 1448 (PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE) + 1449 ", current slot = " + slot + 1450 ", total slotsInUse = " + slotsInUse); 1451 } 1452 1453 SanityManager.ASSERT( 1454 isHeadRow, "restoreRecordFromSlot called on a non-headrow"); 1455 SanityManager.ASSERT( 1456 !isOverflowPage(), 1457 "restoreRecordFromSlot called on an overflow page."); 1458 } 1459 1460 ArrayInputStream lrdi = rawDataIn; 1463 lrdi.setPosition(offset_to_row_data); 1464 1465 if (!recordHeader.hasOverflow()) 1466 { 1467 if (isHeadRow) 1468 { 1469 if (fetchDesc != null && 1470 fetchDesc.getQualifierList() != null) 1471 { 1472 fetchDesc.reset(); 1473 1474 if (!qualifyRecordFromSlot( 1475 row, 1476 offset_to_row_data, 1477 fetchDesc, 1478 recordHeader, 1479 recordToLock)) 1480 { 1481 return(false); 1482 } 1483 else 1484 { 1485 lrdi.setPosition(offset_to_row_data); 1487 } 1488 } 1489 } 1490 1491 if (fetchDesc != null) 1498 { 1499 readRecordFromArray( 1500 row, 1501 (fetchDesc.getValidColumns() == null) ? 1502 row.length -1 : fetchDesc.getMaxFetchColumnId(), 1503 fetchDesc.getValidColumnsArray(), 1504 fetchDesc.getMaterializedColumns(), 1505 lrdi, 1506 recordHeader, 1507 (ErrorObjectInput) null , 1508 recordToLock); 1509 } 1510 else 1511 { 1512 readRecordFromArray( 1513 row, 1514 row.length - 1, 1515 (int[]) null, 1516 (int[]) null, 1517 lrdi, 1518 recordHeader, 1519 (ErrorObjectInput) null , 1520 recordToLock); 1521 } 1522 1523 return(true); 1524 } 1525 else 1526 { 1527 if (fetchDesc != null) 1528 { 1529 if (fetchDesc.getQualifierList() != null) 1530 { 1531 fetchDesc.reset(); 1532 } 1533 1534 readRecordFromArray( 1535 row, 1536 (fetchDesc.getValidColumns() == null) ? 1537 row.length - 1 : fetchDesc.getMaxFetchColumnId(), 1538 fetchDesc.getValidColumnsArray(), 1539 fetchDesc.getMaterializedColumns(), 1540 lrdi, 1541 recordHeader, 1542 (ErrorObjectInput) null , 1543 recordToLock); 1544 } 1545 else 1546 { 1547 readRecordFromArray( 1548 row, 1549 row.length - 1, 1550 (int[]) null, 1551 (int[]) null, 1552 lrdi, 1553 recordHeader, 1554 (ErrorObjectInput) null , 1555 recordToLock); 1556 } 1557 1558 while (recordHeader != null) 1561 { 1562 StoredPage overflowPage = 1566 getOverflowPage(recordHeader.getOverflowPage()); 1567 1568 if (SanityManager.DEBUG) 1569 { 1570 if (overflowPage == null) 1571 SanityManager.THROWASSERT( 1572 "cannot get overflow page"); 1573 } 1574 1575 recordHeader = 1582 overflowPage.restoreLongRecordFromSlot( 1583 row, 1584 fetchDesc, 1585 recordToLock, 1586 recordHeader); 1587 1588 overflowPage.unlatch(); 1589 overflowPage = null; 1590 } 1591 1592 1594 if ((fetchDesc != null) && 1595 (fetchDesc.getQualifierList() != null)) 1596 { 1597 if (!qualifyRecordFromRow( 1598 row, fetchDesc.getQualifierList())) 1599 { 1600 return(false); 1601 } 1602 } 1603 1604 return(true); 1605 } 1606 } 1607 catch (IOException ioe) 1608 { 1609 1610 if (SanityManager.DEBUG) 1611 { 1612 if (pageData == null) 1613 { 1614 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 1615 "caught an IOException in restoreRecordFromSlot " + 1616 (PageKey)getIdentity() + " slot " + slot + 1617 ", pageData is null"); 1618 } 1619 else 1620 { 1621 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 1622 "caught an IOException in reestoreRecordFromSlot, " + 1623 (PageKey)getIdentity() + " slot " + slot + 1624 ", pageData.length = " + 1625 pageData.length + " pageSize = " + getPageSize()); 1626 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 1627 "Hex dump of pageData \n " + 1628 "--------------------------------------------------\n" + 1629 pagedataToHexDump(pageData) + 1630 "--------------------------------------------------\n"); 1631 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 1632 "Attempt to dump page " + this.toString()); 1633 } 1634 } 1635 1636 throw dataFactory.markCorrupt( 1638 StandardException.newException( 1639 SQLState.DATA_CORRUPT_PAGE, ioe, getPageId())); 1640 } 1641 } 1642 1643 private StoredRecordHeader restoreLongRecordFromSlot( 1644 Object [] row, 1645 FetchDescriptor fetchDesc, 1646 RecordHandle recordToLock, 1647 StoredRecordHeader parent_recordHeader) 1648 throws StandardException 1649 { 1650 1651 int slot = 1652 findRecordById( 1653 parent_recordHeader.getOverflowId(), Page.FIRST_SLOT_NUMBER); 1654 1655 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 1656 1657 try 1658 { 1659 int offset_to_row_data = 1660 getRecordOffset(slot) + recordHeader.size(); 1661 1662 if (SanityManager.DEBUG) 1663 { 1664 if (getRecordOffset(slot) < 1665 (PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE)) 1666 { 1667 SanityManager.THROWASSERT( 1668 "Incorrect offset. offset = " + 1669 getRecordOffset(slot) + 1670 ", offset should be < " + 1671 "(PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE) = " + 1672 (PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE) + 1673 ", current slot = " + slot + 1674 ", total slotsInUse = " + slotsInUse); 1675 } 1676 } 1677 1678 ArrayInputStream lrdi = rawDataIn; 1681 lrdi.setPosition(offset_to_row_data); 1682 1683 if (fetchDesc != null) 1684 { 1685 if (fetchDesc.getQualifierList() != null) 1686 { 1687 fetchDesc.reset(); 1688 } 1689 1690 readRecordFromArray( 1691 row, 1692 (fetchDesc.getValidColumns() == null) ? 1693 row.length - 1 : fetchDesc.getMaxFetchColumnId(), 1694 fetchDesc.getValidColumnsArray(), 1695 fetchDesc.getMaterializedColumns(), 1696 lrdi, 1697 recordHeader, 1698 (ErrorObjectInput) null , 1699 recordToLock); 1700 } 1701 else 1702 { 1703 readRecordFromArray( 1704 row, 1705 row.length - 1, 1706 (int[]) null, 1707 (int[]) null, 1708 lrdi, 1709 recordHeader, 1710 (ErrorObjectInput) null , 1711 recordToLock); 1712 } 1713 1714 return(recordHeader.hasOverflow() ? recordHeader : null); 1715 } 1716 catch (IOException ioe) 1717 { 1718 if (SanityManager.DEBUG) 1719 { 1720 if (pageData == null) 1721 { 1722 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 1723 "caught an IOException in restoreRecordFromSlot " + 1724 (PageKey)getIdentity() + " slot " + slot + 1725 ", pageData is null"); 1726 } 1727 else 1728 { 1729 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 1730 "caught an IOException in reestoreRecordFromSlot, " + 1731 (PageKey)getIdentity() + " slot " + slot + 1732 ", pageData.length = " + 1733 pageData.length + " pageSize = " + getPageSize()); 1734 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 1735 "Hex dump of pageData \n " + 1736 "--------------------------------------------------\n" + 1737 pagedataToHexDump(pageData) + 1738 "--------------------------------------------------\n"); 1739 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 1740 "Attempt to dump page " + this.toString()); 1741 } 1742 } 1743 1744 throw dataFactory.markCorrupt( 1746 StandardException.newException( 1747 SQLState.DATA_CORRUPT_PAGE, ioe, getPageId())); 1748 } 1749 } 1750 1751 1761 public int newRecordId() 1762 { 1763 return nextId; 1764 } 1765 1766 1777 public int newRecordIdAndBump() 1778 { 1779 headerOutOfDate = true; 1782 1783 return nextId++; 1784 } 1785 1786 1787 1802 protected int newRecordId(int recordId) 1803 { 1804 if (SanityManager.DEBUG) 1805 { 1806 SanityManager.ASSERT( 1807 recordId >= nextId, 1808 "should not create a record Id that is already given out"); 1809 } 1810 1811 return recordId + 1; 1812 } 1813 1814 public boolean isOverflowPage() 1815 { 1816 return isOverflowPage; 1817 } 1818 1819 1820 1821 1825 1826 1829 public final int getPageSize() 1830 { 1831 return pageData.length; 1832 } 1833 1834 1835 1839 protected final void clearSection(int offset, int length) 1840 { 1841 int endOffset = offset + length; 1842 1843 while (offset < endOffset) 1844 pageData[offset++] = 0; 1845 } 1846 1847 1857 protected int getMaxFreeSpace() 1858 { 1859 return getPageSize() - RECORD_SPACE_OFFSET - CHECKSUM_SIZE; 1860 } 1861 1862 1865 protected int getCurrentFreeSpace() 1866 { 1867 return freeSpace; 1868 } 1869 1870 1874 1875 1881 private void readPageHeader() 1882 throws IOException 1883 { 1884 ArrayInputStream lrdi = rawDataIn; 1886 1887 lrdi.setPosition(PAGE_HEADER_OFFSET); 1888 long spare; 1889 1890 isOverflowPage = lrdi.readBoolean(); 1891 setPageStatus (lrdi.readByte()); 1892 setPageVersion (lrdi.readLong()); 1893 slotsInUse = lrdi.readUnsignedShort(); 1894 nextId = lrdi.readInt(); 1895 generation = lrdi.readInt(); prevGeneration = lrdi.readInt(); bipLocation = lrdi.readLong(); 1899 deletedRowCount = lrdi.readUnsignedShort() - 1; 1902 1903 spare = lrdi.readUnsignedShort(); 1905 spare = lrdi.readInt(); spare = lrdi.readLong(); 1907 spare = lrdi.readLong(); 1908 } 1909 1910 1911 1917 private void updatePageHeader() 1918 throws IOException 1919 { 1920 rawDataOut.setPosition(PAGE_HEADER_OFFSET); 1921 1922 logicalDataOut.writeBoolean(isOverflowPage); 1923 logicalDataOut.writeByte(getPageStatus()); 1924 logicalDataOut.writeLong(getPageVersion()); 1925 logicalDataOut.writeShort(slotsInUse); 1926 logicalDataOut.writeInt(nextId); 1927 logicalDataOut.writeInt(generation); logicalDataOut.writeInt(prevGeneration); logicalDataOut.writeLong(bipLocation); 1931 logicalDataOut.writeShort(deletedRowCount + 1); 1935 1936 logicalDataOut.writeShort(0); logicalDataOut.writeInt( 1938 dataFactory.random()); logicalDataOut.writeLong(0); logicalDataOut.writeLong(0); 1942 1950 headerOutOfDate = false; 1951 } 1952 1953 1956 private void updatePageVersion() 1957 throws IOException 1958 { 1959 rawDataOut.setPosition(PAGE_VERSION_OFFSET); 1960 logicalDataOut.writeLong(getPageVersion()); 1961 } 1962 1963 1967 1968 1978 private int getSlotOffset(int slot) 1979 { 1980 1983 return(slotTableOffsetToFirstEntry - (slot * slotEntrySize)); 1984 } 1985 1986 1995 private int getRecordOffset(int slot) 1996 { 1997 byte[] data = pageData; 1998 int offset = slotTableOffsetToFirstEntry - (slot * slotEntrySize); 1999 2000 2008 return( 2009 (slotFieldSize == SMALL_SLOT_SIZE) ? 2010 2011 ((data[offset++] & 0xff) << 8) | 2012 (data[offset] & 0xff) : 2013 2014 (((data[offset++] & 0xff) << 24) | 2015 ((data[offset++] & 0xff) << 16) | 2016 ((data[offset++] & 0xff) << 8) | 2017 ((data[offset] & 0xff) ))); 2018 } 2019 2020 2028 private void setRecordOffset(int slot, int recordOffset) 2029 throws IOException 2030 { 2031 rawDataOut.setPosition(getSlotOffset(slot)); 2032 2033 if (slotFieldSize == SMALL_SLOT_SIZE) 2034 logicalDataOut.writeShort(recordOffset); 2035 else 2036 logicalDataOut.writeInt(recordOffset); 2037 } 2038 2039 2051 protected int getRecordPortionLength(int slot) 2052 throws IOException 2053 { 2054 if (SanityManager.DEBUG) 2055 { 2056 SanityManager.ASSERT(getRecordOffset(slot) != 0); 2057 } 2058 2059 ArrayInputStream lrdi = rawDataIn; 2061 2062 lrdi.setPosition( 2063 slotTableOffsetToFirstRecordLengthField - (slot * slotEntrySize)); 2064 2065 return( 2066 (slotFieldSize == SMALL_SLOT_SIZE) ? 2067 lrdi.readUnsignedShort() : lrdi.readInt()); 2068 } 2069 2070 2081 public int getReservedCount(int slot) throws IOException 2082 { 2083 if (SanityManager.DEBUG) 2084 { 2085 SanityManager.ASSERT(getRecordOffset(slot) != 0); 2086 } 2087 2088 ArrayInputStream lrdi = rawDataIn; 2090 2091 lrdi.setPosition( 2092 slotTableOffsetToFirstReservedSpaceField - (slot * slotEntrySize)); 2093 2094 return( 2095 (slotFieldSize == SMALL_SLOT_SIZE) ? 2096 lrdi.readUnsignedShort() : lrdi.readInt()); 2097 } 2098 2099 2100 2103 2119 private void updateRecordPortionLength( 2120 int slot, 2121 int delta, 2122 int reservedDelta) 2123 throws IOException 2124 { 2125 if (SanityManager.DEBUG) 2126 { 2127 SanityManager.ASSERT(getRecordOffset(slot) != 0); 2128 2129 if ((delta + reservedDelta) < 0) 2130 SanityManager.THROWASSERT( 2131 "total space of record is not allowed to shrink, delta == " 2132 + delta + " reservedDelta = " + reservedDelta); 2133 2134 if ((getRecordPortionLength(slot) + delta) < 0) 2135 SanityManager.THROWASSERT( 2136 "record portion length cannot be < 0.recordPortionLength = " 2137 + getRecordPortionLength(slot) + " delta = " + delta); 2138 2139 if ((getReservedCount(slot) + reservedDelta) < 0) 2140 SanityManager.THROWASSERT( 2141 "reserved space for record cannot be < 0. reservedCount = " 2142 + getReservedCount(slot) + " reservedDelta = " 2143 + reservedDelta); 2144 } 2145 2146 rawDataOut.setPosition( 2148 slotTableOffsetToFirstRecordLengthField - (slot * slotEntrySize)); 2149 2150 if (slotFieldSize == SMALL_SLOT_SIZE) 2152 logicalDataOut.writeShort(getRecordPortionLength(slot) + delta); 2153 else 2154 logicalDataOut.writeInt(getRecordPortionLength(slot) + delta); 2155 2156 if (reservedDelta != 0) 2159 { 2160 if (slotFieldSize == SMALL_SLOT_SIZE) 2161 { 2162 logicalDataOut.writeShort( 2163 getReservedCount(slot) + reservedDelta); 2164 } 2165 else 2166 { 2167 logicalDataOut.writeInt( 2168 getReservedCount(slot) + reservedDelta); 2169 } 2170 } 2171 } 2172 2173 2183 private void initSlotTable() 2184 throws StandardException 2185 { 2186 int localSlotsInUse = slotsInUse; 2187 2188 initializeHeaders(localSlotsInUse); 2190 2191 clearAllSpace(); 2193 2194 freeSpace -= localSlotsInUse * slotEntrySize; 2196 2197 int lastSlotOnPage = -1; 2198 int lastRecordOffset = -1; 2199 2200 try 2201 { 2202 for (int slot = 0; slot < localSlotsInUse; slot++) 2203 { 2204 if (SanityManager.DEBUG) 2205 { 2206 if (!isOverflowPage() && 2207 minimumRecordSize > getTotalSpace(slot)) 2208 { 2209 SanityManager.THROWASSERT( 2210 " slot " + slot + 2211 " minimumRecordSize = " + minimumRecordSize + 2212 " totalSpace = " + getTotalSpace(slot) + 2213 "recordPortionLength = " + 2214 getRecordPortionLength(slot) 2215 + " reservedCount = " + getReservedCount(slot)); 2216 } 2217 } 2218 2219 int recordOffset = getRecordOffset(slot); 2220 2221 if ((recordOffset < RECORD_SPACE_OFFSET) || 2223 (recordOffset >= (getPageSize() - CHECKSUM_SIZE))) 2224 { 2225 throw dataFactory.markCorrupt( 2226 StandardException.newException( 2227 SQLState.DATA_CORRUPT_PAGE, getPageId())); 2228 } 2229 2230 if (recordOffset > lastRecordOffset) 2231 { 2232 lastRecordOffset = recordOffset; 2233 lastSlotOnPage = slot; 2234 } 2235 } 2236 2237 bumpRecordCount(localSlotsInUse); 2238 2239 if (lastSlotOnPage != -1) 2240 { 2241 2244 firstFreeByte = 2245 lastRecordOffset + getTotalSpace(lastSlotOnPage); 2246 freeSpace -= firstFreeByte - RECORD_SPACE_OFFSET; 2247 } 2248 2249 if (SanityManager.DEBUG) 2250 { 2251 if ((freeSpace < 0) || 2252 ((firstFreeByte + freeSpace) != 2253 (getSlotOffset(slotsInUse - 1)))) 2254 { 2255 SanityManager.THROWASSERT( 2256 "firstFreeByte = " + firstFreeByte 2257 + ", freeSpace = " + freeSpace 2258 + ", slotOffset = " + (getSlotOffset(slotsInUse - 1)) 2259 + ", slotsInUse = " + localSlotsInUse); 2260 } 2261 2262 if (localSlotsInUse == 0) 2263 { 2264 SanityManager.ASSERT( 2265 firstFreeByte == 2266 (getPageSize() - totalSpace - CHECKSUM_SIZE)); 2267 } 2268 } 2269 2270 if (deletedRowCount == -1) 2274 { 2275 int count = 0; 2276 int maxSlot = slotsInUse; 2277 for (int slot = FIRST_SLOT_NUMBER ; slot < maxSlot; slot++) 2278 { 2279 if (isDeletedOnPage(slot)) 2280 count++; 2281 } 2282 deletedRowCount = count; 2283 } 2284 2285 } 2286 catch (IOException ioe) 2287 { 2288 throw dataFactory.markCorrupt( 2290 StandardException.newException( 2291 SQLState.DATA_CORRUPT_PAGE, ioe, getPageId())); 2292 } 2293 } 2294 2295 2296 2307 private void setSlotEntry( 2308 int slot, 2309 int recordOffset, 2310 int recordPortionLength, 2311 int reservedSpace) 2312 throws IOException 2313 { 2314 rawDataOut.setPosition(getSlotOffset(slot)); 2315 2316 if (SanityManager.DEBUG) 2317 { 2318 if ((recordPortionLength < 0) || 2319 (reservedSpace < 0) || 2320 (recordPortionLength >= getPageSize()) || 2321 (reservedSpace >= getPageSize())) 2322 { 2323 SanityManager.THROWASSERT( 2324 "recordPortionLength and reservedSpace must " + 2325 "be > 0, and < page size." 2326 + " slot = " + slot 2327 + ", in use = " + slotsInUse 2328 + ", recordOffset = " + recordOffset 2329 + ", recordPortionLength = " + recordPortionLength 2330 + ", reservedSpace = " + reservedSpace); 2331 } 2332 2333 if (recordOffset < (PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE)) 2334 { 2335 SanityManager.THROWASSERT( 2336 "Record offset must be after the page header." 2337 + " slot = " + slot 2338 + ", in use = " + slotsInUse 2339 + ", recordOffset = " + recordOffset 2340 + ", recordPortionLength = " + recordPortionLength 2341 + ", reservedSpace = " + reservedSpace); 2342 } 2343 } 2344 2345 if (slotFieldSize == SMALL_SLOT_SIZE) 2346 { 2347 logicalDataOut.writeShort(recordOffset); 2348 logicalDataOut.writeShort(recordPortionLength); 2349 logicalDataOut.writeShort(reservedSpace); 2350 } 2351 else 2352 { 2353 logicalDataOut.writeInt(recordOffset); 2354 logicalDataOut.writeInt(recordPortionLength); 2355 logicalDataOut.writeInt(reservedSpace); 2356 } 2357 } 2358 2359 2372 private void addSlotEntry( 2373 int slot, 2374 int recordOffset, 2375 int recordPortionLength, 2376 int reservedSpace) 2377 throws IOException 2378 { 2379 if (SanityManager.DEBUG) 2380 { 2381 if ((slot < 0) || (slot > slotsInUse)) 2382 SanityManager.THROWASSERT("invalid slot " + slot); 2383 2384 if ((recordPortionLength < 0) || (reservedSpace < 0)) 2385 SanityManager.THROWASSERT( 2386 "recordPortionLength and reservedSpace must be > 0." + 2387 "recordPortionLength = " + recordPortionLength + 2388 " reservedSpace = " + reservedSpace); 2389 2390 if (recordOffset < (PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE)) 2391 { 2392 SanityManager.THROWASSERT( 2393 "Record offset must be after the page header." 2394 + " slot = " + slot 2395 + ", in use = " + slotsInUse 2396 + ", recordOffset = " + recordOffset 2397 + ", recordPortionLength = " + recordPortionLength 2398 + ", reservedSpace = " + reservedSpace); 2399 } 2400 } 2401 2402 int newSlotOffset; 2403 2404 2406 if (slot < slotsInUse) 2407 { 2408 2411 int startOffset = 2412 getSlotOffset(slotsInUse - 1); 2413 2414 int length = 2415 (getSlotOffset(slot) + slotEntrySize) - startOffset; 2416 2417 newSlotOffset = getSlotOffset(slotsInUse); 2418 2419 System.arraycopy( 2420 pageData, startOffset, pageData, newSlotOffset, length); 2421 } 2422 else 2423 { 2424 newSlotOffset = getSlotOffset(slot); 2426 } 2427 2428 freeSpace -= slotEntrySize; 2429 2430 slotsInUse++; 2431 headerOutOfDate = true; 2434 setSlotEntry(slot, recordOffset, recordPortionLength, reservedSpace); 2435 } 2436 2437 2447 private void removeSlotEntry(int slot) 2448 throws IOException 2449 { 2450 if (SanityManager.DEBUG) 2451 { 2452 if ((slot < 0) || (slot >= slotsInUse)) 2453 SanityManager.THROWASSERT("invalid slot " + slot); 2454 } 2455 2456 int oldEndOffset = getSlotOffset(slotsInUse - 1); 2457 int newEndOffset = getSlotOffset(slotsInUse - 2); 2458 2459 if (slot != slotsInUse - 1) 2460 { 2461 2463 int length = getSlotOffset(slot) - oldEndOffset; 2466 2467 System.arraycopy( 2468 pageData, oldEndOffset, pageData, newEndOffset, length); 2469 } 2470 2471 clearSection(oldEndOffset, slotEntrySize); 2473 2474 freeSpace += slotEntrySize; 2478 2479 slotsInUse--; 2480 2481 headerOutOfDate = true; } 2484 2485 2498 public StoredRecordHeader recordHeaderOnDemand(int slot) 2499 { 2500 StoredRecordHeader recordHeader = 2501 new StoredRecordHeader(pageData, getRecordOffset(slot)); 2502 2503 setHeaderAtSlot(slot, recordHeader); 2504 2505 return recordHeader; 2506 } 2507 2508 2512 2513 2524 public boolean entireRecordOnPage(int slot) 2525 throws StandardException 2526 { 2527 if (SanityManager.DEBUG) 2528 { 2529 SanityManager.ASSERT(isLatched()); 2530 } 2531 2532 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 2533 2534 if (recordHeader.hasOverflow()) 2535 return false; 2536 2537 2540 try 2541 { 2542 2543 int offset = getRecordOffset(slot); 2544 2545 if (SanityManager.DEBUG) 2546 { 2547 if (offset < (PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE)) 2548 { 2549 SanityManager.THROWASSERT( 2550 "Incorrect offset. offset = " + offset + 2551 ", offset should be < " + 2552 "(PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE) = " + 2553 (PAGE_HEADER_OFFSET + PAGE_HEADER_SIZE) + 2554 ", current slot = " + slot + 2555 ", total slotsInUse = " + slotsInUse); 2556 } 2557 2558 SanityManager.ASSERT(recordHeader.getFirstField() == 0, 2559 "Head row piece should start at field 0 but is not"); 2560 } 2561 2562 int numberFields = recordHeader.getNumberFields(); 2563 2564 ArrayInputStream lrdi = rawDataIn; 2566 2567 lrdi.setPosition(offset + recordHeader.size()); 2569 2570 for (int i = 0; i < numberFields; i++) 2571 { 2572 int fieldStatus = StoredFieldHeader.readStatus(lrdi); 2573 if (StoredFieldHeader.isOverflow(fieldStatus)) 2574 return false; 2575 2576 int fieldLength = 2577 StoredFieldHeader.readFieldDataLength( 2578 lrdi, fieldStatus, slotFieldSize); 2579 2580 if (fieldLength != 0) 2581 lrdi.setPosition(lrdi.getPosition() + fieldLength); 2582 } 2583 } 2584 catch (IOException ioe) 2585 { 2586 throw dataFactory.markCorrupt( 2587 StandardException.newException( 2588 SQLState.DATA_CORRUPT_PAGE, ioe, getPageId())); 2589 } 2590 2591 return true; 2593 } 2594 2595 2607 protected void purgeOverflowAtSlot( 2608 int slot, 2609 RecordHandle headRowHandle, 2610 boolean needDataLogged) 2611 throws StandardException 2612 { 2613 if (SanityManager.DEBUG) 2614 { 2615 SanityManager.ASSERT(isLatched()); 2616 SanityManager.ASSERT(isOverflowPage()); 2617 } 2618 2619 if ((slot < 0) || (slot >= slotsInUse)) 2620 { 2621 throw StandardException.newException( 2622 SQLState.DATA_SLOT_NOT_ON_PAGE); 2623 } 2624 2625 2627 RawTransaction t = owner.getTransaction(); 2631 int[] recordId = new int[1]; 2632 2633 recordId[0] = getHeaderAtSlot(slot).getId(); 2634 2635 owner.getActionSet().actionPurge(t, this, slot, 1, recordId, needDataLogged); 2636 } 2637 2638 2654 private void purgeOneColumnChain( 2655 long overflowPageId, 2656 int overflowRecordId) 2657 throws StandardException 2658 { 2659 StoredPage pageOnColumnChain = null; 2660 boolean removePageHappened = false; 2661 2662 try 2663 { 2664 while (overflowPageId != ContainerHandle.INVALID_PAGE_NUMBER) 2665 { 2666 2667 pageOnColumnChain = getOverflowPage(overflowPageId); 2669 removePageHappened = false; 2670 2671 if (pageOnColumnChain == null) 2672 { 2673 if (SanityManager.DEBUG) 2674 SanityManager.THROWASSERT( 2675 "got null page following long column chain. " + 2676 "Head column piece at " + getIdentity() + 2677 " null page at " + overflowPageId); 2678 2679 break; } 2682 2683 int overflowSlotId = FIRST_SLOT_NUMBER; 2684 if (SanityManager.DEBUG) 2685 { 2686 int checkSlot = 2687 pageOnColumnChain.findRecordById( 2688 overflowRecordId, FIRST_SLOT_NUMBER); 2689 2690 if (overflowSlotId != checkSlot) 2691 { 2692 SanityManager.THROWASSERT( 2693 "Long column is not at the expected " + 2694 FIRST_SLOT_NUMBER + " slot, instead at slot " + 2695 checkSlot); 2696 } 2697 2698 SanityManager.ASSERT(pageOnColumnChain.recordCount() == 1, 2699 "long column page has > 1 record"); 2700 } 2701 2702 RecordHandle nextColumnPiece = 2705 pageOnColumnChain.getNextColumnPiece(overflowSlotId); 2706 2707 if (pageOnColumnChain.recordCount() == 1) 2708 { 2709 removePageHappened = true; 2710 owner.removePage(pageOnColumnChain); 2711 } 2712 else 2713 { 2714 if (SanityManager.DEBUG) 2715 SanityManager.THROWASSERT( 2716 "page on column chain has more then one record" + 2717 pageOnColumnChain.toString()); 2718 2719 pageOnColumnChain.unlatch(); 2720 pageOnColumnChain = null; 2721 } 2722 2723 if (nextColumnPiece != null) 2725 { 2726 overflowPageId = nextColumnPiece.getPageNumber(); 2727 overflowRecordId = nextColumnPiece.getId(); 2728 } 2729 else 2730 { 2731 overflowPageId = ContainerHandle.INVALID_PAGE_NUMBER; 2733 } 2734 } 2735 } 2736 finally 2737 { 2738 2741 if (!removePageHappened && pageOnColumnChain != null) 2742 { 2743 pageOnColumnChain.unlatch(); 2744 pageOnColumnChain = null; 2745 } 2746 } 2747 } 2748 2749 2766 private void purgeColumnChains( 2767 RawTransaction t, 2768 int slot, 2769 RecordHandle headRowHandle) 2770 throws StandardException 2771 { 2772 try 2773 { 2774 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 2775 2776 int numberFields = recordHeader.getNumberFields(); 2777 2778 ArrayInputStream lrdi = rawDataIn; 2780 2781 int offset = getRecordOffset(slot) + recordHeader.size(); 2783 lrdi.setPosition(offset); 2784 2785 for (int i = 0; i < numberFields; i++) 2786 { 2787 int fieldStatus = StoredFieldHeader.readStatus(lrdi); 2788 int fieldLength = 2789 StoredFieldHeader.readFieldDataLength( 2790 lrdi, fieldStatus, slotFieldSize); 2791 2792 if (!StoredFieldHeader.isOverflow(fieldStatus)) 2793 { 2794 if (fieldLength != 0) 2796 lrdi.setPosition(lrdi.getPosition() + fieldLength); 2797 continue; 2798 } 2799 else 2800 { 2801 2802 2806 long overflowPageId = 2807 CompressedNumber.readLong((InputStream)lrdi); 2808 int overflowRecordId = 2809 CompressedNumber.readInt((InputStream)lrdi); 2810 2811 purgeOneColumnChain(overflowPageId, overflowRecordId); 2812 } 2813 } 2814 } 2815 catch (IOException ioe) 2816 { 2817 throw dataFactory.markCorrupt( 2818 StandardException.newException( 2819 SQLState.DATA_CORRUPT_PAGE, ioe, getPageId())); 2820 } 2821 } 2822 2823 2838 protected void purgeRowPieces( 2839 RawTransaction t, 2840 int slot, 2841 RecordHandle headRowHandle, 2842 boolean needDataLogged) 2843 throws StandardException 2844 { 2845 if (SanityManager.DEBUG) 2846 SanityManager.ASSERT(isOverflowPage() == false, 2847 "not expected to call purgeRowPieces on a overflow page"); 2848 2849 purgeColumnChains(t, slot, headRowHandle); 2851 2852 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 2855 2856 while (recordHeader.hasOverflow()) 2857 { 2858 2859 StoredPage nextPageInRowChain = 2861 getOverflowPage(recordHeader.getOverflowPage()); 2862 2863 if (nextPageInRowChain == null) 2864 { 2865 if (SanityManager.DEBUG) 2866 { 2867 SanityManager.THROWASSERT( 2868 "got null page following long row chain. " + 2869 "Head row piece at " + getIdentity() + " slot " + 2870 slot + " headRecord " + headRowHandle + 2871 ". Broken row chain at " + 2872 recordHeader.getOverflowPage() + ", " + 2873 recordHeader.getOverflowId()); 2874 2875 } 2876 2877 break; } 2880 2881 try 2882 { 2883 2884 int nextPageSlot = 2885 getOverflowSlot(nextPageInRowChain, recordHeader); 2886 2887 nextPageInRowChain.purgeColumnChains( 2889 t, nextPageSlot, headRowHandle); 2890 2891 recordHeader = nextPageInRowChain.getHeaderAtSlot(nextPageSlot); 2894 2895 2902 if (nextPageSlot == 0 && nextPageInRowChain.recordCount() == 1) 2903 { 2904 2909 try 2910 { 2911 owner.removePage(nextPageInRowChain); 2912 } 2913 finally 2914 { 2915 nextPageInRowChain = null; 2919 } 2920 } 2921 else 2922 { 2923 nextPageInRowChain.purgeOverflowAtSlot( 2924 nextPageSlot, headRowHandle, needDataLogged); 2925 2926 nextPageInRowChain.unlatch(); 2927 nextPageInRowChain = null; 2928 } 2929 } 2930 finally 2931 { 2932 if (nextPageInRowChain != null) 2935 { 2936 nextPageInRowChain.unlatch(); 2937 nextPageInRowChain = null; 2938 } 2939 } 2940 } 2941 } 2942 2943 2944 2961 2962 void removeOrphanedColumnChain( 2963 ReclaimSpace work, 2964 ContainerHandle containerHdl) 2965 throws StandardException 2966 { 2967 StoredPage headOfChain = 2981 (StoredPage)containerHdl.getPageNoWait(work.getColumnPageId()); 2982 2983 if (headOfChain == null) 2985 return; 2986 2987 boolean pageUnchanged = 2989 headOfChain.equalTimeStamp(work.getPageTimeStamp()); 2990 2991 headOfChain.unlatch(); 2993 if (pageUnchanged == false) 2994 return; 2995 2996 2999 RecordHandle headRowHandle = work.getHeadRowHandle(); 3000 3001 if (SanityManager.DEBUG) 3002 { 3003 3008 SanityManager.ASSERT(isLatched()); 3009 SanityManager.ASSERT( 3010 headRowHandle.getPageNumber() == getPageNumber(), 3011 "got wrong head page"); 3012 } 3013 3014 int slot = 3016 findRecordById( 3017 headRowHandle.getId(), headRowHandle.getSlotNumberHint()); 3018 3019 3022 if (slot >= 0) 3023 { 3024 if (SanityManager.DEBUG) 3025 { 3026 if (isOverflowPage()) 3027 { 3028 SanityManager.THROWASSERT( 3029 "Page " + getPageNumber() + " is overflow " + 3030 "\nwork = " + work + 3031 "\nhead = " + headOfChain + 3032 "\nthis = " + this); 3033 } 3034 } 3035 3036 StoredPage pageInRowChain = this; 3039 try 3040 { 3041 3042 int columnId = work.getColumnId(); 3043 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 3044 3045 if (SanityManager.DEBUG) 3046 SanityManager.ASSERT(recordHeader.getFirstField() == 0, 3047 "Head row piece should start at field 0 but is not"); 3048 3049 while ((recordHeader.getNumberFields() + 3051 recordHeader.getFirstField()) <= columnId) 3052 { 3053 3055 if (pageInRowChain != this) 3056 { 3057 pageInRowChain.unlatch(); 3059 pageInRowChain = null; 3060 } 3061 3062 if (recordHeader.hasOverflow()) 3063 { 3064 pageInRowChain = 3066 getOverflowPage(recordHeader.getOverflowPage()); 3067 recordHeader = 3068 pageInRowChain.getHeaderAtSlot( 3069 getOverflowSlot(pageInRowChain, recordHeader)); 3070 } 3071 else 3072 { 3073 break; 3078 } 3079 } 3080 3081 if ((recordHeader.getNumberFields() + 3082 recordHeader.getFirstField()) > columnId) 3083 { 3084 if (!pageInRowChain.isColumnOrphaned( 3088 recordHeader, columnId, 3089 work.getColumnPageId(), work.getColumnRecordId())) 3090 { 3091 if (pageInRowChain != this) 3093 { 3094 pageInRowChain.unlatch(); 3096 pageInRowChain = null; 3097 } 3098 return; 3099 } 3100 } 3101 3102 } 3103 catch (IOException ioe) 3104 { 3105 throw StandardException.newException( 3106 SQLState.DATA_UNEXPECTED_EXCEPTION, ioe); 3107 } 3108 finally 3109 { 3110 if (pageInRowChain != this && pageInRowChain != null) 3111 pageInRowChain.unlatch(); 3112 } 3113 } 3114 3115 3118 long nextPageId = work.getColumnPageId(); 3119 int nextRecordId = work.getColumnRecordId(); 3120 3121 purgeOneColumnChain(nextPageId, nextRecordId); 3122 } 3123 3124 3143 private boolean isColumnOrphaned( 3144 StoredRecordHeader recordHeader, 3145 int columnId, 3146 long oldPageId, 3147 long oldRecordId) 3148 throws StandardException, IOException 3149 { 3150 int slot = findRecordById(recordHeader.getId(), Page.FIRST_SLOT_NUMBER); 3151 3152 if (SanityManager.DEBUG) 3153 { 3154 SanityManager.ASSERT(slot >= 0, "overflow row chain truncated"); 3155 3156 SanityManager.ASSERT( 3157 columnId >= recordHeader.getFirstField(), 3158 "first column on page > expected"); 3159 } 3160 3161 ArrayInputStream lrdi = rawDataIn; 3163 3164 int offset = getRecordOffset(slot); 3166 lrdi.setPosition(offset + recordHeader.size()); 3167 3168 for (int i = recordHeader.getFirstField(); i < columnId; i++) 3170 skipField(lrdi); 3171 3172 int fieldStatus = StoredFieldHeader.readStatus(lrdi); 3174 int fieldLength = StoredFieldHeader.readFieldDataLength 3175 (lrdi, fieldStatus, slotFieldSize); 3176 3177 if (StoredFieldHeader.isOverflow(fieldStatus)) 3178 { 3179 3182 long ovflowPage = CompressedNumber.readLong((InputStream) lrdi); 3183 int ovflowRid = CompressedNumber.readInt((InputStream) lrdi); 3184 3185 if (ovflowPage == oldPageId && ovflowRid == oldRecordId) 3186 { 3187 return false; 3190 } 3191 } 3192 3193 return true; 3196 } 3197 3198 3207 3221 private RecordHandle getNextColumnPiece(int slot) 3222 throws StandardException 3223 { 3224 if (SanityManager.DEBUG) 3225 { 3226 SanityManager.ASSERT(isLatched()); 3227 SanityManager.ASSERT(isOverflowPage(), 3228 "not expected to call getNextColumnPiece on non-overflow page"); 3229 3230 if (recordCount() != 1) 3231 { 3232 SanityManager.THROWASSERT( 3233 "getNextColumnPiece called on a page with " + 3234 recordCount() + " rows"); 3235 } 3236 } 3237 3238 try 3239 { 3240 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 3241 int numberFields = 3242 recordHeader.getNumberFields(); 3243 3244 if (SanityManager.DEBUG) 3245 { 3246 if ((numberFields > 2) || (numberFields < 1)) 3247 { 3248 SanityManager.THROWASSERT( 3249 "longColumn record header must have 1 or 2 fields." + 3250 " numberFields = " + numberFields); 3251 } 3252 } 3253 3254 if (numberFields != 2) return null; 3256 3257 ArrayInputStream lrdi = rawDataIn; 3259 3260 3262 int offset = getRecordOffset(slot) + recordHeader.size(); 3263 lrdi.setPosition(offset); 3264 3265 skipField(lrdi); 3267 3268 int fieldStatus = StoredFieldHeader.readStatus(lrdi); 3271 int fieldLength = StoredFieldHeader.readFieldDataLength 3272 (lrdi, fieldStatus, slotFieldSize); 3273 3274 long ovflowPage = CompressedNumber.readLong((InputStream) lrdi); 3275 int ovflowRid = CompressedNumber.readInt((InputStream) lrdi); 3276 3277 if (SanityManager.DEBUG) 3278 { 3279 if (!StoredFieldHeader.isOverflow(fieldStatus)) 3280 { 3281 lrdi.setPosition(offset); 3288 fieldStatus = StoredFieldHeader.readStatus(lrdi); 3289 SanityManager.ASSERT( 3290 StoredFieldHeader.isOverflow(fieldStatus)); 3291 } 3292 } 3293 3294 3299 return owner.makeRecordHandle(ovflowPage, ovflowRid); 3300 3301 } 3302 catch (IOException ioe) 3303 { 3304 throw dataFactory.markCorrupt( 3305 StandardException.newException( 3306 SQLState.DATA_CORRUPT_PAGE, ioe, getPageId())); 3307 } 3308 } 3309 3310 3311 3315 3316 3322 private void initSpace() 3323 { 3324 totalSpace = getMaxFreeSpace(); 3327 3328 3331 3352 maxFieldSize = totalSpace - slotEntrySize - 16 - OVERFLOW_POINTER_SIZE; 3353 3354 if (SanityManager.DEBUG) 3355 SanityManager.ASSERT(maxFieldSize >= 0); 3356 } 3357 3358 3361 private void clearAllSpace() 3362 { 3363 freeSpace = totalSpace; 3364 firstFreeByte = getPageSize() - totalSpace - CHECKSUM_SIZE; 3365 } 3366 3367 3378 private void compressPage( 3379 int startByte, 3380 int endByte) 3381 throws IOException 3382 { 3383 if (SanityManager.DEBUG) 3384 { 3385 if (((endByte + 1) > firstFreeByte) || (startByte > firstFreeByte)) 3386 { 3387 SanityManager.THROWASSERT( 3388 "startByte = " + startByte + " endByte = " + endByte + 3389 " firstFreeByte = " + firstFreeByte); 3390 } 3391 } 3392 3393 int lengthToClear = endByte + 1 - startByte; 3394 3395 if ((endByte + 1) != firstFreeByte) 3397 { 3398 int moveLength = (firstFreeByte - endByte - 1); 3400 3401 System.arraycopy( 3402 pageData, (endByte + 1), pageData, startByte, moveLength); 3403 3404 for (int slot = 0; slot < slotsInUse; slot++) 3406 { 3407 int offset = getRecordOffset(slot); 3408 3409 if (offset >= (endByte + 1)) 3410 { 3411 offset -= lengthToClear; 3412 setRecordOffset(slot, offset); 3413 } 3414 } 3415 } 3416 3417 freeSpace += lengthToClear; 3418 firstFreeByte -= lengthToClear; 3419 3420 clearSection(firstFreeByte, lengthToClear); 3421 } 3422 3423 3434 protected void expandPage( 3435 int startOffset, 3436 int requiredBytes) 3437 throws IOException 3438 { 3439 if (SanityManager.DEBUG) 3440 { 3441 SanityManager.ASSERT(requiredBytes <= freeSpace); 3442 SanityManager.ASSERT(startOffset <= firstFreeByte); 3443 } 3444 3445 int totalLength = firstFreeByte - startOffset; 3446 3447 if (totalLength > 0) 3448 { 3449 System.arraycopy( 3450 pageData, startOffset, 3451 pageData, startOffset + requiredBytes, totalLength); 3452 3453 for (int slot = 0; slot < slotsInUse; slot++) 3455 { 3456 int offset = getRecordOffset(slot); 3457 if (offset >= startOffset) 3458 { 3459 offset += requiredBytes; 3460 setRecordOffset(slot, offset); 3461 } 3462 } 3463 } 3464 3465 freeSpace -= requiredBytes; 3466 firstFreeByte += requiredBytes; 3467 } 3468 3469 3481 private void shrinkPage(int startOffset, int shrinkBytes) 3482 throws IOException 3483 { 3484 int totalLength = firstFreeByte - startOffset; 3486 3487 if (SanityManager.DEBUG) 3488 { 3489 SanityManager.DEBUG( 3490 "shrinkPage", "page " + getIdentity() + 3491 " shrinking " + shrinkBytes + 3492 " from offset " + startOffset + 3493 " to offset " + (startOffset-shrinkBytes) + 3494 " moving " + totalLength + 3495 " bytes. FirstFreeByte at " + firstFreeByte); 3496 3497 SanityManager.ASSERT( 3498 totalLength >= 0, "firstFreeByte - startOffset <= 0"); 3499 3500 SanityManager.ASSERT( 3501 (startOffset-shrinkBytes) > RECORD_SPACE_OFFSET , 3502 "shrinking too much "); 3503 3504 if (startOffset != firstFreeByte) 3505 { 3506 boolean foundslot = false; 3508 for (int slot = 0; slot < slotsInUse; slot++) 3509 { 3510 if (getRecordOffset(slot) == startOffset) 3511 { 3512 foundslot = true; 3513 break; 3514 } 3515 } 3516 3517 if (!foundslot) 3518 { 3519 SanityManager.THROWASSERT( 3520 "startOffset " + startOffset + 3521 " not at the beginning of a record"); 3522 } 3523 } 3524 } 3525 3526 if (totalLength > 0) 3527 { 3528 System.arraycopy( 3529 pageData, startOffset, 3530 pageData, startOffset-shrinkBytes , totalLength); 3531 3532 for (int slot = 0; slot < slotsInUse; slot++) 3534 { 3535 int offset = getRecordOffset(slot); 3536 if (offset >= startOffset) 3537 { 3538 offset -= shrinkBytes; 3539 setRecordOffset(slot, offset); 3540 } 3541 } 3542 } 3543 3544 freeSpace += shrinkBytes; 3545 firstFreeByte -= shrinkBytes; 3546 } 3547 3548 public int getRecordLength(int slot) throws IOException 3549 { 3550 return getRecordPortionLength(slot); 3551 } 3552 protected boolean getIsOverflow(int slot) throws IOException 3553 { 3554 return getHeaderAtSlot(slot).hasOverflow(); 3555 } 3556 3557 3566 3618 public int logRow( 3619 int slot, 3620 boolean forInsert, 3621 int recordId, 3622 Object [] row, 3623 FormatableBitSet validColumns, 3624 DynamicByteArrayOutputStream out, 3625 int startColumn, 3626 byte insertFlag, 3627 int realStartColumn, 3628 int realSpaceOnPage, 3629 int overflowThreshold) 3630 throws StandardException, IOException 3631 { 3632 if (!forInsert) 3636 { 3637 if ((realStartColumn != -1) && (realSpaceOnPage == -1)) 3638 { 3639 return realStartColumn; 3640 } 3641 } 3642 3643 int spaceAvailable = freeSpace; 3644 setOutputStream(out); 3645 int beginPosition = out.getPosition(); 3646 3647 userRowSize = 0; 3651 boolean calcMinimumRecordSize = false; 3652 3653 if (realStartColumn != (-1)) 3654 { 3655 3657 spaceAvailable = realSpaceOnPage; 3658 beginPosition = out.getBeginPosition(); 3659 } 3660 else 3661 { 3662 3664 if (!forInsert) 3665 { 3666 spaceAvailable += getTotalSpace(slot); 3671 3672 } 3673 else 3674 { 3675 spaceAvailable -= slotEntrySize; 3677 3678 if (startColumn == 0) 3679 calcMinimumRecordSize = true; 3680 } 3681 3682 if (spaceAvailable <= 0) 3684 throw new NoSpaceOnPage(isOverflowPage()); 3685 } 3686 3687 try 3688 { 3689 if (row == null) 3690 { 3691 3693 return(logOverflowRecord(slot, spaceAvailable, out)); 3694 } 3695 3696 int numberFields = 0; 3697 StoredRecordHeader recordHeader; 3698 3699 if (forInsert) 3700 { 3701 recordHeader = new StoredRecordHeader(); 3702 } 3703 else 3704 { 3705 recordHeader = 3708 new StoredRecordHeader(getHeaderAtSlot(slot)); 3709 3710 startColumn = recordHeader.getFirstField(); 3712 } 3713 3714 if (validColumns == null) 3715 { 3716 3718 numberFields = row.length - startColumn; 3719 } 3720 else 3721 { 3722 3725 for (int i = validColumns.getLength() - 1; 3726 i >= startColumn; 3727 i--) 3728 { 3729 if (validColumns.isSet(i)) 3730 { 3731 numberFields = i + 1 - startColumn; 3732 break; 3733 } 3734 } 3735 } 3736 3737 int onPageNumberFields = -1; 3739 if (forInsert) 3740 { 3741 recordHeader.setId(recordId); 3742 recordHeader.setNumberFields(numberFields); 3743 } 3744 else 3745 { 3746 3748 onPageNumberFields = recordHeader.getNumberFields(); 3749 3750 if (numberFields > onPageNumberFields) 3751 { 3752 if (recordHeader.hasOverflow()) 3754 { 3755 3757 numberFields = onPageNumberFields; 3758 } 3759 else 3760 { 3761 3763 recordHeader.setNumberFields(numberFields); 3764 } 3765 } 3766 else if (numberFields < onPageNumberFields) 3767 { 3768 if (validColumns == null) 3769 { 3770 recordHeader.setNumberFields(numberFields); 3774 3775 3778 3782 } 3783 else 3784 { 3785 numberFields = onPageNumberFields; 3789 } 3790 } 3791 } 3792 3793 int endFieldExclusive = startColumn + numberFields; 3794 3795 if (realStartColumn >= endFieldExclusive) 3796 { 3797 return (-1); 3800 } 3801 3802 if ((insertFlag & Page.INSERT_DEFAULT) != Page.INSERT_DEFAULT) 3803 { 3804 recordHeader.setFirstField(startColumn); 3807 } 3808 3809 3811 int firstColumn = realStartColumn; 3812 if (realStartColumn == (-1)) 3813 { 3814 3816 int recordHeaderLength = recordHeader.write(logicalDataOut); 3817 3818 spaceAvailable -= recordHeaderLength; 3819 if (spaceAvailable < 0) 3820 { 3821 throw new NoSpaceOnPage(isOverflowPage()); 3823 } 3824 3825 firstColumn = startColumn; 3826 } 3827 3828 3829 boolean monitoringOldFields = false; 3830 int validColumnsSize = 3831 (validColumns == null) ? 0 : validColumns.getLength(); 3832 3833 if (validColumns != null) 3834 { 3835 if (!forInsert) 3836 { 3837 if ((validColumns != null) && 3840 (firstColumn < (startColumn + onPageNumberFields))) 3841 { 3842 rawDataIn.setPosition( 3843 getFieldOffset(slot, firstColumn)); 3844 3845 monitoringOldFields = true; 3846 } 3847 } 3848 } 3849 3850 int lastSpaceAvailable = spaceAvailable; 3851 int recordSize = 0; 3852 int lastColumnPositionAllowOverflow = out.getPosition(); 3853 int lastColumnAllowOverflow = startColumn; 3854 3855 if (spaceAvailable > OVERFLOW_POINTER_SIZE) 3856 lastColumnPositionAllowOverflow = -1; 3857 int columnFlag = COLUMN_FIRST; 3858 3859 for (int i = firstColumn; i < endFieldExclusive; i++) 3860 { 3861 Object ref = null; 3862 boolean ignoreColumn = false; 3863 3864 3865 if ((validColumns == null) || 3867 (validColumnsSize > i && validColumns.isSet(i))) 3868 { 3869 if (i < row.length) 3870 ref = row[i]; 3871 } 3872 else if (!forInsert) 3873 { 3874 ignoreColumn = true; 3876 } 3877 3878 if (spaceAvailable > OVERFLOW_POINTER_SIZE) 3879 { 3880 lastColumnPositionAllowOverflow = out.getPosition(); 3881 lastColumnAllowOverflow = i; 3882 } 3883 3884 lastSpaceAvailable = spaceAvailable; 3885 3886 if (ignoreColumn) 3887 { 3888 if (SanityManager.DEBUG) 3889 { 3890 SanityManager.ASSERT( 3891 ref == null, 3892 "ref should be null for an ignored column"); 3893 3894 SanityManager.ASSERT( 3895 validColumns != null, 3896 "validColumns should be non-null for ignored col"); 3897 } 3898 3899 if (i < (startColumn + onPageNumberFields)) 3900 { 3901 if (SanityManager.DEBUG) 3902 { 3903 SanityManager.ASSERT( 3904 monitoringOldFields, 3905 "monitoringOldFields must be true"); 3906 } 3907 3908 int oldOffset = rawDataIn.getPosition(); 3911 skipField(rawDataIn); 3912 int oldFieldLength = 3913 rawDataIn.getPosition() - oldOffset; 3914 3915 if (oldFieldLength <= spaceAvailable) 3916 { 3917 3920 logColumn( 3921 null, 0, out, Integer.MAX_VALUE, 3922 COLUMN_NONE, overflowThreshold); 3923 3924 spaceAvailable -= oldFieldLength; 3925 } 3926 3927 } 3928 else 3929 { 3930 3933 spaceAvailable = 3934 logColumn( 3935 null, 0, out, spaceAvailable, 3936 columnFlag, overflowThreshold); 3937 } 3938 3939 } 3940 else 3941 { 3942 3944 if (monitoringOldFields && 3945 (i < (startColumn + onPageNumberFields))) 3946 { 3947 skipField(rawDataIn); 3950 } 3951 3952 3953 try 3954 { 3955 if (ref == null) 3956 { 3957 spaceAvailable = 3959 logColumn( 3960 null, 0, out, spaceAvailable, 3961 columnFlag, overflowThreshold); 3962 } 3963 else 3964 { 3965 spaceAvailable = 3967 logColumn( 3968 row, i, out, spaceAvailable, 3969 columnFlag, overflowThreshold); 3970 } 3971 3972 } 3973 catch (LongColumnException lce) 3974 { 3975 3979 3980 if ((insertFlag & Page.INSERT_DEFAULT) == 3981 Page.INSERT_DEFAULT) 3982 { 3983 3985 4003 if ((lce.getColumn() instanceof InputStream) 4004 && (row[i] instanceof StreamStorable) ) 4005 { 4006 if ((row[i] instanceof InputStream) || 4007 (((StreamStorable) row[i]).returnStream() 4008 != null) ) 4009 { 4010 4017 ((StreamStorable) row[i]).setStream( 4018 (InputStream) lce.getColumn()); 4019 } 4020 } 4021 4022 throw new NoSpaceOnPage(isOverflowPage()); 4023 } 4024 4025 4036 if (((spaceAvailable >= OVERFLOW_PTR_FIELD_SIZE) && 4037 (i == (endFieldExclusive - 1))) || 4038 ((spaceAvailable >= (OVERFLOW_PTR_FIELD_SIZE * 2))&& 4039 (i < (endFieldExclusive - 1)))) 4040 { 4041 4047 out.setBeginPosition(beginPosition); 4050 lce.setExceptionInfo(out, i, spaceAvailable); 4051 throw (lce); 4052 } 4053 } 4054 } 4055 4056 int nextColumn; 4057 4058 recordSize += (lastSpaceAvailable - spaceAvailable); 4059 boolean recordIsLong = 4060 (overflowThreshold == 100) ? 4061 false : isLong(recordSize, overflowThreshold); 4062 4063 if ((lastSpaceAvailable == spaceAvailable) || recordIsLong) 4065 { 4066 if ((insertFlag & Page.INSERT_DEFAULT) == 4067 Page.INSERT_DEFAULT) 4068 { 4069 throw new NoSpaceOnPage(isOverflowPage()); 4070 } 4071 4072 if (recordIsLong) 4073 { 4074 4078 out.setPosition(out.getPosition() - recordSize); 4079 } 4080 4081 nextColumn = i; 4083 } 4084 else 4085 { 4086 nextColumn = endFieldExclusive; 4088 } 4089 4090 4095 if ((lastSpaceAvailable == spaceAvailable) || 4096 ((insertFlag & Page.INSERT_FOR_SPLIT) == 4097 Page.INSERT_FOR_SPLIT)) 4098 { 4099 4101 if (spaceAvailable <= OVERFLOW_POINTER_SIZE) 4102 { 4103 if ((i == startColumn) || 4104 (lastColumnPositionAllowOverflow < 0)) 4105 { 4106 throw new NoSpaceOnPage(isOverflowPage()); 4110 } 4111 else 4112 { 4113 4116 out.setPosition(lastColumnPositionAllowOverflow); 4117 nextColumn = lastColumnAllowOverflow; 4118 } 4119 } 4120 } 4121 4122 if (nextColumn < endFieldExclusive) 4123 { 4124 4126 int actualNumberFields = nextColumn - startColumn; 4127 4128 4133 int oldSize = recordHeader.size(); 4134 recordHeader.setNumberFields(actualNumberFields); 4135 4136 int newSize = recordHeader.size(); 4137 4138 int endPosition = out.getPosition(); 4140 4141 if (oldSize > newSize) 4142 { 4143 4146 int delta = oldSize - newSize; 4147 out.setBeginPosition(beginPosition + delta); 4148 out.setPosition(beginPosition + delta); 4149 } 4150 else if (newSize > oldSize) 4151 { 4152 out.setPosition(beginPosition); 4153 4154 } 4155 else 4156 { 4157 out.setBeginPosition(beginPosition); 4158 out.setPosition(beginPosition); 4159 } 4160 4161 int realLen = recordHeader.write(logicalDataOut); 4162 if (SanityManager.DEBUG) 4163 { 4164 if ((realLen + (oldSize - newSize)) != oldSize) 4165 { 4166 SanityManager.THROWASSERT( 4167 "recordHeader size incorrect. realLen = " + 4168 realLen + ", delta = " + 4169 (oldSize - newSize) + ", oldSize = " + oldSize); 4170 } 4171 } 4172 4173 out.setPosition(endPosition); 4174 4175 if (!forInsert) 4176 { 4177 if (validColumns != null) 4186 { 4187 handleIncompleteLogRow( 4188 slot, nextColumn, validColumns, out); 4189 } 4190 } 4191 4192 return (nextColumn); 4193 } 4194 4195 columnFlag = COLUMN_NONE; 4196 } 4197 4198 out.setBeginPosition(beginPosition); 4199 startColumn = -1; 4200 4201 if ((calcMinimumRecordSize) && 4202 (spaceAvailable < (minimumRecordSize - userRowSize))) 4203 { 4204 throw new NoSpaceOnPage(isOverflowPage()); 4205 } 4206 4207 } 4208 finally 4209 { 4210 resetOutputStream(); 4211 } 4212 4213 return (startColumn); 4214 } 4215 4216 4240 private void handleIncompleteLogRow( 4241 int slot, 4242 int startColumn, 4243 FormatableBitSet columnList, 4244 DynamicByteArrayOutputStream out) 4245 throws StandardException 4246 { 4247 if (SanityManager.DEBUG) 4248 SanityManager.ASSERT(columnList != null); 4249 4250 StoredRecordHeader rh = getHeaderAtSlot(slot); 4251 4252 int endFieldExclusive = rh.getFirstField() + rh.getNumberFields(); 4253 4254 boolean needSave = false; 4256 int columnListSize = columnList.size(); 4257 for (int i = startColumn; i < endFieldExclusive; i++) 4258 { 4259 if (!(columnListSize > i && columnList.get(i))) 4260 { 4261 needSave = true; 4262 break; 4263 } 4264 } 4265 if (!needSave) 4266 return; 4267 4268 Object [] savedFields = 4269 new Object [endFieldExclusive - startColumn]; 4270 4271 ByteArrayOutputStream fieldStream = null; 4272 4273 for (int i = startColumn; i < endFieldExclusive; i++) 4274 { 4275 if (columnListSize > i && columnList.get(i)) 4277 continue; 4278 4279 4281 try 4282 { 4283 if (fieldStream == null) 4288 fieldStream = new ByteArrayOutputStream(); 4289 else 4290 fieldStream.reset(); 4291 4292 logField(slot, i, fieldStream); 4293 4294 savedFields[i - startColumn] = 4295 new RawField(fieldStream.toByteArray()); 4296 4297 } 4298 catch (IOException ioe) 4299 { 4300 throw dataFactory.markCorrupt( 4301 StandardException.newException( 4302 SQLState.DATA_CORRUPT_PAGE, ioe, getPageId())); 4303 } 4304 } 4305 4306 4309 LongColumnException lce = new LongColumnException(); 4310 lce.setExceptionInfo( 4311 out, startColumn, -1 ); 4312 lce.setColumn(savedFields); 4313 4314 throw lce; 4315 } 4316 4317 4326 4327 4341 public void restoreRecordFromStream( 4342 LimitObjectInput in, 4343 Object [] row) 4344 throws StandardException, IOException 4345 { 4346 4347 StoredRecordHeader recordHeader = new StoredRecordHeader(); 4348 recordHeader.read(in); 4349 readRecordFromStream( 4350 row, 4351 row.length - 1, 4352 (int[]) null, 4353 (int[]) null, 4354 in, 4355 recordHeader, 4356 (ErrorObjectInput) null , null); 4357 } 4358 4359 4390 private boolean qualifyRecordFromRow( 4391 Object [] row, 4392 Qualifier[][] qual_list) 4393 throws StandardException 4394 { 4395 boolean row_qualifies = true; 4396 4397 if (SanityManager.DEBUG) 4398 { 4399 SanityManager.ASSERT(row != null); 4400 } 4401 4402 4404 if (SanityManager.DEBUG) 4405 { 4406 SanityManager.ASSERT(qual_list != null); 4408 SanityManager.ASSERT(qual_list.length > 0); 4409 } 4410 4411 for (int i = 0; i < qual_list[0].length; i++) 4412 { 4413 4415 row_qualifies = false; 4416 4417 4419 Qualifier q = qual_list[0][i]; 4420 4421 DataValueDescriptor columnValue = 4424 (DataValueDescriptor) row[q.getColumnId()]; 4425 4426 row_qualifies = 4427 columnValue.compare( 4428 q.getOperator(), 4429 q.getOrderable(), 4430 q.getOrderedNulls(), 4431 q.getUnknownRV()); 4432 4433 if (q.negateCompareResult()) 4434 row_qualifies = !row_qualifies; 4435 4436 if (!row_qualifies) 4438 return(false); 4439 } 4440 4441 4443 for (int and_idx = 1; and_idx < qual_list.length; and_idx++) 4444 { 4445 4447 row_qualifies = false; 4448 4449 if (SanityManager.DEBUG) 4450 { 4451 SanityManager.ASSERT(qual_list[and_idx].length > 0); 4453 } 4454 4455 for (int or_idx = 0; or_idx < qual_list[and_idx].length; or_idx++) 4456 { 4457 Qualifier q = qual_list[and_idx][or_idx]; 4459 int col_id = q.getColumnId(); 4460 4461 if (SanityManager.DEBUG) 4462 { 4463 SanityManager.ASSERT( 4464 (col_id < row.length), 4465 "Qualifier is referencing a column not in the row."); 4466 } 4467 4468 DataValueDescriptor columnValue = 4471 (DataValueDescriptor) row[q.getColumnId()]; 4472 4473 if (SanityManager.DEBUG) 4474 { 4475 if (columnValue == null) 4476 SanityManager.THROWASSERT( 4477 "1:row = " + RowUtil.toString(row) + 4478 "row.length = " + row.length + 4479 ";q.getColumnId() = " + q.getColumnId()); 4480 } 4481 4482 row_qualifies = 4485 columnValue.compare( 4486 q.getOperator(), 4487 q.getOrderable(), 4488 q.getOrderedNulls(), 4489 q.getUnknownRV()); 4490 4491 if (q.negateCompareResult()) 4492 row_qualifies = !row_qualifies; 4493 4494 4496 4498 if (row_qualifies) 4501 break; 4502 4503 } 4504 4505 if (!row_qualifies) 4508 break; 4509 } 4510 4511 return(row_qualifies); 4512 } 4513 4514 4543 private final void readOneColumnFromPage( 4544 Object [] row, 4545 int colid, 4546 int offset_to_field_data, 4547 StoredRecordHeader recordHeader, 4548 RecordHandle recordToLock) 4549 throws StandardException, IOException 4550 { 4551 ErrorObjectInput inUserCode = null; 4552 4553 ArrayInputStream lrdi = rawDataIn; 4556 4557 try 4558 { 4559 if (SanityManager.DEBUG) 4560 { 4561 if (colid >= row.length) 4562 SanityManager.THROWASSERT( 4563 "colid = " + colid + 4564 ";row length = " + row.length); 4565 4566 if (recordHeader.getFirstField() != 0) 4568 { 4569 SanityManager.THROWASSERT( 4570 "recordHeader.getFirstField() = " + 4571 recordHeader.getFirstField()); 4572 } 4573 } 4574 4575 Object column = row[colid]; 4576 4577 if (colid <= (recordHeader.getNumberFields() - 1)) 4579 { 4580 4583 for (int columnId = colid; columnId > 0; columnId--) 4584 { 4585 offset_to_field_data += 4586 StoredFieldHeader.readTotalFieldLength( 4587 pageData, offset_to_field_data); 4588 } 4589 4590 4591 4592 4594 int fieldStatus = 4596 StoredFieldHeader.readStatus( 4597 pageData, offset_to_field_data); 4598 4599 int fieldDataLength = 4601 StoredFieldHeader.readFieldLengthAndSetStreamPosition( 4602 pageData, 4603 offset_to_field_data + 4604 StoredFieldHeader.STORED_FIELD_HEADER_STATUS_SIZE, 4605 fieldStatus, 4606 slotFieldSize, 4607 lrdi); 4608 4609 if (SanityManager.DEBUG) 4610 { 4611 SanityManager.ASSERT( 4612 !StoredFieldHeader.isExtensible(fieldStatus), 4613 "extensible fields not supported yet"); 4614 } 4615 4616 4618 if (!StoredFieldHeader.isNonexistent(fieldStatus)) 4619 { 4620 boolean isOverflow = 4621 StoredFieldHeader.isOverflow(fieldStatus); 4622 4623 OverflowInputStream overflowIn = null; 4624 4625 if (isOverflow) 4626 { 4627 long overflowPage = 4629 CompressedNumber.readLong((InputStream) lrdi); 4630 4631 int overflowId = 4632 CompressedNumber.readInt((InputStream) lrdi); 4633 4634 MemByteHolder byteHolder = 4638 new MemByteHolder(pageData.length); 4639 4640 overflowIn = new OverflowInputStream( 4641 byteHolder, owner, overflowPage, 4642 overflowId, recordToLock); 4643 } 4644 4645 if (column instanceof DataValueDescriptor) 4647 { 4648 DataValueDescriptor sColumn = 4649 (DataValueDescriptor) column; 4650 4651 if (StoredFieldHeader.isNull(fieldStatus)) 4653 { 4654 sColumn.restoreToNull(); 4655 } 4656 else 4657 { 4658 if (!isOverflow) 4660 { 4661 4663 lrdi.setLimit(fieldDataLength); 4664 inUserCode = lrdi; 4665 sColumn.readExternalFromArray(lrdi); 4666 inUserCode = null; 4667 int unread = lrdi.clearLimit(); 4668 if (unread != 0) 4669 lrdi.skipBytes(unread); 4670 } 4671 else 4672 { 4673 4675 FormatIdInputStream newIn = 4676 new FormatIdInputStream(overflowIn); 4677 4678 if ((sColumn instanceof StreamStorable)) 4679 { 4680 ((StreamStorable)sColumn).setStream(newIn); 4681 } 4682 else 4683 { 4684 inUserCode = newIn; 4685 sColumn.readExternal(newIn); 4686 inUserCode = null; 4687 } 4688 } 4689 } 4690 } 4691 else 4692 { 4693 4695 if (StoredFieldHeader.isNull(fieldStatus)) 4696 { 4697 4699 throw StandardException.newException( 4700 SQLState.DATA_NULL_STORABLE_COLUMN, 4701 Integer.toString(colid)); 4702 } 4703 4704 4711 lrdi.setLimit(fieldDataLength); 4712 inUserCode = lrdi; 4713 row[colid] = (Object ) lrdi.readObject(); 4715 inUserCode = null; 4716 int unread = lrdi.clearLimit(); 4717 if (unread != 0) 4718 lrdi.skipBytes(unread); 4719 } 4720 4721 } 4722 else 4723 { 4724 4726 4728 if (column instanceof DataValueDescriptor) 4729 { 4730 4735 ((DataValueDescriptor) column).restoreToNull(); 4736 } 4737 else 4738 { 4739 row[colid] = null; 4740 } 4741 } 4742 } 4743 else 4744 { 4745 4747 if (column instanceof DataValueDescriptor) 4748 { 4749 ((DataValueDescriptor) column).restoreToNull(); 4754 } 4755 else 4756 { 4757 row[colid] = null; 4758 } 4759 } 4760 } 4761 catch (IOException ioe) 4762 { 4763 4766 if (inUserCode != null) 4767 { 4768 lrdi.clearLimit(); 4769 4770 if (ioe instanceof EOFException ) 4771 { 4772 if (SanityManager.DEBUG) 4773 { 4774 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 4775 "StoredPage.readOneColumnFromPage - EOF while restoring record: " + 4776 recordHeader + 4777 "Page dump = " + this); 4778 SanityManager.showTrace(ioe); 4779 } 4780 4781 throw StandardException.newException( 4784 SQLState.DATA_STORABLE_READ_MISMATCH, 4785 ioe, inUserCode.getErrorInfo()); 4786 } 4787 4788 Exception ne = inUserCode.getNestedException(); 4790 if (ne != null) 4791 { 4792 if (ne instanceof InstantiationException ) 4793 { 4794 throw StandardException.newException( 4795 SQLState.DATA_SQLDATA_READ_INSTANTIATION_EXCEPTION, 4796 ne, inUserCode.getErrorInfo()); 4797 } 4798 4799 if (ne instanceof IllegalAccessException ) 4800 { 4801 throw StandardException.newException( 4802 SQLState.DATA_SQLDATA_READ_ILLEGAL_ACCESS_EXCEPTION, 4803 ne, inUserCode.getErrorInfo()); 4804 } 4805 4806 if (ne instanceof StandardException) 4807 { 4808 throw (StandardException) ne; 4809 } 4810 } 4811 4812 throw StandardException.newException( 4813 SQLState.DATA_STORABLE_READ_EXCEPTION, 4814 ioe, inUserCode.getErrorInfo()); 4815 } 4816 4817 throw ioe; 4819 4820 } 4821 catch (ClassNotFoundException cnfe) 4822 { 4823 lrdi.clearLimit(); 4824 4825 throw StandardException.newException( 4828 SQLState.DATA_STORABLE_READ_MISSING_CLASS, 4829 cnfe, inUserCode.getErrorInfo()); 4830 4831 } 4832 catch (LinkageError le) 4833 { 4834 if (inUserCode != null) 4836 { 4837 lrdi.clearLimit(); 4838 4839 throw StandardException.newException( 4840 SQLState.DATA_STORABLE_READ_EXCEPTION, 4841 le, inUserCode.getErrorInfo()); 4842 } 4843 throw le; 4844 } 4845 4846 } 4847 4848 4849 4850 4905 private final boolean qualifyRecordFromSlot( 4906 Object [] row, 4907 int offset_to_row_data, 4908 FetchDescriptor fetchDesc, 4909 StoredRecordHeader recordHeader, 4910 RecordHandle recordToLock) 4911 throws StandardException, IOException 4912 { 4913 boolean row_qualifies = true; 4914 Qualifier[][] qual_list = fetchDesc.getQualifierList(); 4915 int[] materializedCols = fetchDesc.getMaterializedColumns(); 4916 4917 if (SanityManager.DEBUG) 4918 { 4919 SanityManager.ASSERT(qual_list != null, "Not coded yet!"); 4920 } 4921 4922 if (SanityManager.DEBUG) 4923 { 4924 SanityManager.ASSERT(row != null); 4925 } 4926 4927 4929 for (int i = 0; i < qual_list[0].length; i++) 4930 { 4931 4933 row_qualifies = false; 4934 4935 Qualifier q = qual_list[0][i]; 4937 int col_id = q.getColumnId(); 4938 4939 if (SanityManager.DEBUG) 4940 { 4941 SanityManager.ASSERT( 4942 (col_id < row.length), 4943 "Qualifier is referencing a column not in the row."); 4944 } 4945 4946 if (materializedCols[col_id] == 0) 4948 { 4949 readOneColumnFromPage( 4951 row, 4952 col_id, 4953 offset_to_row_data, 4954 recordHeader, 4955 recordToLock); 4956 4957 materializedCols[col_id] = offset_to_row_data; 4964 } 4965 4966 4969 if (SanityManager.DEBUG) 4970 { 4971 if (row[col_id] == null) 4972 SanityManager.THROWASSERT( 4973 "1:row = " + RowUtil.toString(row) + 4974 "row.length = " + row.length + 4975 ";q.getColumnId() = " + q.getColumnId()); 4976 } 4977 4978 row_qualifies = 4981 ((DataValueDescriptor) row[col_id]).compare( 4982 q.getOperator(), 4983 q.getOrderable(), 4984 q.getOrderedNulls(), 4985 q.getUnknownRV()); 4986 4987 if (q.negateCompareResult()) 4988 row_qualifies = !row_qualifies; 4989 4990 if (!row_qualifies) 4992 return(false); 4993 } 4994 4995 4997 for (int and_idx = 1; and_idx < qual_list.length; and_idx++) 4998 { 4999 5001 row_qualifies = false; 5002 5003 for (int or_idx = 0; or_idx < qual_list[and_idx].length; or_idx++) 5004 { 5005 Qualifier q = qual_list[and_idx][or_idx]; 5007 int col_id = q.getColumnId(); 5008 5009 if (SanityManager.DEBUG) 5010 { 5011 SanityManager.ASSERT( 5012 (col_id < row.length), 5013 "Qualifier is referencing a column not in the row."); 5014 } 5015 5016 if (materializedCols[col_id] == 0) 5018 { 5019 readOneColumnFromPage( 5021 row, 5022 col_id, 5023 offset_to_row_data, 5024 recordHeader, 5025 recordToLock); 5026 5027 materializedCols[col_id] = offset_to_row_data; 5034 } 5035 5036 5039 if (SanityManager.DEBUG) 5040 { 5041 if (row[col_id] == null) 5042 SanityManager.THROWASSERT( 5043 "1:row = " + RowUtil.toString(row) + 5044 "row.length = " + row.length + 5045 ";q.getColumnId() = " + q.getColumnId()); 5046 } 5047 5048 row_qualifies = 5051 ((DataValueDescriptor) row[col_id]).compare( 5052 q.getOperator(), 5053 q.getOrderable(), 5054 q.getOrderedNulls(), 5055 q.getUnknownRV()); 5056 5057 5058 if (q.negateCompareResult()) 5059 row_qualifies = !row_qualifies; 5060 5061 5063 5065 if (row_qualifies) 5068 break; 5069 5070 } 5071 5072 if (!row_qualifies) 5075 break; 5076 } 5077 5078 return(row_qualifies); 5079 } 5080 5081 5113 private final boolean readRecordFromStream( 5114 Object [] row, 5115 int max_colid, 5116 int[] vCols, 5117 int[] mCols, 5118 LimitObjectInput dataIn, 5119 StoredRecordHeader recordHeader, 5120 ErrorObjectInput inUserCode, 5121 RecordHandle recordToLock) 5122 throws StandardException, IOException 5123 { 5124 try 5125 { 5126 int numberFields = recordHeader.getNumberFields(); 5128 5129 int startColumn = recordHeader.getFirstField(); 5130 5131 if (startColumn > max_colid) 5132 { 5133 return true; 5135 } 5136 5137 5141 int highestColumnOnPage = numberFields + startColumn; 5142 5143 int vColsSize = (vCols == null ) ? 0 : vCols.length; 5144 5145 for (int columnId = startColumn; columnId <= max_colid; columnId++) 5146 { 5147 if (((vCols != null) && 5150 (!(vColsSize > columnId && (vCols[columnId] != 0)))) || 5151 ((mCols != null) && (mCols[columnId] != 0))) 5152 { 5153 if (columnId < highestColumnOnPage) 5154 { 5155 5159 skipField(dataIn); 5160 } 5161 5162 continue; 5163 } 5164 5165 if (columnId >= highestColumnOnPage) 5168 { 5169 Object column = row[columnId]; 5171 5172 if (column instanceof DataValueDescriptor) 5173 { 5174 5179 ((DataValueDescriptor) column).restoreToNull(); 5180 } 5181 else 5182 { 5183 row[columnId] = null; 5184 } 5185 continue; 5186 } 5187 5188 int fieldStatus = 5190 StoredFieldHeader.readStatus(dataIn); 5191 5192 int fieldDataLength = 5193 StoredFieldHeader.readFieldDataLength( 5194 dataIn, fieldStatus, slotFieldSize); 5195 5196 if (SanityManager.DEBUG) 5197 { 5198 SanityManager.ASSERT( 5199 !StoredFieldHeader.isExtensible(fieldStatus), 5200 "extensible fields not supported yet"); 5201 } 5202 5203 Object column = row[columnId]; 5204 5205 OverflowInputStream overflowIn = null; 5206 5207 5209 if (StoredFieldHeader.isNonexistent(fieldStatus)) 5211 { 5212 5213 if (column instanceof DataValueDescriptor) 5214 { 5215 ((DataValueDescriptor) column).restoreToNull(); 5220 } 5221 else 5222 { 5223 row[columnId] = null; 5224 } 5225 continue; 5226 } 5227 5228 boolean isOverflow = StoredFieldHeader.isOverflow(fieldStatus); 5229 5230 if (isOverflow) 5231 { 5232 5233 long overflowPage = 5236 CompressedNumber.readLong((InputStream) dataIn); 5237 5238 int overflowId = 5239 CompressedNumber.readInt((InputStream) dataIn); 5240 5241 MemByteHolder byteHolder = 5245 new MemByteHolder(pageData.length); 5246 5247 overflowIn = new OverflowInputStream( 5248 byteHolder, owner, overflowPage, 5249 overflowId, recordToLock); 5250 } 5251 5252 if (column instanceof DataValueDescriptor) 5254 { 5255 DataValueDescriptor sColumn = (DataValueDescriptor) column; 5256 5257 if (StoredFieldHeader.isNull(fieldStatus)) 5259 { 5260 sColumn.restoreToNull(); 5261 continue; 5262 } 5263 5264 if (!isOverflow) 5266 { 5267 5269 dataIn.setLimit(fieldDataLength); 5270 inUserCode = dataIn; 5271 sColumn.readExternal(dataIn); 5272 inUserCode = null; 5273 int unread = dataIn.clearLimit(); 5274 if (unread != 0) 5275 dataIn.skipBytes(unread); 5276 } 5277 else 5278 { 5279 5281 FormatIdInputStream newIn = 5282 new FormatIdInputStream(overflowIn); 5283 5284 boolean fetchStream = true; 5287 5288 if (!(sColumn instanceof StreamStorable)) 5289 { 5290 fetchStream = false; 5291 } 5292 5293 if (fetchStream) 5294 { 5295 ((StreamStorable)sColumn).setStream(newIn); 5296 } 5297 else 5298 { 5299 inUserCode = newIn; 5300 sColumn.readExternal(newIn); 5301 inUserCode = null; 5302 } 5303 5304 } 5305 5306 continue; 5307 } 5308 5309 5311 if (StoredFieldHeader.isNull(fieldStatus)) 5312 { 5313 5315 throw StandardException.newException( 5316 SQLState.DATA_NULL_STORABLE_COLUMN, 5317 Integer.toString(columnId)); 5318 } 5319 5320 5326 dataIn.setLimit(fieldDataLength); 5327 inUserCode = dataIn; 5328 row[columnId] = (Object ) dataIn.readObject(); 5329 inUserCode = null; 5330 int unread = dataIn.clearLimit(); 5331 if (unread != 0) 5332 dataIn.skipBytes(unread); 5333 5334 continue; 5335 } 5336 5337 5340 if ((numberFields + startColumn) > max_colid) 5341 return true; 5342 else 5343 return false; 5344 5345 } 5346 catch (IOException ioe) 5347 { 5348 5351 if (inUserCode != null) 5352 { 5353 dataIn.clearLimit(); 5354 5355 if (ioe instanceof EOFException ) 5356 { 5357 if (SanityManager.DEBUG) 5358 { 5359 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 5360 "StoredPage - EOF while restoring record: " + 5361 recordHeader + 5362 "Page dump = " + this); 5363 } 5364 5365 throw StandardException.newException( 5368 SQLState.DATA_STORABLE_READ_MISMATCH, 5369 ioe, inUserCode.getErrorInfo()); 5370 } 5371 5372 Exception ne = inUserCode.getNestedException(); 5374 if (ne != null) 5375 { 5376 if (ne instanceof InstantiationException ) 5377 { 5378 throw StandardException.newException( 5379 SQLState.DATA_SQLDATA_READ_INSTANTIATION_EXCEPTION, 5380 ne, inUserCode.getErrorInfo()); 5381 } 5382 5383 if (ne instanceof IllegalAccessException ) 5384 { 5385 throw StandardException.newException( 5386 SQLState.DATA_SQLDATA_READ_ILLEGAL_ACCESS_EXCEPTION, 5387 ne, inUserCode.getErrorInfo()); 5388 } 5389 5390 if (ne instanceof StandardException) 5391 { 5392 throw (StandardException) ne; 5393 } 5394 } 5395 5396 throw StandardException.newException( 5397 SQLState.DATA_STORABLE_READ_EXCEPTION, 5398 ioe, inUserCode.getErrorInfo()); 5399 } 5400 5401 throw ioe; 5403 5404 } 5405 catch (ClassNotFoundException cnfe) 5406 { 5407 dataIn.clearLimit(); 5408 5409 throw StandardException.newException( 5412 SQLState.DATA_STORABLE_READ_MISSING_CLASS, 5413 cnfe, inUserCode.getErrorInfo()); 5414 5415 } 5416 catch (LinkageError le) 5417 { 5418 if (inUserCode != null) 5420 { 5421 dataIn.clearLimit(); 5422 5423 throw StandardException.newException( 5424 SQLState.DATA_STORABLE_READ_EXCEPTION, 5425 le, inUserCode.getErrorInfo()); 5426 } 5427 throw le; 5428 } 5429 5430 } 5431 5432 private final boolean readRecordFromArray( 5433 Object [] row, 5434 int max_colid, 5435 int[] vCols, 5436 int[] mCols, 5437 ArrayInputStream dataIn, 5438 StoredRecordHeader recordHeader, 5439 ErrorObjectInput inUserCode, 5440 RecordHandle recordToLock) 5441 throws StandardException, IOException 5442 { 5443 try 5444 { 5445 int numberFields = recordHeader.getNumberFields(); 5447 5448 int startColumn = recordHeader.getFirstField(); 5449 5450 if (startColumn > max_colid) 5451 { 5452 return true; 5454 } 5455 5456 5460 int highestColumnOnPage = numberFields + startColumn; 5461 5462 int vColsSize = (vCols == null ) ? 0 : vCols.length; 5463 5464 int offset_to_field_data = dataIn.getPosition(); 5465 5466 for (int columnId = startColumn; columnId <= max_colid; columnId++) 5467 { 5468 if (((vCols != null) && 5471 (!(vColsSize > columnId && (vCols[columnId] != 0)))) || 5472 ((mCols != null) && (mCols[columnId] != 0))) 5473 { 5474 if (columnId < highestColumnOnPage) 5475 { 5476 5480 offset_to_field_data += 5481 StoredFieldHeader.readTotalFieldLength( 5482 pageData, offset_to_field_data); 5483 } 5484 5485 continue; 5486 } 5487 else if (columnId < highestColumnOnPage) 5488 { 5489 5491 5493 int fieldStatus = 5495 StoredFieldHeader.readStatus( 5496 pageData, offset_to_field_data); 5497 5498 int fieldDataLength = 5500 StoredFieldHeader.readFieldLengthAndSetStreamPosition( 5501 pageData, 5502 offset_to_field_data + 5503 StoredFieldHeader.STORED_FIELD_HEADER_STATUS_SIZE, 5504 fieldStatus, 5505 slotFieldSize, 5506 dataIn); 5507 5508 5509 if (SanityManager.DEBUG) 5510 { 5511 SanityManager.ASSERT( 5512 !StoredFieldHeader.isExtensible(fieldStatus), 5513 "extensible fields not supported yet"); 5514 } 5515 5516 Object column = row[columnId]; 5517 5518 OverflowInputStream overflowIn = null; 5519 5520 5522 if ((fieldStatus & StoredFieldHeader.FIELD_NONEXISTENT) != 5523 StoredFieldHeader.FIELD_NONEXISTENT) 5524 { 5525 5527 boolean isOverflow = 5528 ((fieldStatus & 5529 StoredFieldHeader.FIELD_OVERFLOW) != 0); 5530 5531 if (isOverflow) 5532 { 5533 5534 5536 long overflowPage = 5537 CompressedNumber.readLong((InputStream) dataIn); 5538 5539 int overflowId = 5540 CompressedNumber.readInt((InputStream) dataIn); 5541 5542 5547 MemByteHolder byteHolder = 5548 new MemByteHolder(pageData.length); 5549 5550 overflowIn = new OverflowInputStream( 5551 byteHolder, owner, overflowPage, 5552 overflowId, recordToLock); 5553 } 5554 5555 if (column instanceof DataValueDescriptor) 5557 { 5558 DataValueDescriptor sColumn = 5559 (DataValueDescriptor) column; 5560 5561 if ((fieldStatus & 5563 StoredFieldHeader.FIELD_NULL) == 0) 5564 { 5565 5567 if (!isOverflow) 5569 { 5570 5572 dataIn.setLimit(fieldDataLength); 5573 inUserCode = dataIn; 5574 sColumn.readExternalFromArray(dataIn); 5575 inUserCode = null; 5576 int unread = dataIn.clearLimit(); 5577 if (unread != 0) 5578 dataIn.skipBytes(unread); 5579 } 5580 else 5581 { 5582 5584 FormatIdInputStream newIn = 5585 new FormatIdInputStream(overflowIn); 5586 5587 5589 boolean fetchStream = true; 5590 5591 if (!(sColumn instanceof StreamStorable)) 5592 { 5593 fetchStream = false; 5594 } 5595 5596 if (fetchStream) 5597 { 5598 ((StreamStorable) sColumn).setStream( 5599 newIn); 5600 } 5601 else 5602 { 5603 inUserCode = newIn; 5604 sColumn.readExternal(newIn); 5605 inUserCode = null; 5606 } 5607 } 5608 } 5609 else 5610 { 5611 sColumn.restoreToNull(); 5612 } 5613 5614 } 5615 else 5616 { 5617 5618 5620 if (StoredFieldHeader.isNull(fieldStatus)) 5621 { 5622 5624 throw StandardException.newException( 5625 SQLState.DATA_NULL_STORABLE_COLUMN, 5626 Integer.toString(columnId)); 5627 } 5628 5629 5636 dataIn.setLimit(fieldDataLength); 5637 inUserCode = dataIn; 5638 row[columnId] = (Object ) dataIn.readObject(); 5640 inUserCode = null; 5641 int unread = dataIn.clearLimit(); 5642 if (unread != 0) 5643 dataIn.skipBytes(unread); 5644 } 5645 } 5646 else 5647 { 5648 5650 if (column instanceof DataValueDescriptor) 5651 { 5652 ((DataValueDescriptor) column).restoreToNull(); 5657 } 5658 else 5659 { 5660 row[columnId] = null; 5661 } 5662 } 5663 5664 offset_to_field_data = dataIn.getPosition(); 5666 } 5667 else 5668 { 5669 Object column = row[columnId]; 5671 5672 if (column instanceof DataValueDescriptor) 5673 { 5674 5679 ((DataValueDescriptor) column).restoreToNull(); 5680 } 5681 else 5682 { 5683 row[columnId] = null; 5684 } 5685 } 5686 } 5687 5688 5691 if ((numberFields + startColumn) > max_colid) 5692 return true; 5693 else 5694 return false; 5695 5696 } 5697 catch (IOException ioe) 5698 { 5699 5702 if (inUserCode != null) 5703 { 5704 dataIn.clearLimit(); 5705 5706 if (ioe instanceof EOFException ) 5707 { 5708 if (SanityManager.DEBUG) 5709 { 5710 SanityManager.DEBUG_PRINT("DEBUG_TRACE", 5711 "StoredPage - EOF while restoring record: " + 5712 recordHeader + 5713 "Page dump = " + this); 5714 } 5715 5716 throw StandardException.newException( 5719 SQLState.DATA_STORABLE_READ_MISMATCH, 5720 ioe, inUserCode.getErrorInfo()); 5721 } 5722 5723 Exception ne = inUserCode.getNestedException(); 5725 if (ne != null) 5726 { 5727 if (ne instanceof InstantiationException ) 5728 { 5729 throw StandardException.newException( 5730 SQLState.DATA_SQLDATA_READ_INSTANTIATION_EXCEPTION, 5731 ne, inUserCode.getErrorInfo()); 5732 } 5733 5734 if (ne instanceof IllegalAccessException ) 5735 { 5736 throw StandardException.newException( 5737 SQLState.DATA_SQLDATA_READ_ILLEGAL_ACCESS_EXCEPTION, 5738 ne, inUserCode.getErrorInfo()); 5739 } 5740 5741 if (ne instanceof StandardException) 5742 { 5743 throw (StandardException) ne; 5744 } 5745 } 5746 5747 throw StandardException.newException( 5748 SQLState.DATA_STORABLE_READ_EXCEPTION, 5749 ioe, inUserCode.getErrorInfo()); 5750 } 5751 5752 throw ioe; 5754 5755 } 5756 catch (ClassNotFoundException cnfe) 5757 { 5758 dataIn.clearLimit(); 5759 5760 throw StandardException.newException( 5763 SQLState.DATA_STORABLE_READ_MISSING_CLASS, 5764 cnfe, inUserCode.getErrorInfo()); 5765 5766 } 5767 catch (LinkageError le) 5768 { 5769 if (inUserCode != null) 5771 { 5772 dataIn.clearLimit(); 5773 5774 throw StandardException.newException( 5775 SQLState.DATA_STORABLE_READ_EXCEPTION, 5776 le, inUserCode.getErrorInfo()); 5777 } 5778 throw le; 5779 } 5780 5781 } 5782 5783 5794 public void restorePortionLongColumn( 5795 OverflowInputStream fetchStream) 5796 throws StandardException, IOException 5797 { 5798 int slot = 5799 findRecordById(fetchStream.getOverflowId(), FIRST_SLOT_NUMBER); 5800 5801 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 5802 5803 int offset = getRecordOffset(slot); 5804 int numberFields = recordHeader.getNumberFields(); 5805 5806 if (SanityManager.DEBUG) 5807 { 5808 if ((numberFields > 2) || (numberFields < 1)) 5809 { 5810 SanityManager.THROWASSERT( 5811 "longColumn record header must have 1 or 2 fields." + 5812 "numberFields = " + numberFields); 5813 } 5814 } 5815 5816 rawDataIn.setPosition(offset + recordHeader.size()); 5817 5818 int fieldStatus = 5819 StoredFieldHeader.readStatus(rawDataIn); 5820 int fieldDataLength = 5821 StoredFieldHeader.readFieldDataLength( 5822 rawDataIn, fieldStatus, slotFieldSize); 5823 5824 5826 ByteHolder bh = fetchStream.getByteHolder(); 5827 bh.write(rawDataIn, fieldDataLength); 5828 fetchStream.setByteHolder(bh); 5829 5830 if (numberFields == 1) 5832 { 5833 fetchStream.setOverflowPage(-1); 5835 fetchStream.setOverflowId(-1); 5836 } 5837 else 5838 { 5839 int firstFieldStatus = fieldStatus; 5841 fieldStatus = 5843 StoredFieldHeader.readStatus(rawDataIn); 5844 fieldDataLength = 5845 StoredFieldHeader.readFieldDataLength( 5846 rawDataIn, fieldStatus, slotFieldSize); 5847 5848 if (SanityManager.DEBUG) 5849 { 5850 if (!StoredFieldHeader.isOverflow(fieldStatus)) 5851 { 5852 SanityManager.ASSERT( 5859 StoredFieldHeader.isOverflow(firstFieldStatus)); 5860 } 5861 } 5862 5863 long overflowPage = 5864 CompressedNumber.readLong((InputStream) rawDataIn); 5865 int overflowId = 5866 CompressedNumber.readInt((InputStream) rawDataIn); 5867 5868 fetchStream.setOverflowPage(overflowPage); 5870 fetchStream.setOverflowId(overflowId); 5871 } 5872 } 5873 5874 5875 5887 public void logColumn( 5888 int slot, 5889 int fieldId, 5890 Object column, 5891 DynamicByteArrayOutputStream out, 5892 int overflowThreshold) 5893 throws StandardException, IOException 5894 { 5895 5900 int bytesAvailable = freeSpace; 5902 int beginPosition = -1; 5903 5904 bytesAvailable += getReservedCount(slot); 5906 5907 rawDataIn.setPosition(getFieldOffset(slot, fieldId)); 5909 5910 int fieldStatus = 5911 StoredFieldHeader.readStatus(rawDataIn); 5912 int fieldDataLength = 5913 StoredFieldHeader.readFieldDataLength( 5914 rawDataIn, fieldStatus, slotFieldSize); 5915 5916 bytesAvailable += 5917 StoredFieldHeader.size(fieldStatus, fieldDataLength, slotFieldSize) 5918 + fieldDataLength; 5919 5920 try 5921 { 5922 setOutputStream(out); 5923 beginPosition = rawDataOut.getPosition(); 5924 5925 Object [] row = new Object [1]; 5926 row[0] = column; 5927 if (bytesAvailable == logColumn( 5928 row, 0, out, bytesAvailable, 5929 COLUMN_NONE, overflowThreshold)) 5930 { 5931 throw new NoSpaceOnPage(isOverflowPage()); 5932 } 5933 5934 } 5935 finally 5936 { 5937 rawDataOut.setPosition(beginPosition); 5938 resetOutputStream(); 5939 } 5940 } 5941 5942 5961 public int logLongColumn( 5962 int slot, 5963 int recordId, 5964 Object column, 5965 DynamicByteArrayOutputStream out) 5966 throws StandardException, IOException 5967 { 5968 int spaceAvailable = freeSpace; 5969 5970 spaceAvailable -= slotEntrySize; 5972 5973 if (spaceAvailable <= 0) 5975 throw new NoSpaceOnPage(isOverflowPage()); 5976 5977 setOutputStream(out); 5978 int beginPosition = out.getPosition(); 5979 5980 try 5981 { 5982 int numberFields = 1; 5986 5987 StoredRecordHeader recordHeader = 5988 new StoredRecordHeader(recordId, numberFields); 5989 5990 int recordHeaderLength = recordHeader.write(logicalDataOut); 5991 5992 spaceAvailable -= recordHeaderLength; 5993 5994 if (spaceAvailable < 0) 5995 { 5996 6001 throw new NoSpaceOnPage(isOverflowPage()); 6002 } 6003 else 6004 { 6005 6007 Object [] row = new Object [1]; 6008 row[0] = column; 6009 return logColumn(row, 0, out, spaceAvailable, COLUMN_LONG, 100); 6010 } 6011 6012 } 6013 finally 6014 { 6015 resetOutputStream(); 6016 } 6017 } 6018 6019 6059 private int logColumn( 6060 Object [] row, 6061 int arrayPosition, 6062 DynamicByteArrayOutputStream out, 6063 int spaceAvailable, 6064 int columnFlag, 6065 int overflowThreshold) 6066 throws StandardException, IOException 6067 { 6068 Object column = (row != null ? row[arrayPosition] : null); 6070 6071 if (column instanceof RawField) 6074 { 6075 6077 byte[] data = ((RawField) column).getData(); 6078 6079 if (data.length <= spaceAvailable) 6080 { 6081 out.write(data); 6082 spaceAvailable -= data.length; 6083 } 6084 return spaceAvailable; 6085 } 6086 6087 boolean longColumnDone = true; 6089 6090 6091 int fieldStatus = 6093 StoredFieldHeader.setFixed(StoredFieldHeader.setInitial(), true); 6094 6095 int beginPosition = out.getPosition(); 6096 int columnBeginPosition = 0; 6097 int headerLength; 6098 int fieldDataLength = 0; 6099 6100 if (column instanceof StreamStorable) 6101 { 6102 StreamStorable stream_storable_column = (StreamStorable) column; 6103 6104 if (stream_storable_column.returnStream() != null) 6105 { 6106 column = 6107 (Object ) stream_storable_column.returnStream(); 6108 } 6109 } 6110 6111 if (column == null) 6112 { 6113 fieldStatus = StoredFieldHeader.setNonexistent(fieldStatus); 6114 headerLength = 6115 StoredFieldHeader.write( 6116 logicalDataOut, fieldStatus, 6117 fieldDataLength, slotFieldSize); 6118 } 6119 else if (column instanceof InputStream) 6120 { 6121 RememberBytesInputStream bufferedIn = null; 6122 int bufferLen = 0; 6123 6124 int estimatedMaxDataSize = 6125 getMaxDataLength(spaceAvailable, overflowThreshold); 6126 6127 if (column instanceof RememberBytesInputStream) 6131 { 6132 6134 bufferedIn = (RememberBytesInputStream) column; 6135 bufferLen = bufferedIn.numBytesSaved(); 6136 6137 } 6138 else 6139 { 6140 bufferedIn = new RememberBytesInputStream( 6142 (InputStream) column, new MemByteHolder(maxFieldSize + 1)); 6143 6144 if (row[arrayPosition] instanceof StreamStorable) 6149 ((StreamStorable)row[arrayPosition]).setStream(bufferedIn); 6150 6151 column = bufferedIn; 6157 } 6158 6159 if (bufferLen < (estimatedMaxDataSize + 1)) 6161 { 6162 bufferLen += 6163 bufferedIn.fillBuf(estimatedMaxDataSize + 1 - bufferLen); 6164 } 6165 6166 if ((bufferLen <= estimatedMaxDataSize)) 6167 { 6168 6170 fieldDataLength = bufferLen; 6171 fieldStatus = StoredFieldHeader.setFixed(fieldStatus, true); 6172 headerLength = StoredFieldHeader.write( 6173 logicalDataOut, fieldStatus, 6174 fieldDataLength, slotFieldSize); 6175 6176 bufferedIn.putBuf(logicalDataOut, fieldDataLength); 6183 } 6184 else 6185 { 6186 6188 if (columnFlag == COLUMN_LONG) 6189 { 6190 longColumnDone = false; 6193 6194 fieldDataLength = 6199 estimatedMaxDataSize - OVERFLOW_POINTER_SIZE - 2; 6200 fieldStatus = 6201 StoredFieldHeader.setFixed(fieldStatus, true); 6202 6203 headerLength = 6204 StoredFieldHeader.write( 6205 logicalDataOut, fieldStatus, 6206 fieldDataLength, slotFieldSize); 6207 bufferedIn.putBuf(logicalDataOut, fieldDataLength); 6208 6209 int remainingBytes = bufferedIn.available(); 6213 6214 int bytesShifted = bufferedIn.shiftToFront(); 6216 6217 } 6218 else 6219 { 6220 int delta = maxFieldSize - bufferLen + 1; 6222 6223 if (delta > 0) 6224 bufferLen += bufferedIn.fillBuf(delta); 6225 fieldDataLength = bufferLen; 6226 6227 column = (Object ) bufferedIn; 6230 } 6231 } 6232 6233 } 6234 else if (column instanceof DataValueDescriptor) 6235 { 6236 DataValueDescriptor sColumn = (DataValueDescriptor) column; 6237 6238 boolean isNull = sColumn.isNull(); 6239 if (isNull) 6240 { 6241 fieldStatus = StoredFieldHeader.setNull(fieldStatus, true); 6242 } 6243 6244 headerLength = 6246 StoredFieldHeader.write( 6247 logicalDataOut, fieldStatus, 6248 fieldDataLength, slotFieldSize); 6249 6250 if (!isNull) 6251 { 6252 try 6254 { 6255 columnBeginPosition = out.getPosition(); 6256 sColumn.writeExternal(logicalDataOut); 6257 } 6258 catch (IOException ioe) 6259 { 6260 if (logicalDataOut != null) 6262 { 6263 Exception ne = logicalDataOut.getNestedException(); 6264 if (ne != null) 6265 { 6266 if (ne instanceof StandardException) 6267 { 6268 throw (StandardException) ne; 6269 } 6270 } 6271 } 6272 6273 6274 throw StandardException.newException( 6275 SQLState.DATA_STORABLE_WRITE_EXCEPTION, ioe); 6276 } 6277 6278 fieldDataLength = 6279 (out.getPosition() - beginPosition) - headerLength; 6280 } 6281 } 6282 else if (column instanceof RecordHandle) 6283 { 6284 6286 RecordHandle overflowHandle = (RecordHandle) column; 6288 6289 fieldStatus = StoredFieldHeader.setOverflow(fieldStatus, true); 6290 headerLength = 6291 StoredFieldHeader.write( 6292 logicalDataOut, fieldStatus, 6293 fieldDataLength, slotFieldSize); 6294 6295 fieldDataLength += 6296 CompressedNumber.writeLong(out, overflowHandle.getPageNumber()); 6297 fieldDataLength += 6298 CompressedNumber.writeInt(out, overflowHandle.getId()); 6299 6300 } 6301 else 6302 { 6303 6306 headerLength = 6308 StoredFieldHeader.write( 6309 logicalDataOut, fieldStatus, 6310 fieldDataLength, slotFieldSize); 6311 6312 logicalDataOut.writeObject(column); 6313 fieldDataLength = 6314 (out.getPosition() - beginPosition) - headerLength; 6315 } 6316 6317 6319 fieldStatus = StoredFieldHeader.setFixed(fieldStatus, false); 6320 int fieldSizeOnPage = 6321 StoredFieldHeader.size(fieldStatus, fieldDataLength, slotFieldSize) 6322 + fieldDataLength; 6323 6324 userRowSize += fieldDataLength; 6325 6326 boolean fieldIsLong = isLong(fieldSizeOnPage, overflowThreshold); 6327 6328 if (((spaceAvailable < fieldSizeOnPage) || (fieldIsLong)) && 6330 (columnFlag != COLUMN_LONG)) 6331 { 6332 6334 if (fieldIsLong) 6335 { 6336 6339 if (!(column instanceof InputStream)) 6340 { 6341 ByteArray fieldData = 6343 new ByteArray( 6344 ((DynamicByteArrayOutputStream)out).getByteArray(), 6345 (columnBeginPosition), fieldDataLength); 6346 6347 ByteArrayInputStream columnIn = 6348 new ByteArrayInputStream ( 6349 fieldData.getArray(), columnBeginPosition, 6350 fieldDataLength); 6351 6352 MemByteHolder byteHolder = 6353 new MemByteHolder(fieldDataLength + 1); 6354 6355 RememberBytesInputStream bufferedIn = 6356 new RememberBytesInputStream(columnIn, byteHolder); 6357 6358 column = bufferedIn; 6361 } 6362 6363 out.setPosition(beginPosition); 6364 6365 LongColumnException lce = new LongColumnException(); 6369 lce.setColumn(column); 6370 throw lce; 6371 6372 } 6373 else 6374 { 6375 6377 out.setPosition(beginPosition); 6378 return(spaceAvailable); 6379 } 6380 } 6381 6382 out.setPosition(beginPosition); 6384 6385 fieldStatus = StoredFieldHeader.setFixed(fieldStatus, true); 6388 headerLength = StoredFieldHeader.write( 6389 out, fieldStatus, fieldDataLength, slotFieldSize); 6390 6391 out.setPosition(beginPosition + fieldDataLength + headerLength); 6393 6394 spaceAvailable -= fieldSizeOnPage; 6395 6396 if (columnFlag == COLUMN_LONG) 6398 { 6399 if (longColumnDone) 6406 return -1; 6407 else 6408 return 1; 6409 } else 6410 { 6411 return (spaceAvailable); 6412 } 6413 } 6414 6415 6430 private int logOverflowRecord( 6431 int slot, 6432 int spaceAvailable, 6433 DynamicByteArrayOutputStream out) 6434 throws StandardException, IOException 6435 { 6436 setOutputStream(out); 6437 6438 StoredRecordHeader pageRecordHeader = getHeaderAtSlot(slot); 6439 6440 StoredRecordHeader overflow_rh = getOverFlowRecordHeader(); 6441 overflow_rh.setOverflowFields(pageRecordHeader); 6442 6443 if (SanityManager.DEBUG) 6444 { 6445 SanityManager.ASSERT(overflow_rh.getOverflowPage() != 0); 6446 } 6447 6448 6468 6469 6474 int oldSize = pageRecordHeader.size(); 6475 int newSize = overflow_rh.size(); 6476 6477 if (oldSize < newSize) 6478 { 6479 int delta = newSize - oldSize; 6481 if (spaceAvailable < delta) 6482 { 6483 throw new NoSpaceOnPage(isOverflowPage()); 6484 } 6485 } 6486 6487 overflow_rh.write(logicalDataOut); 6489 6490 logRecordDataPortion( 6492 slot, LOG_RECORD_DEFAULT, pageRecordHeader, 6493 (FormatableBitSet) null, logicalDataOut, (RecordHandle)null); 6494 6495 return (-1); 6496 } 6497 6498 private int logOverflowField( 6499 DynamicByteArrayOutputStream out, 6500 int spaceAvailable, 6501 long overflowPage, 6502 int overflowId) 6503 throws StandardException, IOException 6504 { 6505 int fieldStatus = 6506 StoredFieldHeader.setOverflow( 6507 StoredFieldHeader.setInitial(), true); 6508 6509 int fieldSizeOnPage = 6510 CompressedNumber.sizeLong(overflowPage) + 6511 CompressedNumber.sizeInt(overflowId); 6512 6513 int fieldDataLength = fieldSizeOnPage; 6514 6515 fieldSizeOnPage += 6516 StoredFieldHeader.size(fieldStatus, fieldDataLength, slotFieldSize); 6517 6518 spaceAvailable -= fieldSizeOnPage; 6520 6521 if (spaceAvailable < 0) 6523 throw new NoSpaceOnPage(isOverflowPage()); 6524 6525 StoredFieldHeader.write( 6527 logicalDataOut, fieldStatus, fieldDataLength, slotFieldSize); 6528 CompressedNumber.writeLong(out, overflowPage); 6529 CompressedNumber.writeInt(out, overflowId); 6530 6531 return(spaceAvailable); 6533 } 6534 6535 6547 public void logRecord( 6548 int slot, 6549 int flag, 6550 int recordId, 6551 FormatableBitSet validColumns, 6552 OutputStream out, 6553 RecordHandle headRowHandle) 6554 throws StandardException, IOException 6555 { 6556 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 6557 6558 if (recordId != recordHeader.getId()) 6559 { 6560 StoredRecordHeader newRecordHeader = 6563 new StoredRecordHeader(recordHeader); 6564 6565 newRecordHeader.setId(recordId); 6566 6567 newRecordHeader.write(out); 6568 newRecordHeader = null; 6569 } 6570 else 6571 { 6572 recordHeader.write(out); 6574 } 6575 6576 logRecordDataPortion( 6577 slot, flag, recordHeader, validColumns, out, headRowHandle); 6578 6579 } 6580 6581 private void logRecordDataPortion( 6582 int slot, 6583 int flag, 6584 StoredRecordHeader recordHeader, 6585 FormatableBitSet validColumns, 6586 OutputStream out, 6587 RecordHandle headRowHandle) 6588 throws StandardException, IOException 6589 { 6590 int offset = getRecordOffset(slot); 6591 6592 int oldHeaderLength = recordHeader.size(); 6594 offset += oldHeaderLength; 6595 6596 int startField = recordHeader.getFirstField(); 6598 int endField = startField + recordHeader.getNumberFields(); 6599 int validColumnsSize = (validColumns == null) ? 0 : validColumns.getLength(); 6600 6601 for (int fieldId = startField; fieldId < endField; fieldId++) { 6602 6603 rawDataIn.setPosition(offset); 6604 6605 int fieldStatus = StoredFieldHeader.readStatus(rawDataIn); 6607 int fieldDataLength = StoredFieldHeader.readFieldDataLength(rawDataIn, fieldStatus, slotFieldSize); 6608 6609 if (((validColumns != null) && !(validColumnsSize > fieldId && validColumns.isSet(fieldId))) || 6613 ((flag & BasePage.LOG_RECORD_FOR_PURGE)!=0 && !StoredFieldHeader.isOverflow(fieldStatus))) 6614 { 6615 offset += StoredFieldHeader.size(fieldStatus, fieldDataLength, slotFieldSize); 6617 offset += fieldDataLength; 6618 6619 fieldStatus = StoredFieldHeader.setInitial(); 6621 fieldStatus = StoredFieldHeader.setNonexistent(fieldStatus); 6622 StoredFieldHeader.write(out, fieldStatus, 0, slotFieldSize); 6623 continue; 6624 } 6625 6626 if (((flag & BasePage.LOG_RECORD_FOR_UPDATE) != 0) && 6636 headRowHandle != null && 6637 StoredFieldHeader.isOverflow(fieldStatus) && 6638 owner.isTemporaryContainer() == false) 6639 { 6640 6641 int saveOffset = rawDataIn.getPosition(); long overflowPage = CompressedNumber.readLong((InputStream) rawDataIn); 6643 int overflowId = CompressedNumber.readInt((InputStream) rawDataIn); 6644 6645 Page firstPageOnColumnChain = getOverflowPage(overflowPage); 6651 PageTimeStamp ts = firstPageOnColumnChain.currentTimeStamp(); 6652 firstPageOnColumnChain.unlatch(); 6653 6654 RawTransaction rxact = (RawTransaction)owner.getTransaction(); 6655 6656 ReclaimSpace work = 6657 new ReclaimSpace(ReclaimSpace.COLUMN_CHAIN, 6658 headRowHandle, 6659 fieldId, overflowPage, overflowId, ts, 6663 rxact.getDataFactory(), true); 6664 6665 rxact.addPostCommitWork(work); 6666 6667 rawDataIn.setPosition(saveOffset); } 6669 6670 6671 offset += StoredFieldHeader.write(out, fieldStatus, fieldDataLength, slotFieldSize); 6673 6674 if (fieldDataLength != 0) { 6675 6676 out.write(pageData, offset, fieldDataLength); 6678 6679 offset += fieldDataLength; 6680 } 6681 } 6682 } 6683 6684 6695 6696 public void logField(int slot, int fieldNumber, OutputStream out) 6697 throws StandardException, IOException 6698 { 6699 int offset = getFieldOffset(slot, fieldNumber); 6700 6701 ArrayInputStream lrdi = rawDataIn; 6703 6704 lrdi.setPosition(offset); 6706 int fieldStatus = StoredFieldHeader.readStatus(lrdi); 6707 int fieldDataLength = StoredFieldHeader.readFieldDataLength(lrdi, fieldStatus, slotFieldSize); 6708 6709 StoredFieldHeader.write(out, fieldStatus, fieldDataLength, slotFieldSize); 6710 6711 if (fieldDataLength != 0) { 6712 out.write(pageData, lrdi.getPosition(), fieldDataLength); 6714 } 6715 } 6716 6717 6720 6721 6725 public RecordHandle insertAtSlot( 6726 int slot, 6727 Object [] row, 6728 FormatableBitSet validColumns, 6729 LogicalUndo undo, 6730 byte insertFlag, 6731 int overflowThreshold) 6732 throws StandardException 6733 { 6734 try { 6735 6736 return super.insertAtSlot(slot, row, validColumns, undo, insertFlag, overflowThreshold); 6737 6738 } catch (NoSpaceOnPage nsop) { 6739 6740 return null; 6748 6749 } 6750 } 6751 6752 6753 6757 public RecordHandle updateFieldAtSlot( 6758 int slot, 6759 int fieldId, 6760 Object newValue, 6761 LogicalUndo undo) 6762 throws StandardException 6763 { 6764 try { 6765 6766 return super.updateFieldAtSlot(slot, fieldId, newValue, undo); 6767 6768 } catch (NoSpaceOnPage nsop) { 6769 6770 6771 if (slotsInUse == 1) 6773 { 6774 throw StandardException.newException( 6775 SQLState.DATA_NO_SPACE_FOR_RECORD); 6776 } 6777 throw StandardException.newException( 6778 SQLState.DATA_NO_SPACE_FOR_RECORD); 6779 6780 6786 } 6787 6788 } 6789 6790 6794 public int fetchNumFieldsAtSlot(int slot) throws StandardException 6795 { 6796 6797 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 6798 6799 if (!recordHeader.hasOverflow()) 6800 return super.fetchNumFieldsAtSlot(slot); 6801 6802 BasePage overflowPage = getOverflowPage(recordHeader.getOverflowPage()); 6803 int count = overflowPage.fetchNumFieldsAtSlot(getOverflowSlot(overflowPage, recordHeader)); 6804 overflowPage.unlatch(); 6805 return count; 6806 } 6807 6808 6849 public int moveRecordForCompressAtSlot( 6850 int slot, 6851 Object [] row, 6852 RecordHandle[] old_handle, 6853 RecordHandle[] new_handle) 6854 throws StandardException 6855 { 6856 long src_pageno = getPageNumber(); 6857 6858 try 6859 { 6860 fetchFromSlot( 6861 null, 6862 slot, 6863 row, 6864 (FetchDescriptor) null, false); 6866 6867 int row_size = getRecordPortionLength(slot); 6868 6869 StoredPage dest_page = 6871 (StoredPage) owner.getPageForCompress(0, src_pageno); 6872 6873 if (dest_page != null) 6874 { 6875 if ((dest_page.getPageNumber() >= getPageNumber()) || 6876 (!dest_page.spaceForCopy(row_size))) 6877 { 6878 dest_page.unlatch(); 6880 dest_page = null; 6881 } 6882 } 6883 6884 if (dest_page == null) 6885 { 6886 dest_page = (StoredPage) 6888 owner.getPageForCompress( 6889 ContainerHandle.GET_PAGE_UNFILLED, src_pageno); 6890 6891 if (dest_page != null) 6892 { 6893 if ((dest_page.getPageNumber() >= getPageNumber()) || 6894 (!dest_page.spaceForCopy(row_size))) 6895 { 6896 dest_page.unlatch(); 6898 dest_page = null; 6899 } 6900 } 6901 } 6902 6903 if (dest_page == null) 6904 { 6905 dest_page = (StoredPage) owner.addPage(); 6907 6908 if (dest_page.getPageNumber() >= getPageNumber()) 6909 { 6910 owner.removePage(dest_page); 6911 dest_page = null; 6912 } 6913 } 6914 6915 if (dest_page != null) 6916 { 6917 int dest_slot = dest_page.recordCount(); 6918 6919 old_handle[0] = getRecordHandleAtSlot(slot); 6920 6921 copyAndPurge(dest_page, slot, 1, dest_slot); 6922 6923 new_handle[0] = dest_page.getRecordHandleAtSlot(dest_slot); 6924 6925 dest_page.unlatch(); 6926 6927 return(1); 6928 } 6929 else 6930 { 6931 return(0); 6932 } 6933 } 6934 catch (IOException ioe) 6935 { 6936 throw StandardException.newException( 6937 SQLState.DATA_UNEXPECTED_EXCEPTION, ioe); 6938 } 6939 } 6940 6941 6944 6945 6948 public void logAction(LogInstant instant) throws StandardException 6949 { 6950 if (SanityManager.DEBUG) { 6951 SanityManager.ASSERT(isLatched()); 6952 } 6953 6954 if (rawDataOut == null) 6955 createOutStreams(); 6956 6957 if (!isActuallyDirty()) { 6958 if (!isOverflowPage() && ((getPageStatus() & VALID_PAGE) != 0)) { 6961 initialRowCount = internalNonDeletedRecordCount(); 6962 } else 6963 initialRowCount = 0; 6964 } 6965 6966 setDirty(); 6967 6968 bumpPageVersion(); 6969 updateLastLogInstant(instant); 6970 } 6971 6972 6973 6974 private void cleanPage() 6975 { 6976 setDirty(); 6977 6978 clearSection(0, getPageSize()); 6980 6981 slotsInUse = 0; 6982 deletedRowCount = 0; 6983 headerOutOfDate = true; 6986 clearAllSpace(); 6987 6988 } 6989 6990 7001 public void initPage(LogInstant instant, byte status, int recordId, 7002 boolean overflow, boolean reuse) 7003 throws StandardException 7004 { 7005 logAction(instant); 7008 7009 if (reuse) 7010 { 7011 cleanPage(); 7012 super.cleanPageForReuse(); 7013 } 7014 7016 headerOutOfDate = true; setPageStatus(status); 7019 isOverflowPage = overflow; 7020 nextId = recordId; 7021 7022 } 7023 7024 7028 public void setPageStatus(LogInstant instant, byte status) 7029 throws StandardException 7030 { 7031 logAction(instant); 7032 headerOutOfDate = true; 7035 setPageStatus(status); 7036 } 7037 7038 7042 public void setReservedSpace(LogInstant instant, int slot, int value) 7043 throws StandardException, IOException 7044 { 7045 logAction(instant); 7046 headerOutOfDate = true; 7049 int delta = value - getReservedCount(slot); 7050 7051 if (SanityManager.DEBUG) { 7052 SanityManager.ASSERT(delta <= freeSpace, 7053 "Cannot grow reserved space because there is not enough free space on the page"); 7054 SanityManager.ASSERT(delta != 0, 7055 "Set Reserved Space called to set identical value"); 7056 7057 if (value < 0) 7058 SanityManager.THROWASSERT( 7059 "Cannot set reserved space to value " + value); 7060 } 7061 7062 int nextRecordOffset = getRecordOffset(slot) + getTotalSpace(slot); 7065 7066 if (delta > 0) { 7067 expandPage(nextRecordOffset, delta); 7069 } else { 7070 shrinkPage(nextRecordOffset, -delta); 7072 } 7073 7074 rawDataOut.setPosition(getSlotOffset(slot) + (2*slotFieldSize)); 7076 if (slotFieldSize == SMALL_SLOT_SIZE) 7077 logicalDataOut.writeShort(value); 7078 else 7079 logicalDataOut.writeInt(value); 7080 7081 } 7082 7083 7084 7090 public void storeRecord(LogInstant instant, int slot, boolean insert, ObjectInput in) 7091 throws StandardException, IOException 7092 { 7093 logAction(instant); 7094 7095 if (insert) 7096 storeRecordForInsert(slot, in); 7097 else 7098 storeRecordForUpdate(slot, in); 7099 } 7100 7101 private void storeRecordForInsert(int slot, ObjectInput in) 7102 throws StandardException, IOException 7103 { 7104 7105 StoredRecordHeader recordHeader = shiftUp(slot); 7106 if (recordHeader == null) { 7107 recordHeader = new StoredRecordHeader(); 7108 setHeaderAtSlot(slot, recordHeader); 7109 } 7110 7111 bumpRecordCount(1); 7112 7113 recordHeader.read(in); 7115 7116 if (recordHeader.isDeleted()) { 7118 deletedRowCount++; 7119 headerOutOfDate = true; 7120 } 7121 7122 if (nextId <= recordHeader.getId()) 7125 nextId = recordHeader.getId()+1; 7126 7127 int recordOffset = firstFreeByte; 7128 int offset = recordOffset; 7129 7130 int numberFields = recordHeader.getNumberFields(); 7132 7133 rawDataOut.setPosition(offset); 7134 offset += recordHeader.write(rawDataOut); 7135 7136 int userData = 0; 7137 for (int i = 0; i < numberFields; i++) { 7138 7139 int newFieldStatus = StoredFieldHeader.readStatus(in); 7141 int newFieldDataLength = StoredFieldHeader.readFieldDataLength(in, newFieldStatus, slotFieldSize); 7142 newFieldStatus = StoredFieldHeader.setFixed(newFieldStatus, false); 7143 7144 rawDataOut.setPosition(offset); 7145 offset += StoredFieldHeader.write(rawDataOut, newFieldStatus, newFieldDataLength, slotFieldSize); 7146 7147 if (newFieldDataLength != 0) { 7148 in.readFully(pageData, offset, newFieldDataLength); 7149 offset += newFieldDataLength; 7150 userData += newFieldDataLength; 7151 } 7152 } 7153 7154 int dataWritten = offset - firstFreeByte; 7155 7156 freeSpace -= dataWritten; 7157 firstFreeByte += dataWritten; 7158 7159 int reservedSpace = 0; 7160 if (minimumRecordSize > 0) { 7161 7162 if (userData < minimumRecordSize) { 7166 reservedSpace = minimumRecordSize - userData; 7167 freeSpace -= reservedSpace; 7168 firstFreeByte += reservedSpace; 7169 } 7170 } 7171 7172 addSlotEntry(slot, recordOffset, dataWritten, reservedSpace); 7174 7175 if (SanityManager.DEBUG) 7176 { 7177 if ((firstFreeByte > getSlotOffset(slot)) || 7178 (freeSpace < 0)) 7179 { 7180 SanityManager.THROWASSERT( 7181 " firstFreeByte = " + firstFreeByte + 7182 " dataWritten = " + dataWritten + 7183 " getSlotOffset(slot) = " + getSlotOffset(slot) + 7184 " slot = " + slot + 7185 " firstFreeByte = " + firstFreeByte + 7186 " freeSpace = " + freeSpace + 7187 " page = " + this); 7188 } 7189 } 7190 7191 if ((firstFreeByte > getSlotOffset(slot)) || (freeSpace < 0)) 7192 { 7193 throw dataFactory.markCorrupt( 7194 StandardException.newException( 7195 SQLState.DATA_CORRUPT_PAGE, getPageId())); 7196 } 7197 7198 } 7199 7200 7201 private void storeRecordForUpdate(int slot, ObjectInput in) 7202 throws StandardException, IOException 7203 { 7204 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 7206 StoredRecordHeader newRecorderHeader = new StoredRecordHeader(); 7207 7208 newRecorderHeader.read(in); 7210 7211 int oldFieldCount = recordHeader.getNumberFields(); 7212 int newFieldCount = newRecorderHeader.getNumberFields(); 7213 7214 int startField = recordHeader.getFirstField(); 7215 if (SanityManager.DEBUG) { 7216 if (startField != newRecorderHeader.getFirstField()) 7217 SanityManager.THROWASSERT("First field changed from " + startField + " to " + newRecorderHeader.getFirstField()); 7218 } 7219 7220 if (newFieldCount < oldFieldCount) { 7225 7226 int oldDataStartingOffset = getFieldOffset(slot, startField + newFieldCount); 7227 7228 int deleteLength = getRecordOffset(slot) + getRecordPortionLength(slot) - oldDataStartingOffset; 7230 7231 updateRecordPortionLength(slot, -(deleteLength), deleteLength); 7233 } 7234 7235 7237 int startingOffset = getRecordOffset(slot); 7238 int newOffset = startingOffset; 7239 int oldOffset = startingOffset; 7240 7241 int reservedSpaceFieldId = newFieldCount < oldFieldCount ? 7243 newFieldCount - 1 : oldFieldCount - 1; 7244 reservedSpaceFieldId += startField; 7245 7246 7247 DynamicByteArrayOutputStream newDataToWrite = null; 7250 7251 rawDataOut.setPosition(newOffset); 7252 7253 int oldLength = recordHeader.size(); 7255 int newLength = newRecorderHeader.size(); 7256 7257 int unusedSpace = oldLength; 7259 if (reservedSpaceFieldId < startField) unusedSpace += getReservedCount(slot); 7262 7263 if (unusedSpace >= newLength) { 7264 newRecorderHeader.write(rawDataOut); 7265 newOffset += newLength; 7266 unusedSpace -= newLength; 7267 7268 } else { 7269 7270 newDataToWrite = new DynamicByteArrayOutputStream(getPageSize()); 7271 newRecorderHeader.write(newDataToWrite); 7272 } 7273 oldOffset += oldLength; 7274 int recordDelta = (newLength - oldLength); 7275 7276 int oldFieldStatus = 0; 7277 int oldFieldDataLength = 0; 7278 int newFieldStatus = 0; 7279 int newFieldDataLength = 0; 7280 7281 int oldEndFieldExclusive = startField + oldFieldCount; 7282 int newEndFieldExclusive = startField + newFieldCount; 7283 7284 for (int fieldId = startField; fieldId < newEndFieldExclusive; fieldId++) { 7285 7286 int oldFieldLength = 0; 7287 if (fieldId < oldEndFieldExclusive) { 7288 rawDataIn.setPosition(oldOffset); 7289 oldFieldStatus = StoredFieldHeader.readStatus(rawDataIn); 7290 oldFieldDataLength = StoredFieldHeader.readFieldDataLength(rawDataIn, oldFieldStatus, slotFieldSize); 7291 oldFieldLength = StoredFieldHeader.size(oldFieldStatus, oldFieldDataLength, slotFieldSize) 7292 + oldFieldDataLength; 7293 } 7294 7295 newFieldStatus = StoredFieldHeader.readStatus(in); 7296 newFieldDataLength = StoredFieldHeader.readFieldDataLength(in, newFieldStatus, slotFieldSize); 7297 7298 if (StoredFieldHeader.isNonexistent(newFieldStatus) && (fieldId < oldEndFieldExclusive)) { 7301 7302 if ((newDataToWrite == null) || (newDataToWrite.getUsed() == 0)) { 7304 if (newOffset == oldOffset) { 7307 if (SanityManager.DEBUG) { 7309 if (unusedSpace != 0) 7310 SanityManager.THROWASSERT("Unused space is out of sync, expect 0 got " + unusedSpace); 7311 } 7312 } else { 7313 if (SanityManager.DEBUG) { 7315 if (unusedSpace != (oldOffset - newOffset)) 7316 SanityManager.THROWASSERT( 7317 "Unused space is out of sync expected " + (oldOffset - newOffset) + " got " + unusedSpace); 7318 } 7319 7320 System.arraycopy(pageData, oldOffset, pageData, newOffset, oldFieldLength); 7321 } 7322 newOffset += oldFieldLength; 7323 7324 if (fieldId == reservedSpaceFieldId) 7326 unusedSpace += getReservedCount(slot); 7327 7328 } else { 7329 int position = newDataToWrite.getPosition(); 7332 newDataToWrite.setPosition(position + oldFieldLength); 7333 System.arraycopy(pageData, oldOffset, 7334 newDataToWrite.getByteArray(), position, oldFieldLength); 7335 7336 unusedSpace += oldFieldLength; 7337 7338 if (fieldId == reservedSpaceFieldId) 7340 unusedSpace += getReservedCount(slot); 7341 7342 int copyLength = moveSavedDataToPage(newDataToWrite, unusedSpace, newOffset); 7344 newOffset += copyLength; 7345 unusedSpace -= copyLength; 7346 7347 } 7348 oldOffset += oldFieldLength; 7349 continue; 7350 } 7351 7352 newFieldStatus = StoredFieldHeader.setFixed(newFieldStatus, false); 7353 7354 int newFieldHeaderLength = StoredFieldHeader.size(newFieldStatus, newFieldDataLength, slotFieldSize); 7355 int newFieldLength = newFieldHeaderLength + newFieldDataLength; 7356 7357 recordDelta += (newFieldLength - oldFieldLength); 7358 7359 7361 unusedSpace += oldFieldLength; 7363 oldOffset += oldFieldLength; 7364 7365 if (fieldId == reservedSpaceFieldId) 7367 unusedSpace += getReservedCount(slot); 7368 7369 if ((newDataToWrite != null) && (newDataToWrite.getUsed() != 0)) { 7370 7371 int copyLength = moveSavedDataToPage(newDataToWrite, unusedSpace, newOffset); 7373 newOffset += copyLength; 7374 unusedSpace -= copyLength; 7375 } 7376 7377 if (((newDataToWrite == null) || (newDataToWrite.getUsed() == 0)) 7378 && (unusedSpace >= newFieldHeaderLength)) { 7379 7380 rawDataOut.setPosition(newOffset); 7382 newOffset += StoredFieldHeader.write(rawDataOut, newFieldStatus, newFieldDataLength, slotFieldSize); 7383 unusedSpace -= newFieldHeaderLength; 7384 7385 if (newFieldDataLength != 0) { 7386 7387 int fieldCopy = unusedSpace >= newFieldDataLength ? 7389 newFieldDataLength : unusedSpace; 7390 7391 if (fieldCopy != 0) { 7392 in.readFully(pageData, newOffset, fieldCopy); 7393 7394 newOffset += fieldCopy; 7395 unusedSpace -= fieldCopy; 7396 } 7397 7398 7399 fieldCopy = newFieldDataLength - fieldCopy; 7400 if (fieldCopy != 0) { 7401 if (newDataToWrite == null) 7402 newDataToWrite = new DynamicByteArrayOutputStream(newFieldLength * 2); 7403 7404 int position = newDataToWrite.getPosition(); 7406 newDataToWrite.setPosition(position + fieldCopy); 7407 in.readFully(newDataToWrite.getByteArray(), 7408 position, fieldCopy); 7409 7410 } 7411 } 7412 } else { 7413 7416 if (newDataToWrite == null) 7417 newDataToWrite = new DynamicByteArrayOutputStream(newFieldLength * 2); 7418 7419 StoredFieldHeader.write(newDataToWrite, newFieldStatus, newFieldDataLength, slotFieldSize); 7420 7421 if (newFieldDataLength != 0) { 7423 int position = newDataToWrite.getPosition(); 7424 newDataToWrite.setPosition(position + newFieldDataLength); 7425 in.readFully(newDataToWrite.getByteArray(), 7426 position, newFieldDataLength); 7427 } 7428 } 7429 } 7430 7431 7434 int reservedDelta; 7435 7436 if ((newDataToWrite != null) && (newDataToWrite.getUsed() != 0)) { 7437 7438 int nextRecordOffset = startingOffset + getTotalSpace(slot); 7440 7441 int spaceRequiredFromFreeSpace = newDataToWrite.getUsed() - (nextRecordOffset - newOffset); 7442 7443 if (SanityManager.DEBUG) { 7444 if (newOffset > nextRecordOffset) 7445 SanityManager.THROWASSERT("data has overwritten next record - offset " + newOffset 7446 + " next record " + nextRecordOffset); 7447 7448 if ((spaceRequiredFromFreeSpace <= 0) || (spaceRequiredFromFreeSpace > freeSpace)) 7449 SanityManager.THROWASSERT("invalid space required " + spaceRequiredFromFreeSpace 7450 + " newDataToWrite.getUsed() " + newDataToWrite.getUsed() 7451 + " nextRecordOffset " + nextRecordOffset 7452 + " newOffset " + newOffset 7453 + " reservedSpaceFieldId " + reservedSpaceFieldId 7454 + " startField " + startField 7455 + " newEndFieldExclusive " + newEndFieldExclusive 7456 + " newFieldCount " + newFieldCount 7457 + " oldFieldCount " + oldFieldCount 7458 + " slot " + slot 7459 + " freeSpace " + freeSpace 7460 + " unusedSpace " + unusedSpace 7461 + " page " + getPageId()); 7462 7463 7464 if ((getReservedCount(slot) + spaceRequiredFromFreeSpace) != recordDelta) 7465 SanityManager.THROWASSERT("mismatch on count: reserved " + getReservedCount(slot) + 7466 "free space take " + spaceRequiredFromFreeSpace + 7467 "record delta " + recordDelta); 7468 7469 } 7470 7471 if (spaceRequiredFromFreeSpace > freeSpace) { 7472 throw dataFactory.markCorrupt( 7473 StandardException.newException( 7474 SQLState.DATA_CORRUPT_PAGE, getPageId())); 7475 } 7476 7477 expandPage(nextRecordOffset, spaceRequiredFromFreeSpace); 7480 7481 unusedSpace += spaceRequiredFromFreeSpace; 7482 7483 moveSavedDataToPage(newDataToWrite, unusedSpace, newOffset); 7484 7485 reservedDelta = -1 * getReservedCount(slot); 7486 7487 if (SanityManager.DEBUG) { 7488 if (newDataToWrite.getUsed() != 0) 7489 SanityManager.THROWASSERT("data is left in save buffer ... " + newDataToWrite.getUsed()); 7490 } 7491 } else { 7492 reservedDelta = -1 * recordDelta; 7493 } 7494 7495 updateRecordPortionLength(slot, recordDelta, reservedDelta); 7497 7498 setHeaderAtSlot(slot, newRecorderHeader); 7499 } 7500 7501 private int moveSavedDataToPage(DynamicByteArrayOutputStream savedData, int unusedSpace, int pageOffset) { 7502 if (unusedSpace > (savedData.getUsed() / 2)) { 7504 int copyLength = unusedSpace <= savedData.getUsed() ? 7506 unusedSpace : savedData.getUsed(); 7507 System.arraycopy(savedData.getByteArray(), 0, 7508 pageData, pageOffset, copyLength); 7509 7510 savedData.discardLeft(copyLength); 7512 7513 return copyLength; 7514 } 7515 7516 return 0; 7517 } 7518 7519 7520 7535 private void createSpaceForUpdate(int slot, int offset, int oldLength, int newLength) 7536 throws StandardException, IOException 7537 { 7538 7539 if (newLength <= oldLength) { 7541 7542 int diffLength = oldLength - newLength; 7544 7545 if (diffLength == 0) 7547 return; 7548 7549 int remainingLength = 7551 shiftRemainingData(slot, offset, oldLength, newLength); 7552 7553 clearSection(offset + newLength + remainingLength, diffLength); 7555 7556 if (SanityManager.DEBUG) { 7557 7558 if ((getRecordPortionLength(slot) - diffLength) != 7559 ((offset - getRecordOffset(slot)) + newLength + 7560 remainingLength)) 7561 { 7562 SanityManager.THROWASSERT( 7563 " Slot table trying to update record length " + 7564 (getRecordPortionLength(slot) - diffLength) + 7565 " that is not the same as what it actully is"); 7566 } 7567 } 7568 7569 updateRecordPortionLength(slot, -(diffLength), diffLength); 7571 return; 7572 } 7573 7574 7577 int extraLength = newLength - oldLength; 7578 7579 if (SanityManager.DEBUG) 7581 SanityManager.ASSERT(extraLength > 0); 7582 7583 int recordReservedSpace = getReservedCount(slot); 7584 int reservedDelta = 0; 7585 7586 int spaceRequiredFromFreeSpace = extraLength - recordReservedSpace; 7587 7588 if (SanityManager.DEBUG) { 7589 if (spaceRequiredFromFreeSpace > freeSpace) 7590 SanityManager.THROWASSERT( 7591 "spaceRequiredFromFreeSpace = " + 7592 spaceRequiredFromFreeSpace + 7593 ";freeSpace = " + freeSpace + 7594 ";newLength = " + newLength + 7595 ";oldLength = " + oldLength + 7596 ";\npage= " + this); 7597 } 7598 7599 if (spaceRequiredFromFreeSpace > 0) { 7600 7602 int nextRecordOffset = getRecordOffset(slot) + getTotalSpace(slot); 7603 7604 expandPage(nextRecordOffset, spaceRequiredFromFreeSpace); 7607 7608 reservedDelta = -(recordReservedSpace); 7610 } else { 7611 7613 reservedDelta = -(extraLength); 7615 } 7616 7617 int remainingLength = shiftRemainingData(slot, offset, oldLength, newLength); 7619 7620 if (SanityManager.DEBUG) { 7621 if ((extraLength + reservedDelta) < 0) 7622 SanityManager.THROWASSERT( 7623 "total space the record occupies cannot shrink, extraLength = " 7624 + extraLength + " reservedDelta = " + reservedDelta 7625 + " spacerequired = " + spaceRequiredFromFreeSpace 7626 + " recordReservedSpace = " + recordReservedSpace); 7627 } 7628 7629 updateRecordPortionLength(slot, extraLength, reservedDelta); 7631 } 7632 7633 7639 public void storeField(LogInstant instant, int slot, int fieldNumber, ObjectInput in) 7640 throws StandardException, IOException 7641 { 7642 logAction(instant); 7643 7644 int offset = getFieldOffset(slot, fieldNumber); 7645 7646 ArrayInputStream lrdi = rawDataIn; 7648 lrdi.setPosition(offset); 7649 int oldFieldStatus = StoredFieldHeader.readStatus(lrdi); 7650 int oldFieldDataLength = StoredFieldHeader.readFieldDataLength(lrdi, oldFieldStatus, slotFieldSize); 7651 7652 int newFieldStatus = StoredFieldHeader.readStatus(in); 7653 int newFieldDataLength = StoredFieldHeader.readFieldDataLength(in, newFieldStatus, slotFieldSize); 7654 newFieldStatus = StoredFieldHeader.setFixed(newFieldStatus, false); 7655 7656 int oldFieldLength = StoredFieldHeader.size(oldFieldStatus, oldFieldDataLength, slotFieldSize) + oldFieldDataLength; 7657 int newFieldLength = StoredFieldHeader.size(newFieldStatus, newFieldDataLength, slotFieldSize) + newFieldDataLength; 7658 7659 createSpaceForUpdate(slot, offset, oldFieldLength, newFieldLength); 7660 7661 rawDataOut.setPosition(offset); 7662 offset += StoredFieldHeader.write(rawDataOut, newFieldStatus, newFieldDataLength, slotFieldSize); 7663 7664 if (newFieldDataLength != 0) 7665 in.readFully(pageData, offset, newFieldDataLength); 7666 } 7667 7668 7676 public void reserveSpaceForSlot(LogInstant instant, int slot, int spaceToReserve) 7677 throws StandardException, IOException 7678 { 7679 logAction(instant); 7680 7681 int extraSpace = spaceToReserve - getReservedCount(slot); 7682 if (extraSpace <= 0) 7683 return; 7684 7685 if (freeSpace < extraSpace) 7686 throw new NoSpaceOnPage(isOverflowPage()); 7687 7688 int startingOffset = getRecordOffset(slot); 7690 int nextRecordOffset = startingOffset + getTotalSpace(slot); 7691 7692 expandPage(nextRecordOffset, extraSpace); 7695 7696 setSlotEntry(slot, startingOffset, getRecordPortionLength(slot), spaceToReserve); 7697 } 7698 7699 7704 public void skipField(ObjectInput in) throws IOException { 7705 7706 7707 int fieldStatus = StoredFieldHeader.readStatus(in); 7708 int fieldDataLength = StoredFieldHeader.readFieldDataLength(in, fieldStatus, slotFieldSize); 7709 7710 if (fieldDataLength != 0) { 7711 in.skipBytes(fieldDataLength); 7712 } 7713 } 7714 7715 public void skipRecord(ObjectInput in) throws IOException 7716 { 7717 7718 StoredRecordHeader recordHeader = new StoredRecordHeader(); 7719 recordHeader.read(in); 7720 7721 for (int i = recordHeader.getNumberFields(); i > 0; i--) { 7722 skipField(in); 7723 } 7724 } 7725 7726 7735 private int shiftRemainingData(int slot, int offset, int oldLength, int newLength) 7736 throws IOException 7737 { 7738 7739 int remainingLength = (getRecordOffset(slot) + getRecordPortionLength(slot)) - 7742 (offset + oldLength); 7743 7744 if (SanityManager.DEBUG) { 7745 7746 if (!(((remainingLength >= 0) && 7747 (getRecordPortionLength(slot) >= oldLength)))) 7748 { 7749 SanityManager.THROWASSERT( 7750 "oldLength = " + oldLength + " newLength = " + newLength + 7751 "remainingLength = " + remainingLength + 7752 " offset = " + offset + 7753 " getRecordOffset(" + slot + ") = " + getRecordOffset(slot)+ 7754 " getRecordPortionLength(" + slot + ") = " + 7755 getRecordPortionLength(slot)); 7756 } 7757 } 7758 7759 if (remainingLength != 0) { 7760 System.arraycopy(pageData, offset + oldLength, 7761 pageData, offset + newLength, remainingLength); 7762 } 7763 7764 return remainingLength; 7765 7766 } 7767 7768 7775 public void setDeleteStatus(LogInstant instant, int slot, boolean delete) 7776 throws StandardException, IOException 7777 { 7778 7779 logAction(instant); 7780 7781 deletedRowCount += super.setDeleteStatus(slot, delete); 7782 headerOutOfDate = true; 7783 7784 int offset = getRecordOffset(slot); 7785 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 7786 7787 rawDataOut.setPosition(offset); 7788 recordHeader.write(logicalDataOut); 7789 } 7790 7791 7794 protected int internalDeletedRecordCount() 7795 { 7796 return deletedRowCount; 7797 } 7798 7799 7805 public void purgeRecord(LogInstant instant, int slot, int recordId) 7806 throws StandardException, IOException 7807 { 7808 7809 logAction(instant); 7810 7811 if (getHeaderAtSlot(slot).isDeleted()) 7813 deletedRowCount--; 7814 7815 int startByte = getRecordOffset(slot); 7816 int endByte = startByte + getTotalSpace(slot) - 1; 7817 7818 compressPage(startByte, endByte); 7819 7820 removeSlotEntry(slot); 7822 7823 removeAndShiftDown(slot); 7825 } 7826 7827 7830 7831 7839 private int getFieldOffset(int slot, int fieldNumber) throws IOException 7840 { 7841 int offset = getRecordOffset(slot); 7843 7844 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 7845 7846 int startField = recordHeader.getFirstField(); 7848 7849 if (SanityManager.DEBUG) { 7850 int numberFields = recordHeader.getNumberFields(); 7851 7852 if ((fieldNumber < startField) || (fieldNumber >= (startField + numberFields))) 7853 SanityManager.THROWASSERT( 7854 "fieldNumber: " + fieldNumber + 7855 " start field: " + startField + 7856 " number of fields " + numberFields); 7857 } 7858 7859 ArrayInputStream lrdi = rawDataIn; 7860 7861 lrdi.setPosition(offset + recordHeader.size()); 7863 7864 for (int i = startField; i < fieldNumber; i++) { 7866 skipField(lrdi); 7867 } 7868 7869 return rawDataIn.getPosition(); 7870 } 7871 7872 7873 7876 7877 7881 public PageTimeStamp currentTimeStamp() 7882 { 7883 return new PageVersion(getPageNumber(), getPageVersion()); 7885 } 7886 7887 7893 public void setTimeStamp(PageTimeStamp ts) throws StandardException 7894 { 7895 if (ts == null) 7896 { 7897 throw StandardException.newException(SQLState.DATA_TIME_STAMP_NULL); 7898 } 7899 7900 if (!(ts instanceof PageVersion)) 7901 { 7902 throw StandardException.newException( 7903 SQLState.DATA_TIME_STAMP_ILLEGAL, ts); 7904 } 7905 7906 PageVersion pv = (PageVersion)ts; 7907 7908 pv.setPageNumber(getPageNumber()); 7909 pv.setPageVersion(getPageVersion()); 7910 } 7911 7912 7921 public boolean equalTimeStamp(PageTimeStamp ts) throws StandardException 7922 { 7923 if (ts == null) 7924 return false; 7925 7926 if (!(ts instanceof PageVersion)) 7927 { 7928 throw StandardException.newException( 7929 SQLState.DATA_TIME_STAMP_ILLEGAL, ts); 7930 } 7931 7932 PageVersion pv = (PageVersion)ts; 7933 7934 if (pv.getPageNumber() != getPageNumber()) 7935 { 7936 throw StandardException.newException( 7937 SQLState.DATA_TIME_STAMP_ILLEGAL, ts); 7938 } 7939 7940 return (pv.getPageVersion() == getPageVersion()); 7941 } 7942 7943 7944 public String toString() 7945 { 7946 if (SanityManager.DEBUG) 7947 { 7948 if (SanityManager.DEBUG_ON("DeadlockTrace") || SanityManager.DEBUG_ON("userLockStackTrace")) 7949 return "page = " + getIdentity(); 7950 7951 String str = "---------------------------------------------------\n"; 7952 str += pageHeaderToString(); 7953 7955 for (int s = 0; s < slotsInUse; s++) 7957 str += recordToString(s); 7958 7959 { 7961 str += "---------------------------------------------------\n"; 7962 str += pagedataToHexDump(pageData); 7963 str += "---------------------------------------------------\n"; 7964 } 7965 return str; 7966 } 7967 else 7968 return null; 7969 } 7970 7971 8005 private static String pagedataToHexDump(byte[] data) 8006 { 8007 return org.apache.derby.iapi.util.StringUtil.hexDump(data); 8008 } 8009 8010 private String pageHeaderToString() 8011 { 8012 if (SanityManager.DEBUG) { 8013 return "page id " + getIdentity() + 8014 " Overflow: " + isOverflowPage + 8015 " PageVersion: " + getPageVersion() + 8016 " SlotsInUse: " + slotsInUse + 8017 " DeletedRowCount: " + deletedRowCount + 8018 " PageStatus: " + getPageStatus() + 8019 " NextId: " + nextId + 8020 " firstFreeByte: " + firstFreeByte + 8021 " freeSpace: " + freeSpace + 8022 " totalSpace: " + totalSpace + 8023 " spareSpace: " + spareSpace + 8024 " PageSize: " + getPageSize() + 8025 "\n"; 8026 } 8027 else 8028 return null; 8029 } 8030 8031 private String recordToString(int slot) 8032 { 8033 if (SanityManager.DEBUG) 8034 { 8035 String str = new String (); 8036 try 8037 { 8038 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 8039 int offset = getRecordOffset(slot); 8040 int numberFields = recordHeader.getNumberFields(); 8041 str = "\nslot " + slot + " offset " + offset + " " + 8042 " recordlen " + getTotalSpace(slot) + 8043 " (" + getRecordPortionLength(slot) + 8044 "," + getReservedCount(slot) + ")"+ 8045 recordHeader.toString(); 8046 8047 rawDataIn.setPosition(offset + recordHeader.size()); 8048 8049 for (int i = 0; i < numberFields; i++) 8050 { 8051 int fieldStatus = StoredFieldHeader.readStatus(rawDataIn); 8052 int fieldDataLength = StoredFieldHeader.readFieldDataLength(rawDataIn, fieldStatus, slotFieldSize); 8053 if (fieldDataLength < 0) 8054 { 8055 str += "\n\tField " + i + ": offset=" + offset + " null " + 8056 StoredFieldHeader.toDebugString(fieldStatus); 8057 } 8058 else 8059 { 8060 str += "\n\tField " + i + ": offset=" + offset + 8061 " len=" + fieldDataLength + " " + 8062 StoredFieldHeader.toDebugString(fieldStatus); 8063 8064 if (StoredFieldHeader.isOverflow(fieldStatus)) 8065 { 8066 if (i == 0 && fieldDataLength != 3) 8071 { 8072 offset = rawDataIn.getPosition() + fieldDataLength; 8074 long overflowPage = CompressedNumber.readLong((InputStream) rawDataIn); 8075 int overflowId = CompressedNumber.readInt((InputStream) rawDataIn); 8076 8077 str += "Questionable long column at (" + 8078 overflowPage + "," + overflowId + ")"; 8079 rawDataIn.setPosition(offset); 8080 } 8081 else 8082 { 8083 long overflowPage = CompressedNumber.readLong((InputStream) rawDataIn); 8085 int overflowId = CompressedNumber.readInt((InputStream) rawDataIn); 8086 str += "long column at (" + overflowPage + "," + overflowId + ")"; 8087 } 8088 } 8089 else 8090 { 8091 offset = rawDataIn.getPosition() + fieldDataLength; 8093 rawDataIn.setPosition(offset); 8094 } 8095 } 8096 } 8097 str += "\n"; 8098 8099 } 8100 catch (IOException ioe) 8101 { 8102 str += "\n ======= ERROR IOException =============\n"; 8103 str += ioe.toString(); 8104 } 8105 catch (StandardException se) 8106 { 8107 str += "\n ======= ERROR StandardException =============\n"; 8108 str += se.toString(); 8109 } 8110 8111 return str; 8112 } 8113 else 8114 return null; 8115 } 8116 8117 8120 8121 8125 protected StoredPage getOverflowPage(long pageNumber) throws StandardException 8126 { 8127 8128 StoredPage overflowPage = (StoredPage) owner.getPage(pageNumber); 8129 if (overflowPage == null) { 8130 } 8131 8132 8137 return overflowPage; 8138 } 8139 8140 8144 protected BasePage getNewOverflowPage() throws StandardException 8145 { 8146 8147 FileContainer myContainer = (FileContainer) containerCache.find(identity.getContainerId()); 8148 8149 try { 8150 return (BasePage) myContainer.addPage(owner, true); 8152 } finally { 8153 containerCache.release(myContainer); 8154 } 8155 } 8156 8157 8161 protected static int getOverflowSlot(BasePage overflowPage, StoredRecordHeader recordHeader) 8162 throws StandardException 8163 { 8164 8165 int slot = overflowPage.findRecordById( 8166 recordHeader.getOverflowId(), Page.FIRST_SLOT_NUMBER); 8167 8168 if (slot < 0) 8169 { 8170 throw StandardException.newException( 8171 SQLState.DATA_SLOT_NOT_ON_PAGE); 8172 } 8173 8174 return slot; 8175 } 8176 8177 8181 public BasePage getOverflowPageForInsert( 8182 int currentSlot, 8183 Object [] row, 8184 FormatableBitSet validColumns) 8185 throws StandardException 8186 { 8187 return getOverflowPageForInsert(currentSlot, row, validColumns, 0); 8188 } 8189 8190 8193 public BasePage getOverflowPageForInsert( 8194 int currentSlot, 8195 Object [] row, 8196 FormatableBitSet validColumns, 8197 int startColumn) 8198 throws StandardException 8199 { 8200 8202 long[] pageList = new long[5]; 8205 int pageCount = 0; 8206 8207 long currentOverflowPageNumber = 0; 8208 8209slotScan: 8210 for (int slot = 0; (slot < slotsInUse) && (pageCount < pageList.length); slot++) { 8211 8212 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 8213 if (!recordHeader.hasOverflow()) 8214 continue; 8215 8216 long overflowPageNumber = recordHeader.getOverflowPage(); 8217 8218 if (slot == currentSlot) { 8219 currentOverflowPageNumber = overflowPageNumber; 8220 continue; 8221 } 8222 8223 for (int i = 0; i < pageCount; i++) { 8224 if (pageList[i] == overflowPageNumber) 8225 continue slotScan; 8226 } 8227 8228 pageList[pageCount++] = overflowPageNumber; 8229 } 8230 8231 8232 for (int i = 0; i < pageCount; i++) { 8233 8234 long pageNumber = pageList[i]; 8235 8236 if (pageNumber == currentOverflowPageNumber) 8241 continue; 8242 StoredPage overflowPage = null; 8243 int spaceNeeded = 0; 8244 try { 8245 overflowPage = getOverflowPage(pageNumber); 8246 if ( overflowPage.spaceForInsert(row, validColumns, 8247 spaceNeeded, startColumn, 100)) 8248 { 8249 return overflowPage; 8251 } 8252 8253 spaceNeeded = ((StoredPage) overflowPage).getCurrentFreeSpace(); 8254 overflowPage.unlatch(); 8255 overflowPage = null; 8256 8257 } catch (StandardException se) { 8258 if (overflowPage != null) { 8259 overflowPage.unlatch(); 8260 overflowPage = null; 8261 } 8262 8263 } 8264 } 8265 8266 return getNewOverflowPage(); 8269 } 8270 8271 8279 protected void updateOverflowed( 8280 RawTransaction t, 8281 int slot, 8282 Object [] row, 8283 FormatableBitSet validColumns, 8284 StoredRecordHeader recordHeader) 8285 throws StandardException 8286 { 8287 8288 BasePage overflowPage = getOverflowPage(recordHeader.getOverflowPage()); 8289 8290 try { 8291 8292 int overflowSlot = getOverflowSlot(overflowPage, recordHeader); 8293 8294 overflowPage.doUpdateAtSlot(t, overflowSlot, recordHeader.getOverflowId(), row, validColumns); 8295 overflowPage.unlatch(); 8296 overflowPage = null; 8297 8298 return; 8299 8300 } finally { 8301 if (overflowPage != null) { 8302 overflowPage.unlatch(); 8303 overflowPage = null; 8304 } 8305 } 8306 } 8307 8308 8309 8314 public void updateOverflowDetails(RecordHandle handle, RecordHandle overflowHandle) 8315 throws StandardException 8316 { 8317 long handlePageNumber = handle.getPageNumber(); 8318 if (handlePageNumber == getPageNumber()) { 8319 updateOverflowDetails(this, handle, overflowHandle); 8320 return; 8321 } 8322 8323 StoredPage handlePage = (StoredPage) owner.getPage(handlePageNumber); 8324 8325 updateOverflowDetails(handlePage, handle, overflowHandle); 8326 handlePage.unlatch(); 8327 } 8328 8329 private void updateOverflowDetails(StoredPage handlePage, RecordHandle handle, RecordHandle overflowHandle) 8330 throws StandardException { 8331 handlePage.getOverFlowRecordHeader().setOverflowDetails(overflowHandle); 8333 8334 int slot = handlePage.getSlotNumber(handle); 8338 8339 handlePage.doUpdateAtSlot( 8343 owner.getTransaction(), slot, handle.getId(), 8344 (Object []) null, (FormatableBitSet) null); 8345 } 8346 8347 8350 public void updateFieldOverflowDetails(RecordHandle handle, RecordHandle overflowHandle) 8351 throws StandardException 8352 { 8353 Object [] row = new Object [2]; 8356 row[1] = overflowHandle; 8357 8358 FormatableBitSet validColumns = new FormatableBitSet(2); 8360 validColumns.set(1); 8361 8362 int slot = getSlotNumber(handle); 8366 8367 doUpdateAtSlot(owner.getTransaction(), slot, handle.getId(), row, validColumns); 8369 } 8370 8371 8374 public int appendOverflowFieldHeader(DynamicByteArrayOutputStream logBuffer, RecordHandle overflowHandle) 8375 throws StandardException, IOException 8376 { 8377 int fieldStatus = StoredFieldHeader.setInitial(); 8378 fieldStatus = StoredFieldHeader.setOverflow(fieldStatus, true); 8379 8380 long overflowPage = overflowHandle.getPageNumber(); 8381 int overflowId = overflowHandle.getId(); 8382 int fieldDataLength = CompressedNumber.sizeLong(overflowPage) 8383 + CompressedNumber.sizeInt(overflowId); 8384 8385 int lenWritten = StoredFieldHeader.write(logBuffer, fieldStatus, fieldDataLength, slotFieldSize); 8387 8388 lenWritten += CompressedNumber.writeLong(logBuffer, overflowPage); 8390 lenWritten += CompressedNumber.writeInt(logBuffer, overflowId); 8391 8392 return (lenWritten); 8394 } 8395 8396 protected int getSlotsInUse() 8397 { 8398 return(slotsInUse); 8399 } 8400 8401 8402 8405 private int getMaxDataLength(int spaceAvailable, int overflowThreshold) { 8406 8407 if (SanityManager.DEBUG) { 8408 if (overflowThreshold == 0) 8409 SanityManager.THROWASSERT("overflowThreshold cannot be 0"); 8410 } 8411 8412 int maxThresholdSpace = totalSpace * overflowThreshold / 100; 8417 int maxAvailable = 0; 8418 8419 if (spaceAvailable < (64 - 2)) 8420 maxAvailable = spaceAvailable - 2; 8421 else if (spaceAvailable < (16383 - 3)) 8422 maxAvailable = spaceAvailable - 3; 8423 else 8424 maxAvailable = spaceAvailable - 5; 8425 8426 return (maxAvailable > maxThresholdSpace ? maxThresholdSpace : maxAvailable); 8427 8428 } 8429 8430 8434 private boolean isLong(int fieldSize, int overflowThreshold) { 8435 8436 if (SanityManager.DEBUG) { 8437 if (overflowThreshold == 0) 8438 SanityManager.THROWASSERT("overflowThreshold cannot be 0"); 8439 } 8440 8441 int maxThresholdSize = maxFieldSize * overflowThreshold / 100; 8443 return (fieldSize > maxThresholdSize); 8444 } 8445 8446 8451 public void doUpdateAtSlot( 8452 RawTransaction t, 8453 int slot, 8454 int id, 8455 Object [] row, 8456 FormatableBitSet validColumns) 8457 throws StandardException 8458 { 8459 RecordHandle headRowHandle = 8464 isOverflowPage() ? null : getRecordHandleAtSlot(slot); 8465 8466 if (row == null) 8468 { 8469 owner.getActionSet().actionUpdate( 8470 t, this, slot, id, row, validColumns, -1, 8471 (DynamicByteArrayOutputStream) null, -1, headRowHandle); 8472 8473 return; 8474 } 8475 8476 int startColumn = RowUtil.nextColumn(row, validColumns, 0); 8478 if (startColumn == -1) 8479 return; 8480 8481 if (SanityManager.DEBUG) 8482 { 8483 if (!isOverflowPage() && validColumns != null) 8486 { 8487 if (RowUtil.getNumberOfColumns(-1, validColumns) > row.length) 8488 SanityManager.THROWASSERT("updating slot " + slot + 8489 " on page " + getIdentity() + " " + 8490 RowUtil.getNumberOfColumns(-1, validColumns) + 8491 " bits are set in validColumns but only " + 8492 row.length + " columns in row[]"); 8493 } 8494 } 8495 8496 8497 boolean rowHasReservedSpace = false; 8501 8502 StoredPage curPage = this; 8503 for (;;) 8504 { 8505 StoredRecordHeader rh = curPage.getHeaderAtSlot(slot); 8506 8507 int startField = rh.getFirstField(); 8508 int endFieldExclusive = startField + rh.getNumberFields(); 8509 8510 8512 8517 long nextPage = -1; 8518 int realStartColumn = -1; 8519 int realSpaceOnPage = -1; 8520 8521 if (!rh.hasOverflow() || 8522 ((startColumn >= startField) && 8523 (startColumn < endFieldExclusive))) 8524 { 8525 boolean hitLongColumn; 8526 int nextColumn = -1; 8527 Object [] savedFields = null; 8528 DynamicByteArrayOutputStream logBuffer = null; 8529 8530 do 8531 { 8532 try 8533 { 8534 nextColumn = 8545 owner.getActionSet().actionUpdate( 8546 t, curPage, slot, id, row, validColumns, 8547 realStartColumn, logBuffer, 8548 realSpaceOnPage, headRowHandle); 8549 8550 hitLongColumn = false; 8551 8552 } 8553 catch (LongColumnException lce) 8554 { 8555 8556 if (lce.getRealSpaceOnPage() == -1) 8557 { 8558 8562 logBuffer = lce.getLogBuffer(); 8565 8566 savedFields = 8567 (Object []) lce.getColumn(); 8568 8569 realStartColumn = lce.getNextColumn(); 8570 realSpaceOnPage = -1; 8571 8572 hitLongColumn = true; 8573 8574 continue; 8575 } 8576 8577 8578 logBuffer = 8584 new DynamicByteArrayOutputStream(lce.getLogBuffer()); 8585 8586 RecordHandle longColumnHandle = 8591 insertLongColumn( 8592 curPage, lce, Page.INSERT_UNDO_WITH_PURGE); 8593 8594 int overflowFieldLen = 0; 8596 try 8597 { 8598 overflowFieldLen += 8599 appendOverflowFieldHeader( 8600 logBuffer, longColumnHandle); 8601 8602 } 8603 catch (IOException ioe) 8604 { 8605 throw StandardException.newException( 8606 SQLState.DATA_UNEXPECTED_EXCEPTION, ioe); 8607 } 8608 8609 realStartColumn = lce.getNextColumn() + 1; 8613 realSpaceOnPage = lce.getRealSpaceOnPage() - overflowFieldLen; 8614 hitLongColumn = true; 8615 8616 } 8617 8618 } while (hitLongColumn); 8619 8620 8621 int validColumnsSize = 8623 (validColumns == null) ? 0 : validColumns.getLength(); 8624 8625 if (nextColumn != -1) 8626 { 8627 8628 if (SanityManager.DEBUG) 8629 { 8630 8636 if ((nextColumn < startField) || 8637 (rh.hasOverflow() && (nextColumn >= endFieldExclusive))) 8638 { 8639 SanityManager.THROWASSERT( 8640 "nextColumn out of range = " + nextColumn + 8641 " expected between " + 8642 startField + " and " + endFieldExclusive); 8643 } 8644 } 8645 8646 int possibleLastFieldExclusive = endFieldExclusive; 8652 8653 if (!rh.hasOverflow()) 8654 { 8655 if (validColumns == null) 8657 { 8658 if (row.length > possibleLastFieldExclusive) 8659 possibleLastFieldExclusive = row.length; 8660 } 8661 else 8662 { 8663 if (validColumnsSize > possibleLastFieldExclusive) 8664 possibleLastFieldExclusive = validColumnsSize; 8665 } 8666 } 8667 8668 8669 Object [] newRow = 8671 new Object [possibleLastFieldExclusive]; 8672 8673 FormatableBitSet newColumnList = 8674 new FormatableBitSet(possibleLastFieldExclusive); 8675 8676 ByteArrayOutputStream fieldStream = null; 8677 8678 for (int i = nextColumn; i < possibleLastFieldExclusive; i++) 8679 { 8680 if ((validColumns == null) || 8681 (validColumnsSize > i && validColumns.isSet(i))) 8682 { 8683 newColumnList.set(i); 8684 newRow[i] = RowUtil.getColumn(row, validColumns, i); 8686 8687 } 8688 else if (i < endFieldExclusive) 8689 { 8690 newColumnList.set(i); 8691 8692 newRow[i] = savedFields[i - nextColumn]; 8694 } 8695 } 8696 8697 RecordHandle handle = curPage.getRecordHandleAtSlot(slot); 8698 8699 if (rh.hasOverflow()) 8702 { 8703 nextPage = rh.getOverflowPage(); 8706 id = rh.getOverflowId(); 8707 8708 startColumn = 8710 RowUtil.nextColumn( 8711 row, validColumns, endFieldExclusive); 8712 } 8713 else 8714 { 8715 startColumn = -1; 8716 nextPage = 0; 8717 } 8718 8719 8720 if (!rowHasReservedSpace && headRowHandle != null && 8727 curPage != null && !owner.isTemporaryContainer()) 8728 { 8729 rowHasReservedSpace = 8730 curPage.checkRowReservedSpace(slot); 8731 } 8732 8733 8734 8738 8740 BasePage op = 8741 curPage.getOverflowPageForInsert( 8742 slot, 8743 newRow, 8744 newColumnList, 8745 nextColumn); 8746 8747 if (curPage != this) 8749 { 8750 curPage.unlatch(); 8751 curPage = null; 8752 } 8753 8754 byte mode = Page.INSERT_OVERFLOW; 8755 if (nextPage != 0) 8756 mode |= Page.INSERT_FOR_SPLIT; 8757 8758 RecordHandle nextPortionHandle = 8759 nextPage == 0 ? null : 8760 owner.makeRecordHandle(nextPage, id); 8761 8762 RecordHandle portionHandle = 8775 op.insertAllowOverflow( 8776 0, newRow, newColumnList, nextColumn, mode, 100, 8777 nextPortionHandle); 8778 8779 if (curPage == this) 8781 updateOverflowDetails(this, handle, portionHandle); 8782 else 8783 updateOverflowDetails(handle, portionHandle); 8784 op.unlatch(); 8785 } 8786 else 8787 { 8788 8789 if (!rowHasReservedSpace && 8791 headRowHandle != null && 8792 curPage != null && 8793 !owner.isTemporaryContainer()) 8794 { 8795 rowHasReservedSpace = 8796 curPage.checkRowReservedSpace(slot); 8797 } 8798 8799 8800 startColumn = 8802 rh.hasOverflow() ? 8803 RowUtil.nextColumn( 8804 row, validColumns, endFieldExclusive) : -1; 8805 } 8806 8807 if (startColumn == -1) { 8809 8810 if ((curPage != this) && (curPage != null)) 8811 curPage.unlatch(); 8812 break; } 8814 } 8815 8816 if (nextPage == -1) 8817 { 8818 if (SanityManager.DEBUG) 8819 { 8820 SanityManager.ASSERT( 8821 curPage != null, 8822 "Current page is null be no overflow information has been obtained"); 8823 } 8824 8825 nextPage = rh.getOverflowPage(); 8828 id = rh.getOverflowId(); 8829 } 8830 8831 if ((curPage != this) && (curPage != null)) 8832 curPage.unlatch(); 8833 8834 curPage = (StoredPage) owner.getPage(nextPage); 8836 8837 if (SanityManager.DEBUG) 8838 { 8839 SanityManager.ASSERT( 8840 curPage.isOverflowPage(), 8841 "following row chain gets a non-overflow page"); 8842 } 8843 8844 slot = curPage.findRecordById(id, FIRST_SLOT_NUMBER); 8845 } 8846 8847 if (rowHasReservedSpace) 8850 { 8851 RawTransaction rxact = (RawTransaction)owner.getTransaction(); 8852 8853 ReclaimSpace work = 8854 new ReclaimSpace(ReclaimSpace.ROW_RESERVE, 8855 headRowHandle, 8856 rxact.getDataFactory(), true); 8857 rxact.addPostCommitWork(work); 8858 } 8859 } 8860 8861 8865 private boolean checkRowReservedSpace(int slot) throws StandardException 8866 { 8867 boolean rowHasReservedSpace = false; 8868 try { 8869 int shrinkage = getReservedCount(slot); 8870 8871 int reclaimThreshold = RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT; 8875 8876 if (shrinkage > reclaimThreshold) { 8877 int totalSpace = getRecordPortionLength(slot) + shrinkage; 8878 8879 if (isOverflowPage()) { 8880 if (totalSpace > 8881 RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT+reclaimThreshold) 8882 rowHasReservedSpace = true; 8883 8884 } else { 8887 if (totalSpace > (minimumRecordSize + 8889 RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT)) 8890 rowHasReservedSpace = true; 8891 8892 } 8895 } 8896 } catch (IOException ioe) { 8897 throw StandardException.newException( 8898 SQLState.DATA_UNEXPECTED_EXCEPTION, ioe); 8899 } 8900 8901 return rowHasReservedSpace; 8902 } 8903 8904 8908 protected void compactRecord(RawTransaction t, int slot, int id) 8909 throws StandardException 8910 { 8911 if (isOverflowPage() == false) { 8915 StoredRecordHeader recordHeader = getHeaderAtSlot(slot); 8916 8917 while (recordHeader.hasOverflow()) { 8918 StoredPage nextPageInRowChain = 8919 getOverflowPage(recordHeader.getOverflowPage()); 8920 8921 if (SanityManager.DEBUG) 8922 SanityManager.ASSERT(nextPageInRowChain != null); 8923 8924 try { 8925 int nextId = recordHeader.getOverflowId(); 8926 int nextSlot = getOverflowSlot(nextPageInRowChain, recordHeader); 8927 8928 nextPageInRowChain.compactRecord(t, nextSlot, nextId); 8929 8930 recordHeader = nextPageInRowChain.getHeaderAtSlot(nextSlot); 8932 } finally { 8933 nextPageInRowChain.unlatch(); 8934 } 8935 } 8936 } 8937 8938 int reclaimThreshold = RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT; 8942 try 8943 { 8944 int reserve = getReservedCount(slot); 8945 if (reserve > reclaimThreshold) { 8946 int recordLength = getRecordPortionLength(slot); 8947 int correctReservedSpace = reserve; 8948 8949 if (isOverflowPage()) { 8950 if ((reserve + recordLength) > 8951 (RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT+reclaimThreshold)) 8952 { 8953 if (recordLength >= RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT) 8955 correctReservedSpace = 0; 8956 else correctReservedSpace = 8958 RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT - recordLength; 8959 } 8960 } else { 8961 if ((reserve + recordLength) > 8963 (minimumRecordSize+reclaimThreshold)) { 8964 if (recordLength >= minimumRecordSize) 8966 correctReservedSpace = 0; 8967 else 8968 correctReservedSpace = minimumRecordSize - recordLength; 8969 } 8970 } 8971 8972 if (SanityManager.DEBUG) 8973 { 8974 SanityManager.ASSERT(correctReservedSpace <= reserve, 8975 "correct reserve > reserve"); 8976 } 8977 8978 if (correctReservedSpace < reserve) { 8980 owner.getActionSet(). 8981 actionShrinkReservedSpace(t, this, slot, id, 8982 correctReservedSpace, reserve); 8983 } 8984 } 8985 } catch (IOException ioe) { 8986 throw StandardException.newException( 8987 SQLState.DATA_UNEXPECTED_EXCEPTION, ioe); 8988 } 8989 } 8990} 8991 8992 | Popular Tags |