SQLState.DATA_CONTAINER_READ_ONLY);
}
// Handle of the first portion of the chain
RecordHandle headHandle = null;
RecordHandle handleToUpdate = null;
RawTransaction t = curPage.owner.getTransaction();
for (;;) {
if (SanityManager.DEBUG) {
SanityManager.ASSERT(curPage.isLatched());
}
if (!curPage.allowInsert())
return null;
// 'this' is the head page
if (curPage != this)
slot = curPage.recordCount;
boolean isLongColumns = false;
int realStartColumn = -1;
int realSpaceOnPage = -1;
DynamicByteArrayOutputStream logBuffer = null;
// allocate new record id and handle
int recordId = curPage.newRecordIdAndBump();
RecordHandle handle =
new RecordId(curPage.getPageId(), recordId, slot);
if (curPage == this) {
// Lock the row, if it is the very first portion of the record.
if (handleToUpdate == null) {
while (!owner.getLockingPolicy().lockRecordForWrite(
t, handle,
true /* lock is for insert */,
false /* don't wait for grant */)) {
// loop until we get a new record id we can get a lock
// on. If we can't get the lock without waiting then
// assume the record id is owned by another xact. The
// current heap overflow algorithm makes this likely,
// as it first try's to insert a row telling raw store
// to fail if it doesn't fit on the page getting a lock
// on an id that never makes it to disk. The
// inserting transaction will hold a lock on this
// "unused" record id until it commits. The page can
// leave the cache at this point, and the inserting
// transaction has not dirtied the page (it failed
// after getting the lock but before logging anything),
// another inserting transaction will then get the
// same id as the previous inserter - thus the loop on
// lock waits.
//
// The lock we request indicates that this is a lock
// for insert, which the locking policy may use to
// perform locking concurrency optimizations.
// allocate new record id and handle
recordId = curPage.newRecordIdAndBump();
handle =
new RecordId(curPage.getPageId(), recordId, slot);
}
}
headHandle = handle;
}
do {
// do this loop at least once. If we caught a long Column,
// then, we redo the insert with saved logBuffer.
try {
startColumn =
owner.getActionSet().actionInsert(
t, curPage, slot, recordId,
row, validColumns, (LogicalUndo) null,
insertFlag, startColumn, false,
realStartColumn, logBuffer, realSpaceOnPage,
overflowThreshold);
isLongColumns = false;
} catch (LongColumnException lce) {
// we caught a long column exception
// three things should happen here:
// 1. insert the long column into overflow pages.
// 2. append the overflow field header in the main chain.
// 3. continue the insert in the main data chain.
logBuffer = new DynamicByteArrayOutputStream(lce.getLogBuffer());
// step 1: insert the long column ... use the same
// insertFlag as the rest of the row.
RecordHandle longColumnHandle =
insertLongColumn(curPage, lce, insertFlag);
// step 2: append the overflow field header to the log buffer
int overflowFieldLen = 0;
try {