/*

   Derby - Class org.apache.derbyTesting.unitTests.store.T_RawStoreFactory

   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

 */

package org.apache.derbyTesting.unitTests.store;

import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
import org.apache.derby.iapi.store.raw.*;

// impl imports are the preferred way to create unit tests.
import org.apache.derbyTesting.unitTests.harness.T_MultiThreadedIterations;
import org.apache.derbyTesting.unitTests.harness.T_Fail;

import org.apache.derby.iapi.services.context.ContextService;
import org.apache.derby.iapi.services.context.ContextManager;
import org.apache.derby.iapi.services.locks.*;
import org.apache.derby.iapi.services.monitor.ModuleFactory;
import org.apache.derby.iapi.services.monitor.Monitor;
import org.apache.derby.shared.common.sanity.SanityManager;
import org.apache.derby.iapi.services.uuid.UUIDFactory;
import org.apache.derby.catalog.UUID;
import org.apache.derby.iapi.db.Database;
import org.apache.derby.iapi.services.property.PropertyUtil;
import org.apache.derby.shared.common.error.ExceptionSeverity;
import org.apache.derby.shared.common.error.StandardException;

import org.apache.derby.iapi.store.access.*;
import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;

import org.apache.derby.iapi.store.raw.xact.RawTransaction;
import org.apache.derby.iapi.store.raw.data.RawContainerHandle;
import org.apache.derby.iapi.store.raw.log.LogInstant;

import org.apache.derby.iapi.types.DataValueDescriptor;

// impl a logInstant implemented as log counter to test truncateLWMs
import org.apache.derby.impl.store.raw.log.LogCounter;

import org.apache.derby.iapi.types.SQLChar;

import org.apache.derby.shared.common.reference.Property;

import org.apache.derby.iapi.services.io.FormatableBitSet;

import java.io.*;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.AccessController;
import java.util.Properties;

/**
	A protocol unit test for the RawStore interface.
*/

public class T_RawStoreFactory extends T_MultiThreadedIterations {


	static protected final String REC_001 = "McLaren";
	static protected final String REC_002 = "Ferrari";
	static protected final String REC_003 = "Benetton";
	static protected final String REC_004 = "Prost";
	static protected final String REC_005 = "Tyrell";
	static protected final String REC_006 = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
	static protected final String REC_007 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
	static protected final String REC_008 = "z";
	static protected final String REC_009 = "nanonano";
	static protected final String REC_010 = "fuzzbutt";
	static protected final String REC_011 = "mork";
	static protected final String REC_012 = "orson";
	static protected final String REC_013 = "mindy";
	static protected final String REC_014 = "thomas";
	static protected final String REC_015 = "henry";
	static protected final String REC_016 = "gordon";
	static protected final String REC_017 = "mavis";
	static protected final String REC_018 = "fatcontroller";
	static protected final String REC_UNDO = "Lotus";
	static protected final String REC_NULL = "NULL";

	static final FormatableBitSet BS_COL_0 = new FormatableBitSet(1);

	static protected final String SP1 = "savepoint1";
	static protected final String SP2 = "savepoint2";

	private static final String TEST_ROLLBACK_OFF = "derby.RawStore.RollbackTestOff";

	private static boolean testRollbackProperty;// initialize in start
	static protected boolean testRollback; // each thread has its own test rollback value

	static protected RawStoreFactory	factory;
	static protected LockFactory  lf;
	static protected ContextService contextService;

	static protected UUIDFactory uuidfactory;
	protected  T_Util t_util;
	protected int    openMode;	// mode flags used in all open containers.
	protected boolean logDataForPurges = true; //used to test non-logged data purges

	public T_RawStoreFactory() {
		super();
		BS_COL_0.set(0);
	}

	/**
	  @exception StandardException cannot startup the context service
	*/
	public void boot(boolean create, Properties startParams)
		 throws StandardException
	{
		super.boot(create, startParams);
		contextService = getContextService();
	}

	/*
	** Methods required by T_Generic
	*/

	protected String getModuleToTestProtocolName() {
		return RawStoreFactory.MODULE;
	}

	/**
		Set up test

		@exception T_Fail Unexpected behaviour from the API
	 */
	protected void setupTest() throws T_Fail {
		
		String rollbackOff = PropertyUtil.getSystemProperty(TEST_ROLLBACK_OFF);
		testRollback = !Boolean.valueOf(rollbackOff).booleanValue();

		testRollbackProperty = testRollback; // testRollbackProperty never changes

		// don't automatic boot this service if it gets left around
		if (startParams == null) {
			startParams = new Properties();
		}
		startParams.put(Property.NO_AUTO_BOOT, Boolean.TRUE.toString());
		// remove the service directory to ensure a clean run
		startParams.put(Property.DELETE_ON_CREATE, Boolean.TRUE.toString());

		// see if we are testing encryption
		startParams = T_Util.setEncryptionParam(startParams);

		try {

			factory = (RawStoreFactory) createPersistentService(getModuleToTestProtocolName(),
								getTestService(), startParams);

			if (factory == null) {
				throw T_Fail.testFailMsg(getModuleToTestProtocolName() + " service not started.");
			}

			lf = factory.getLockFactory();
			if (lf == null) {
				throw T_Fail.testFailMsg("LockFactory.MODULE not found");
			}

			uuidfactory = getMonitor().getUUIDFactory();

		} catch (StandardException mse) {
			throw T_Fail.exceptionFail(mse);
		}

		REPORT("testRollback=" + testRollback);

		return;
	}

	protected String getTestService()
	{
		return "rawStoreTest";
	}


	/**
	 * T_MultiThreadedIteration method
	 *
	 * @exception T_Fail Unexpected behaviour from the API
	 */
	protected void joinSetupTest() throws T_Fail {

		T_Fail.T_ASSERT(factory != null, "raw store factory not setup ");
		T_Fail.T_ASSERT(lf != null, "Lock factory not setup ");
		T_Fail.T_ASSERT(contextService != null, "Context service not setup ");

		testRollback = testRollbackProperty;

	}

	protected T_MultiThreadedIterations newTestObject() {
		try
		{
			Class<?> thisClass = this.getClass();
			return (T_MultiThreadedIterations)(thisClass.getConstructor().newInstance());
		}
		catch (InstantiationException ie)
		{
			return new T_RawStoreFactory();
		}	
		catch (IllegalAccessException iae)
		{
			return new T_RawStoreFactory();
		}
		catch (NoSuchMethodException iae)
		{
			return new T_RawStoreFactory();
		}
		catch (java.lang.reflect.InvocationTargetException iae)
		{
			return new T_RawStoreFactory();
		}
	}	


	/**
	  run the test

	  @exception T_Fail Unexpected behaviour from the API
	*/
	protected void runTestSet() throws T_Fail {

		// get a utility helper
		t_util = new T_Util(factory, lf, contextService);

		ContextManager cm1 = contextService.newContextManager();
		contextService.setCurrentContextManager(cm1);

		try {


			// Run the tests with data not logged for purges.
			REPORT("Running tests with no data logged  for purges");
			openMode = 0;		// logged by default
			runPurgeWithNoDataLoggesTests();

			// Run the tests in normal logged mode
			REPORT("Running tests with logging requested");
			openMode = 0;		// logged by default
			runEachTest();

			
			// run the tests on temp tables
			REPORT("Running tests for temp tables");
			testRollback = false;	// obviously, we can't test rollback if we are not logging
			runTempTests();

			// Run the tests in unlogged mode
			REPORT("Running tests in unlogged mode");
			openMode = ContainerHandle.MODE_UNLOGGED | ContainerHandle.MODE_CREATE_UNLOGGED;
			testRollback = false;	// obviously, we can't test rollback if we are not logging
			runEachTest();

			// if more runs are added here then you probably want to reset testRollback to
			// its initial value, or add the runs before the unlogged mode.

		} catch (StandardException se) {

            //Assume database is not active. DERBY-4856 thread dump
            cm1.cleanupOnError(se, false);
			throw T_Fail.exceptionFail(se);
		}
		finally {
			contextService.resetCurrentContextManager(cm1);
		}
	}

	protected void runEachTest() throws T_Fail, StandardException {

		t_util.setOpenMode(openMode);

		// Transaction tests
 		T000();
		T001();
		T002();
		T003();
		T004();
		T005();
		T006();
		T007();
		T008();
		T009();
		T010();
		T011();
        T012();

		// ContainerHandle tests
		C010(0);
		C011();
		C012(1);
		C014();
		C200();
		C201(0);
		C201(1);

		// Page tests
		P001(0);
		P002(0);
		P005(0);
		P006();
		P007(0);
		P008(0);
		P009(0);
		P011(0);
		P012(0);
		P013();
		P014();
		P015();
		P016();
		P017();
		P018();
		P019();		// test addPage with preallocation turned on
		P020();		// test createContainer with initialPage set to 10 pages
		P021();		// test preAllocate
		P022();
		P023(0);	// overflowThreshold test
		P024(0);	// test page latching

		// long row tests
		P030(0);
		P031(0);
		P032(0);
		P033(0);
		P034(0);

		P035(0);	// long column test



		//run  the following test because they do lot of checks 
		//on rollbacking when contyainer is unlogged nothing is rolled back
		if((openMode & ContainerHandle.MODE_UNLOGGED) ==  ContainerHandle.MODE_UNLOGGED)
		{
			openMode = 0; //run them as logged for time being
			t_util.setOpenMode(openMode);
		}

 		// reclaiming space from long column and long rows - temp container
		// row space is not reclaimed.
		P036();
		P037();
		P038();
		P039();
		P040();
		P041();
		P042();
		P043();


		P050(); // rollback tests
		P051();
		P053();
		P054();
        P055(0);
        P056(0);


		P061(); // sparse row test

        P071(); // serializable column test

		// update/update partial tests with long rows
		P701(0);
        P702(0);
		P703(0);
		P704(0);
		P705(0);

		P706(0, false);
		P706(0, true);
		P707(0);
		P708(0, false);
		P708(0, true);


		L001();	// large log record test

		// checkpoint test
		CP001();
	}

	protected void runTempTests() throws T_Fail, StandardException {

		REPORT("Thread " + threadNumber + " entering temp tests ");

		openMode = 0;			// logged by default
		t_util.setOpenMode(openMode);	// logged mode should be overriden for temp tables

		// now tests for temporary tables

		C010(ContainerHandle.TEMPORARY_SEGMENT);
		C012(ContainerHandle.TEMPORARY_SEGMENT);
		//P001(ContainerHandle.TEMPORARY_SEGMENT);
		//P002(ContainerHandle.TEMPORARY_SEGMENT);
		P005(ContainerHandle.TEMPORARY_SEGMENT);
		P011(ContainerHandle.TEMPORARY_SEGMENT);
		P012(ContainerHandle.TEMPORARY_SEGMENT);
		P030(ContainerHandle.TEMPORARY_SEGMENT);

		// update/update partial tests with long rows
		P055(ContainerHandle.TEMPORARY_SEGMENT);
		P056(ContainerHandle.TEMPORARY_SEGMENT);

		P701(ContainerHandle.TEMPORARY_SEGMENT);
		P702(ContainerHandle.TEMPORARY_SEGMENT);
		P703(ContainerHandle.TEMPORARY_SEGMENT);
		P704(ContainerHandle.TEMPORARY_SEGMENT);
		P705(ContainerHandle.TEMPORARY_SEGMENT);
		P706(ContainerHandle.TEMPORARY_SEGMENT, false);
		P706(ContainerHandle.TEMPORARY_SEGMENT, true);
		P707(ContainerHandle.TEMPORARY_SEGMENT);

		// tests specific to temp tables

		// checking truncate at commit/rollback works
		TC001();
		TC002(ContainerHandle.MODE_TRUNCATE_ON_COMMIT, true);
		TC002(ContainerHandle.MODE_TRUNCATE_ON_COMMIT, false);
		TC002(0, false);

		// checking an explict drop works ...
		TC003(ContainerHandle.MODE_TRUNCATE_ON_COMMIT, true);
		TC003(ContainerHandle.MODE_TRUNCATE_ON_COMMIT, false);
		TC003(0, false);
		TC003(0, true);
		TC003(ContainerHandle.MODE_DROP_ON_COMMIT, true);
		TC003(ContainerHandle.MODE_DROP_ON_COMMIT, false);

		// various combinations of opens ...
		TC004all();

		REPORT("Thread " + threadNumber + " exiting temp tests ");
 	}


	protected void runPurgeWithNoDataLoggesTests() throws T_Fail, StandardException {

		REPORT("Thread " + threadNumber + " entering purges with no data logged tests ");
		logDataForPurges = false;
		P005(0);
		P006();
		P014();
		P036();
		P037();
		P709();
		P710();
		P711();
		REPORT("Thread " + threadNumber + " exiting purge with no data logged tests ");
		logDataForPurges = true;
	}
	/*
	** The tests
	**		Tnnn indicates a test that is mainly testing the Transaction interface
	**		Cnnn indicates a test that is mainly testing the ContainerHandle interface
	**		Pnnn indicates a test that is mainly testing the Page interface
	**
	**	nnn < 200 tends to indicate purely API tests, ie checking methods
	**		are callable and return the right value. This includes negative tests.
	**
	**  nnn >= 200 tends to indicate more involved tests, ie ones that test the
	**			methods actually did something.

	*/

	/**
		T000 - ensure a transaction starts out idle.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void T000() throws T_Fail, StandardException {

		Transaction t1 = t_util.t_startTransaction();

		t1.close();


		t1 = t_util.t_startInternalTransaction();

		t1.close();

		t1 = t_util.t_startTransaction();
		Transaction ti = t_util.t_startInternalTransaction();

		ti.close();

		t1.close();

		PASS("T000");
	}

	/**
		T001 - start and commit an empty transaction.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void T001() throws T_Fail, StandardException {

		Transaction t1 = t_util.t_startTransaction();

		t_util.t_commit(t1);

		t1.close();

		PASS("T001");
	}

	/**
		T002 - start and abort an empty transaction.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void T002() throws T_Fail, StandardException {

		Transaction t1 = t_util.t_startTransaction();

		t_util.t_abort(t1);

		t1.close();

		PASS("T002");
	}

	/**
		T003 - start and commit an empty transaction and then ensure
		that the transaction remains open for another commit.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void T003() throws T_Fail, StandardException {

		Transaction t1 = t_util.t_startTransaction();

		t_util.t_commit(t1);

		t_util.t_commit(t1);
		t_util.t_abort(t1);

		t1.close();

		PASS("T003");
	}

	/**
		T004 - start and abort an empty transaction and then ensure
		that the transaction remains open for a commit and another abort.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void T004() throws T_Fail, StandardException {

		Transaction t1 = t_util.t_startTransaction();

		t_util.t_abort(t1);

		t_util.t_commit(t1);

		t_util.t_abort(t1);

		t1.close();

		PASS("T004");
	}


	/**
		T005 check transaction identifiers on idle transactions.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/
	protected void T005() throws T_Fail, StandardException {

		Transaction t1 = t_util.t_startTransaction();

        // local transactions do not have global id's
		GlobalTransactionId id1 = t1.getGlobalId();
		if (id1 != null)
			throw T_Fail.testFailMsg("null not returned from local Transaction.getId()");
        t1.close();

        byte[] global_id = 
            { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
             10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
             20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
             30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
             40, 41, 42, 44, 44, 45, 46, 47, 48, 49,
             50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
             60, 61, 62, 63};
        byte[] branch_id = 
            { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
             10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
             20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
             30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
             40, 41, 42, 44, 44, 45, 46, 47, 48, 49,
             50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
             60, 61, 62, 63};

        t1 = t_util.t_startGlobalTransaction(42, global_id, branch_id);

        id1 = t1.getGlobalId();

		if (!id1.equals(id1))
			throw T_Fail.testFailMsg("TransactionId does not compare equal to itself");

		if (!id1.equals(t1.getGlobalId()))
			throw T_Fail.testFailMsg("TransactionId has changed without any activity on Transaction");

		if (id1.equals(this))
			throw T_Fail.testFailMsg("TransactionId compared equal to an non-transaction id object");

		t1.close();
		t1 = null;

        // change the branch_id for the second global xact.
        branch_id[63] = 82;
		Transaction t2 = 
            t_util.t_startGlobalTransaction(42, global_id, branch_id);

		GlobalTransactionId id2 = t2.getGlobalId();
		if (id2 == null)
			throw T_Fail.testFailMsg("null returned from Transaction.getId()");

		if (id1.equals(id2))
			throw T_Fail.testFailMsg("TransactionId's returned equal from different transactions");
		if (id2.equals(id1))
			throw T_Fail.testFailMsg("TransactionId's returned equal from different transactions");

		t2.close();

		PASS("T005");
	}

	/**
		T006 - savepoint basic API testing

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void T006() throws T_Fail, StandardException {	

		Transaction t1 = t_util.t_startTransaction();

		// check a random savepoint name is not accepted
		t_util.t_checkInvalidSavePoint(t1, "sdfjsdfg");


		t1.setSavePoint(SP1, null);

		t1.rollbackToSavePoint(SP1, null);	// leaves savepoint around
		t1.rollbackToSavePoint(SP1, null);	// therefore this should work

		t1.releaseSavePoint(SP1, null);

		// SP1 should no longer exist
		t_util.t_checkInvalidSavePoint(t1, SP1);

		// should be able to re-use it ...
		t1.setSavePoint(SP1, null);
		t1.rollbackToSavePoint(SP1, null);	// leaves savepoint around
		t1.rollbackToSavePoint(SP1, null);	// therefore this should work

		t1.releaseSavePoint(SP1, null);
		t_util.t_checkInvalidSavePoint(t1, SP1);

		t_util.t_commit(t1);
		t1.close();

		PASS("T006");
	}


	/**
		T007 - savepoint nesting testing

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void T007() throws T_Fail, StandardException {	

		Transaction t1 = t_util.t_startTransaction();
		int position = 0;

		/*
		** Push two save points and release the first, both should disappear
		*/
		t1.setSavePoint(SP1, null);
		t1.setSavePoint(SP2, null);

		position = t1.releaseSavePoint(SP1, null);
		if (position  != 0)
			throw T_Fail.testFailMsg("Save Point Position in the stack isincorrect:"+
									 position);


		// SP1 and SP2 should no longer exist
		t_util.t_checkInvalidSavePoint(t1, SP1);
		t_util.t_checkInvalidSavePoint(t1, SP2);

		/*
		** Push two save points and remove the second, first should remain
		*/
		t1.setSavePoint(SP1, null);
		t1.setSavePoint(SP2, null);

		t1.rollbackToSavePoint(SP2, null);	// leaves savepoint around
		position = t1.rollbackToSavePoint(SP2, null);	// therefore this should work
		
		if (position  != 2)
			throw T_Fail.testFailMsg("Save Point Position in the stack isincorrect:"+
									 position);



		position = t1.releaseSavePoint(SP2, null);
		if (position  != 1)
			throw T_Fail.testFailMsg("Save Point Position in the stack is incorrect:"+
									 position);


		t_util.t_checkInvalidSavePoint(t1, SP2);

		t1.rollbackToSavePoint(SP1, null);	// this is the main test

		t1.releaseSavePoint(SP1, null);
		t_util.t_checkInvalidSavePoint(t1, SP1);

		/*
		** Push two save points and rollback to the first, the second should disappear
		*/
		t1.setSavePoint(SP1, null);
		t1.setSavePoint(SP2, null);

		position = t1.rollbackToSavePoint(SP1, null);	// leaves SP1, removes SP2
		if (position  != 1)
			throw T_Fail.testFailMsg("Save Point Position in the stack is incorrect:"+
												 position);

		
		t_util.t_checkInvalidSavePoint(t1, SP2);
		t1.rollbackToSavePoint(SP1, null);

		t1.releaseSavePoint(SP1, null);

		t_util.t_commit(t1);
		t1.close();

		PASS("T007");
	}

	/**
		T008 - savepoint  testing, ensure save points disappear at commit or abort.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void T008() throws T_Fail, StandardException {	

		Transaction t1 = t_util.t_startTransaction();
		int position1 = 0;
		int position2 = 0;

		position1 = t1.setSavePoint(SP1, null);
		position2 = t1.setSavePoint(SP2, null);

		if (position1 != 1 && position2 != 2)
			throw T_Fail.testFailMsg("Save Point Position in the Stack seeme to wrong");

		t1.commit();

		t_util.t_checkInvalidSavePoint(t1, SP1);
		t_util.t_checkInvalidSavePoint(t1, SP2);

		position1 = t1.setSavePoint(SP1, null);
		position2 = t1.setSavePoint(SP2, null);
		
		if (position1 != 1 && position2 != 2)
			throw T_Fail.testFailMsg("Save Point Position in the Stack seeme to wrong");

		t1.abort();
		position1 = t1.setSavePoint(SP1, null);
		position2 = t1.setSavePoint(SP2, null);
		if (position1 != 1 && position2 != 2)
			throw T_Fail.testFailMsg("Save Point Position in the Stack seeme to wrong");
		t1.abort();
		t_util.t_checkInvalidSavePoint(t1, SP1);
		t_util.t_checkInvalidSavePoint(t1, SP2);

		t1.close();

		PASS("T008");
	}


	/**
		T009 - add a container and remove it within the same transaction.
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/

	protected void T009() throws StandardException, T_Fail {
		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, 0, 4096);
		t_util.t_dropContainer(t, 0, cid);

		ContainerKey id = new ContainerKey(0, cid);
		ContainerHandle ch = t.openContainer(id, ContainerHandle.MODE_READONLY);
		if (ch != null)
			throw T_Fail.testFailMsg("Dropped Container should not open");

		t_util.t_commit(t);

		t.close();

		PASS("T009");
	}

	/**
		T010 - add a container with a default size and remove it within the same transaction.
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/

	protected void T010() throws StandardException, T_Fail {
		Transaction t1 = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t1, 0);

		t_util.t_dropContainer(t1, 0, cid);

		ContainerKey id = new ContainerKey(0, cid);
		ContainerHandle ch = t1.openContainer(id, ContainerHandle.MODE_READONLY);
		if (ch != null)
			throw T_Fail.testFailMsg("Dropped Container should not open");

		t_util.t_commit(t1);

		t1.close();

		PASS("T010");
	}

	/**
		T011 - see that a container remains open over the commit of an open transaction..
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/

	protected void T011() throws StandardException, T_Fail {

		Transaction t = t_util.t_startInternalTransaction();


		long cid = t_util.t_addContainer(t, 0);

		ContainerHandle c;

		c = t_util.t_openContainer(t, 0, cid, true);

		t.commit();

		// container should still be open
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		t.commit();

		// page should still be latched
		if (!page.isLatched())
			throw T_Fail.testFailMsg("page not latched after commit of internal transaction");

		page.unlatch();
		c.close();

		t.commit();

		c = t_util.t_openContainer(t, 0, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// container and page should be closed
		t.abort();
		if (page.isLatched())
			throw T_Fail.testFailMsg("page latched after abort of internal transaction");

		try {
			page = t_util.t_getLastPage(c);
			throw T_Fail.testFailMsg("container open after abort of internal transaction");

		} catch (StandardException te) {
		}

		t_util.t_dropContainer(t, 0, cid);	// cleanup

		t_util.t_commit(t);

		t.close();

		PASS("T011");	
	}

	/**
		Test Xact.makeRecordHandle()

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void T012() throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, 0);

		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		RecordHandle r1, r2;
		RecordHandle new_r1, new_r2;

		T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
		T_RawStoreRow row2 = new T_RawStoreRow(REC_002);

		r1 = t_util.t_insertAtSlot(page, 0, row1);
        new_r1 = c.makeRecordHandle(r1.getPageNumber(), r1.getId());

		t_util.t_checkFetch(page, new_r1, REC_001);

		r2 = t_util.t_insertAtSlot(page, 1, row2);

		if (r2 != null)
        {
            new_r2 = 
                c.makeRecordHandle(r2.getPageNumber(), r2.getId());
			t_util.t_checkFetch(page, r2, REC_002);
        }

		t_util.t_commit(t);
		t.close();

		PASS("T012");

	}

	/**
		C010 - Create a container within a transaction, commit and the re-open
		the container twice.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/
	protected void C010(int segment) throws T_Fail, StandardException {

		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, segment);

		t_util.t_commit(t);
	
		ContainerHandle c1, c2;

		c1 = t_util.t_openContainer(t, segment, cid, true);
		c1 = t_util.t_openContainer(t, segment, cid, true);
		t_util.t_dropContainer(t, segment, cid);	// cleanup


		t_util.t_commit(t);
		t.close();

		PASS("C010");

	}

	/**
		C011 - Create a container withina transaction, commit and the re-open
		the container in update and non-update mode.
		
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/
	protected void C011() throws T_Fail, StandardException {

		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, 0);

		t_util.t_commit(t);
	
		ContainerHandle c1, c2;

		c1 = t_util.t_openContainer(t, 0, cid, false);
		c1 = t_util.t_openContainer(t, 0, cid, true);

		t_util.t_dropContainer(t, 0, cid);	// cleanup

		t_util.t_commit(t);
		t.close();
		PASS("C011");

	}

	/**
		C012 - Drop a container within a transaction, commit, see that it is deleted.
		Drop a container within a transaction, rollback and re-open and see
		that it is not deleted. 

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Standard Derby error policy
	*/
	protected void C012(long segment) throws T_Fail, StandardException {

		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, segment);
		t_util.t_commit(t);

		ContainerHandle c1 = t_util.t_openContainer(t, segment, cid, true);

		t_util.t_dropContainer(t, segment, cid);

		if (testRollback)
		{
			t_util.t_abort(t);			// this should rollback the drop
			c1 = t_util.t_openContainer(t, segment, cid, true);

			REPORT("rollback of drop container tested");

			t_util.t_dropContainer(t, segment, cid);
		}

		t_util.t_commit(t);

		ContainerKey id = new ContainerKey(segment, cid);
		c1 = t.openContainer(id, (ContainerHandle.MODE_FORUPDATE | openMode));	// this should fail
		if (c1 != null)
			throw T_Fail.testFailMsg("Deleted Container should fail to open");

		t_util.t_commit(t);
		t.close();
		PASS("C012");
	}

	/**
		C014 - Open a container for locking only.
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Standard Derby error policy
	*/
	protected void C014() throws T_Fail, StandardException {

		Transaction t = t_util.t_startTransaction();

		ContainerKey id = new ContainerKey(77, 45);
		ContainerHandle c = t.openContainer(id,
			ContainerHandle.MODE_OPEN_FOR_LOCK_ONLY);

		if (c == null)
			throw T_Fail.testFailMsg("open of a container for lock only failed.");

		RecordHandle rh1 = c.makeRecordHandle(23, 456);
		if (rh1 == null)
			throw T_Fail.testFailMsg("makeRecordHandle returned null");
		c.getLockingPolicy().lockRecordForRead(t, c, rh1, true, true);


		RecordHandle rh2 = c.makeRecordHandle(23, 7);
		if (rh2 == null)
			throw T_Fail.testFailMsg("makeRecordHandle returned null");
		c.getLockingPolicy().lockRecordForRead(t, c, rh2, true, false);

		RecordHandle rh3 = c.makeRecordHandle(23, 9);
		c.getLockingPolicy().lockRecordForWrite(t, rh3, false, true);
		if (rh3 == null)
			throw T_Fail.testFailMsg("makeRecordHandle returned null");

		c.getLockingPolicy().unlockRecordAfterRead(t, c, rh2, false, true);

		c.close();

		t.commit();

		t.close();

		PASS("C014");
	}

	/**
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void C200() throws T_Fail, StandardException {

		Transaction t1 = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t1, 0);

		t_util.t_commit(t1);

		ContainerHandle c1;
		Page lastPage;
		RecordHandle rh001, rh002, rh003;
		T_RawStoreRow row;
	
		REPORT("see if the container can be opened again");
		c1 = t_util.t_openContainer(t1, 0, cid, false);

		c1.close();
		t_util.t_commit(t1);

		REPORT("insert a record into the container.");

		c1 = t_util.t_openContainer(t1, 0, cid, true);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Could get container's last page");

		if (lastPage.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
			throw T_Fail.testFailMsg("Initial page must be " + ContainerHandle.FIRST_PAGE_NUMBER + ", is " + lastPage.getPageNumber());

		row = new T_RawStoreRow(REC_001);
		if (!lastPage.spaceForInsert())
			throw T_Fail.testFailMsg("No room for record on page");

		rh001 = t_util.t_insert(lastPage, row);
		if (rh001 == null)
			throw T_Fail.testFailMsg("Failed to insert record");

		// see if we can fetch that record
		t_util.t_checkFetch(lastPage, rh001, REC_001);

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);
		c1 = null;


		REPORT("read record just inserted.");

		c1 = t_util.t_openContainer(t1, 0, cid, false);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Could get container's last page");

		t_util.t_checkFetch(lastPage, rh001, REC_001);
		t_util.t_checkFetchFirst(lastPage, REC_001);
		t_util.t_checkFetchLast(lastPage, REC_001);

		t_util.t_commit(t1);
		lastPage = null;
		c1 = null;


		REPORT("insert 2 more records.");

		c1 = t_util.t_openContainer(t1, 0, cid, true);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Could get container's last page");

		if (lastPage.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
			throw T_Fail.testFailMsg("Initial page must be " + ContainerHandle.FIRST_PAGE_NUMBER + ", is " + lastPage.getPageNumber());

		row = new T_RawStoreRow(REC_002);
		if (!lastPage.spaceForInsert())
			throw T_Fail.testFailMsg("No room for record on page");

		if (!lastPage.recordExists(rh001, false))
			throw T_Fail.testFailMsg("Record 001 has vanished");

		//

		// RESOLVE: just insert them for now, order is 002,001,003
		// 001 is already on the page

		rh002 = t_util.t_insertAtSlot(lastPage, 0, row);
		row = new T_RawStoreRow(REC_003);
		rh003 = t_util.t_insert(lastPage, row);
		// Order is 002, 001, 003
	

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);
		c1 = null;
	
		REPORT("checks on all 3 records.");

		c1 = t_util.t_openContainer(t1, 0, cid, false);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Could get container's last page");

		// Order is 002, 001, 003
		t_util.t_checkFetch(lastPage, rh001, REC_001);
		t_util.t_checkFetch(lastPage, rh002, REC_002);
		t_util.t_checkFetch(lastPage, rh003, REC_003);


		t_util.t_checkFetch(lastPage, lastPage.getRecordHandle(rh001.getId()), REC_001);
		t_util.t_checkFetch(lastPage, lastPage.getRecordHandle(rh002.getId()), REC_002);

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);

		REPORT("start deleting.");

		c1 = t_util.t_openContainer(t1, 0, cid, true);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Could get container's last page");

		// Order is 002, 001, 003
		t_util.t_checkFetch(lastPage, rh001, REC_001);
		t_util.t_checkFetch(lastPage, rh002, REC_002);
		t_util.t_checkFetch(lastPage, rh003, REC_003);

		int slot1 = lastPage.getSlotNumber(rh001);
		lastPage.deleteAtSlot(slot1, true, null);
		if (lastPage.fetchFromSlot(
				rh001, slot1, new DataValueDescriptor[0], null, false) != null)
        {
			throw T_Fail.testFailMsg("deleted record is still present");
        }
		// Order is 002,  003
		t_util.t_checkFetch(lastPage, rh002, REC_002);
		t_util.t_checkFetch(lastPage, rh003, REC_003);

		t_util.t_checkFetchNext(lastPage, rh002, REC_003);
		t_util.t_checkFetchPrevious(lastPage, rh003, REC_002);

		int slot2 = lastPage.getSlotNumber(rh002);
		lastPage.deleteAtSlot(slot2, true, null);
		if (lastPage.fetchFromSlot(
				rh002, slot2, new DataValueDescriptor[0], null, false) != null)
        {
			throw T_Fail.testFailMsg("deleted record is still present");
        }

		t_util.t_checkFetch(lastPage, rh003, REC_003);
		t_util.t_checkFetchFirst(lastPage, REC_003);
		t_util.t_checkFetchLast(lastPage, REC_003);

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);

		REPORT("update the remaining record.");

		c1 = t_util.t_openContainer(t1, 0, cid, true);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Could get container's last page");

		// Order is 003
		t_util.t_checkFetch(lastPage, rh003, REC_003);

		T_RawStoreRow urow = new T_RawStoreRow(REC_004);

		int slot3 = lastPage.getSlotNumber(rh003);
		if (lastPage.updateAtSlot(slot3, urow.getRow(), null) == null)
			throw T_Fail.testFailMsg("updateAtSlot returned null");

		// Order is 003
		t_util.t_checkFetch(lastPage, rh003, REC_004);

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);

		t_util.t_dropContainer(t1, 0, cid); // cleanup

		t_util.t_commit(t1);
		t1.close();
		   
		PASS("C200");

	}

	/**
		C201 - Create container with different page size, minimum record size,
		inserting into these containers to check if the variables are set correctly.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void C201(int whatPage) throws T_Fail, StandardException {

		int pageSize = (whatPage == 0 ? 4096 : 32768);

		Transaction t1 = t_util.t_startTransaction();

		REPORT("create container with pageSize " + pageSize + ", spareSpace " + 0 + ", minimumRecordSize " + pageSize/2);
		long cid = t_util.t_addContainer(t1, 0, pageSize, 0, pageSize/2, false);
		
		t_util.t_commit(t1);

		ContainerHandle c1;
		Page lastPage;
		RecordHandle rh001, rh002, rh003;
		T_RawStoreRow row;
	
		REPORT("see if the container can be opened again");
		c1 = t_util.t_openContainer(t1, 0, cid, false);

		c1.close();
		t_util.t_commit(t1);

		REPORT("insert a record into the container.");

		c1 = t_util.t_openContainer(t1, 0, cid, true);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Couldn't get container's last page");

		if (lastPage.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
			throw T_Fail.testFailMsg("Initial page must be " + ContainerHandle.FIRST_PAGE_NUMBER + ", is " + lastPage.getPageNumber());

		row = new T_RawStoreRow(REC_001);
		if (!lastPage.spaceForInsert())
			throw T_Fail.testFailMsg("No room for record on page");

		rh001 = t_util.t_insert(lastPage, row);
		if (rh001 == null)
			throw T_Fail.testFailMsg("Failed to insert record");

		// see if we can fetch that record
		t_util.t_checkFetch(lastPage, rh001, REC_001);

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);
		c1 = null;

		REPORT("read record just inserted.");

		c1 = t_util.t_openContainer(t1, 0, cid, false);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Couldn't get container's last page");

		t_util.t_checkFetch(lastPage, rh001, REC_001);
		t_util.t_checkFetchFirst(lastPage, REC_001);
		t_util.t_checkFetchLast(lastPage, REC_001);

		t_util.t_commit(t1);
		lastPage = null;
		c1 = null;

		// negative testing
		REPORT("try inserting 1 more record, but there should be no room on page for it.");

		c1 = t_util.t_openContainer(t1, 0, cid, true);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Couldn't get container's last page");

		if (lastPage.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
			throw T_Fail.testFailMsg("Initial page must be " + ContainerHandle.FIRST_PAGE_NUMBER + ", is " + lastPage.getPageNumber());

		row = new T_RawStoreRow(REC_002);
		if (lastPage.spaceForInsert())
        {
			throw T_Fail.testFailMsg("Did not get no room for record on page error");
        }

		if (!lastPage.recordExists(rh001, false))
			throw T_Fail.testFailMsg("Record 001 has vanished");

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);
		c1 = null;

		t_util.t_dropContainer(t1, 0, cid); // cleanup
		t_util.t_commit(t1);
		//t1.close();


		//t1 = t_util.t_startTransaction();

		REPORT("create container with pageSize " + pageSize + ", spareSpace " + 0 + ", minimumRecordSize " + pageSize);
		REPORT("this should set minimumRecordSize to the default 100");
		cid = t_util.t_addContainer(t1, 0, pageSize, 0, pageSize, false);
		
		t_util.t_commit(t1);

		REPORT("see if the container can be opened again");
		c1 = t_util.t_openContainer(t1, 0, cid, false);

		c1.close();
		t_util.t_commit(t1);

		REPORT("insert a record into the container.");

		c1 = t_util.t_openContainer(t1, 0, cid, true);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Couldn't get container's last page");

		if (lastPage.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
			throw T_Fail.testFailMsg("Initial page must be " + ContainerHandle.FIRST_PAGE_NUMBER + ", is " + lastPage.getPageNumber());

		row = new T_RawStoreRow(REC_001);
		if (!lastPage.spaceForInsert())
			throw T_Fail.testFailMsg("No room for record on page");

		rh001 = t_util.t_insert(lastPage, row);
		if (rh001 == null)
			throw T_Fail.testFailMsg("Failed to insert record");

		// see if we can fetch that record
		t_util.t_checkFetch(lastPage, rh001, REC_001);

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);
		c1 = null;

		REPORT("read record just inserted.");

		c1 = t_util.t_openContainer(t1, 0, cid, false);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Couldn't get container's last page");

		t_util.t_checkFetch(lastPage, rh001, REC_001);
		t_util.t_checkFetchFirst(lastPage, REC_001);
		t_util.t_checkFetchLast(lastPage, REC_001);

		t_util.t_commit(t1);
		lastPage = null;
		c1 = null;

		REPORT("insert 2 more records.");

		c1 = t_util.t_openContainer(t1, 0, cid, true);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Could get container's last page");

		if (lastPage.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
			throw T_Fail.testFailMsg("Initial page must be " + ContainerHandle.FIRST_PAGE_NUMBER + ", is " + lastPage.getPageNumber());

		row = new T_RawStoreRow(REC_002);
		if (!lastPage.spaceForInsert())
			throw T_Fail.testFailMsg("No room for record on page");

		if (!lastPage.recordExists(rh001, false))
			throw T_Fail.testFailMsg("Record 001 has vanished");

		rh002 = t_util.t_insertAtSlot(lastPage, 0, row);
		row = new T_RawStoreRow(REC_003);
		rh003 = t_util.t_insert(lastPage, row);

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);
		c1 = null;
	
		REPORT("checks on all 3 records.");

		c1 = t_util.t_openContainer(t1, 0, cid, false);

		lastPage = t_util.t_getLastPage(c1);
		if (lastPage == null)
			throw T_Fail.testFailMsg("Could get container's last page");

		// Order is 002, 001, 003
		t_util.t_checkFetch(lastPage, rh001, REC_001);
		t_util.t_checkFetch(lastPage, rh002, REC_002);
		t_util.t_checkFetch(lastPage, rh003, REC_003);


		t_util.t_checkFetch(lastPage, lastPage.getRecordHandle(rh001.getId()), REC_001);
		t_util.t_checkFetch(lastPage, lastPage.getRecordHandle(rh002.getId()), REC_002);

		lastPage.unlatch();
		lastPage = null;

		t_util.t_commit(t1);

		c1 = null;

		// clean ip
		t_util.t_dropContainer(t1, 0, cid);
		t_util.t_commit(t1);
		t1.close();

		PASS("C201 - " + whatPage);

	}

	/**
		Page tests
	 */
	 /**
	    Create a container, ensure it has one page with no records. Then test
		all the things we can do with an empty page opened read-only in the container.
		Then add a new page, ensure it has the correct page number and is empty.
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P001(long segment) throws T_Fail, StandardException {

		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, segment);

		t_util.t_commit(t);

		// Get the first page & check the record counts are zero
		ContainerHandle c = t_util.t_openContainer(t, segment, cid, false);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		t_util.t_checkEmptyPage(page);

		if (Page.FIRST_SLOT_NUMBER != 0)
			throw T_Fail.testFailMsg("Page.FIRST_SLOT_NUMBER must be 0, is " + Page.FIRST_SLOT_NUMBER);

		page.unlatch();
		page = null;

		// get the last page and check it is the first page
		page = t_util.t_getLastPage(c);

		t_util.t_checkPageNumber(page, ContainerHandle.FIRST_PAGE_NUMBER);
	
		t_util.t_checkEmptyPage(page);

		t_util.t_commit(t);

		// t_util.t_addPage checks that the page is empty.
		c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_addPage(c);

		t_util.t_checkPageNumber(page, ContainerHandle.FIRST_PAGE_NUMBER + 1);
		page.unlatch();

		page = t_util.t_addPage(c);
		t_util.t_checkPageNumber(page, ContainerHandle.FIRST_PAGE_NUMBER + 2);
		page.unlatch();

		t_util.t_commit(t);

		c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_updateSlotOutOfRange(page, 0);
		t_util.t_updateSlotOutOfRange(page, -1);
		t_util.t_updateSlotOutOfRange(page, 1);


		t_util.t_dropContainer(t, segment, cid);	// cleanup
		t_util.t_commit(t);

		// RESOLVE drop container

		t.close();

		PASS("P001");
	}

	/**
		Insert rows on the first page until the page is full, then add a page
		and repeat the test (for a total of three pages with full rows).
		Fetch the rows back by handle and slot methods.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P002(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		RecordHandle rh;
		T_RawStoreRow row;
		int	recordCount[] = {0,0,0};

		for (int i = 0; i < 3;) {
			row = new T_RawStoreRow(REC_001 + i + "X" + recordCount[i]);

			boolean spaceThere = page.spaceForInsert();

			rh = t_util.t_insert(page, row);

			if (rh != null) {
				recordCount[i]++;
				if (!spaceThere)
					REPORT("record inserted after spaceForInsert() returned false, count is " + recordCount[i]);
			} else {
				if (spaceThere)
					REPORT("record insert failed after spaceForInsert() returned true, count is " + recordCount[i]);
			}

			t_util.t_checkRecordCount(page, recordCount[i], recordCount[i]);

			if (rh != null)
				continue;

			page.unlatch();
			page = null;

			if (++i < 3) {
				page = t_util.t_addPage(c);
				t_util.t_checkEmptyPage(page);
			}
		}
		t_util.t_commit(t);

		for (int i = 0; i < 3; i++) {
			REPORT("RecordCount on page " + i + "=" + recordCount[i]);
		}

		// now check that we read the same number of records back
		// using the handle interface
		c = t_util.t_openContainer(t, segment, cid, false);

		long pageNumber = ContainerHandle.FIRST_PAGE_NUMBER;
		for (int i = 0; i < 3; i++, pageNumber++) {
			page = t_util.t_getPage(c, pageNumber);
			t_util.t_checkRecordCount(page, recordCount[i], recordCount[i]);
			rh = t_util.t_checkFetchFirst(page, REC_001 + i + "X" + 0);
			for (int j = 1; j < recordCount[i]; j++)
				rh = t_util.t_checkFetchNext(page, rh, REC_001 + i + "X" + j);

            try
            {
                rh = page.fetchFromSlot(
                        null, 
                        page.getSlotNumber(rh) + 1, 
                        new DataValueDescriptor[0], 
                        (FetchDescriptor) null, 
                        false);

				throw T_Fail.testFailMsg(
                        "reading more rows on page than were written");
            }
            catch (StandardException se)
            {
                // expected error.
            }

			rh = t_util.t_checkFetchLast(page, REC_001 + i + "X" + (recordCount[i] - 1));
			for (int j = recordCount[i] - 2; j >= 0; j--)
				rh = t_util.t_checkFetchPrevious(page, rh, REC_001 + i + "X" + j);

			page.unlatch();
			page = null;
		}
		t_util.t_commit(t);

		// now check that we read the same number of records back
		// using the slot interface
		c = t_util.t_openContainer(t, segment, cid, false);

		pageNumber = ContainerHandle.FIRST_PAGE_NUMBER;
		for (int i = 0; i < 3; i++, pageNumber++) {
			page = t_util.t_getPage(c, pageNumber);
		
			for (int j = 0; j < recordCount[i]; j++)
				t_util.t_checkFetchBySlot(page, j, REC_001 + i + "X" + j,
										false, false);

			t_util.t_readOnlySlotOutOfRange(page, recordCount[i]);

			page.unlatch();
			page = null;
		}

		t_util.t_dropContainer(t, segment, cid);	// cleanup

		t_util.t_commit(t);

		t.close();

		PASS("P002");
	}

	/* test repeated insert */
	protected void P005(long segment) throws StandardException, T_Fail 
	{
		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page1 = t_util.t_getLastPage(c);
	
		T_RawStoreRow row0 = new T_RawStoreRow
			("long row xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx long row ");
		T_RawStoreRow row1 = new T_RawStoreRow
			("medium row yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy medium row");

		t_util.t_insertAtSlot(page1, 0, row0);

		int i = 0;
		while (page1.spaceForInsert())
		{
			if (t_util.t_insertAtSlot(page1, 1, row1) == null)
				break;
			i++;
		}

		int count1 = page1.recordCount();

		Page page2 = t_util.t_addPage(c);
		t_util.t_insertAtSlot(page2, 0, row0);

		i = 1;
		while (page2.spaceForInsert())
		{
			if (t_util.t_insertAtSlot(page2, i++, row1) == null)
				break;
		}

		int count2 = page2.recordCount();

		// now purge them all and start over
		page1.purgeAtSlot(1, page1.recordCount()-1, logDataForPurges);
		page2.purgeAtSlot(1, page2.recordCount()-1, logDataForPurges);
		if (page1.recordCount() != 1)
			throw T_Fail.testFailMsg("purge did not clean up page");

		if (page2.recordCount() != 1)
			throw T_Fail.testFailMsg("purge did not clean up page");

		i = 0;
		while(page1.spaceForInsert())
		{
			if (t_util.t_insertAtSlot(page1, 1, row1) == null)
				return;
			i++;
		}

		if (page1.recordCount() != count1)
			throw T_Fail.testFailMsg("cannot insert back same number of rows we purged");


		i = 1;
		while(page2.spaceForInsert())
		{
			if (t_util.t_insertAtSlot(page2, i++, row1) == null)
				break;
		}

		if (page2.recordCount() != count2)
			throw T_Fail.testFailMsg("cannot insert back same number of rows we purged");

		page1.unlatch();
		page2.unlatch();	

		t_util.t_dropContainer(t, segment, cid);	// cleanup

		t_util.t_commit(t);
		t.close();

		PASS("P005");
	}

	/*
		P006

		test page time stamp - make sure all operation changes page time stamp
	*/
	protected void P006() throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		PageTimeStamp ts;

		long cid = t_util.t_addContainer(t, 0);
		t_util.t_commit(t);

		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
		Page page1 = t_util.t_getLastPage(c);
		
		ts = page1.currentTimeStamp();
		if (ts != null && !page1.equalTimeStamp(ts))
			throw T_Fail.testFailMsg("page returns non-null time stamp which is not equal to its current time stamp");

		T_RawStoreRow row = new T_RawStoreRow(REC_001);
		RecordHandle rh = t_util.t_insert(page1, row);

		if (page1.equalTimeStamp(ts))
			throw T_Fail.testFailMsg("timestamp on page not changed after insert operation");
		page1.setTimeStamp(ts);
		if (ts != null && !page1.equalTimeStamp(ts))
			throw T_Fail.testFailMsg("page returns non-null time stamp which is not equal to its current time stamp");

		// failed update should not change time stamp
		t_util.t_updateSlotOutOfRange(page1, 3);
		if (ts != null && !page1.equalTimeStamp(ts))
			throw T_Fail.testFailMsg("failed pdate should not change time stamp");

		T_RawStoreRow row2 = new T_RawStoreRow(REC_002);
		int slot2 = page1.getSlotNumber(rh);
		page1.updateAtSlot(slot2, row2.getRow(), null);
		if (page1.equalTimeStamp(ts))
			throw T_Fail.testFailMsg("timestamp on page not changed after update operation");

		page1.setTimeStamp(ts);

		T_RawStoreRow upd1 = new T_RawStoreRow(REC_003);
		int slot = page1.getSlotNumber(rh);
		page1.updateAtSlot(slot, upd1.getRow(), BS_COL_0);
		if (page1.equalTimeStamp(ts))
			throw T_Fail.testFailMsg("timestamp on page not changed after update field operation");

		page1.setTimeStamp(ts);

		page1.deleteAtSlot(slot, true, null);
		if (page1.equalTimeStamp(ts))
			throw T_Fail.testFailMsg("timestamp on page not changed after delete operation");

		page1.setTimeStamp(ts);
		
		page1.purgeAtSlot(0, 1, logDataForPurges);
		if (page1.equalTimeStamp(ts))
			throw T_Fail.testFailMsg("timestamp on page not changed after delete operation");

		page1.setTimeStamp(ts);
		page1.unlatch();

		if (testRollback)
		{
			t_util.t_abort(t);
			c = t_util.t_openContainer(t, 0, cid, true);
			page1 = t_util.t_getLastPage(c);

			if (page1.equalTimeStamp(ts))
				throw T_Fail.testFailMsg("timestamp on page not changed after rollback");

			page1.setTimeStamp(ts);
		}
		
		Page page2 = c.addPage();
		Page page3 = c.addPage();

		page2.setTimeStamp(ts);

		if (ts != null)
		{
			try 
			{
				if (page3.equalTimeStamp(ts))
					throw T_Fail.testFailMsg("timestamp on 2 different pages should not equate");
			}
			catch (StandardException se)
			{
				// either throw an exception or return false is OK
			}
		}


		t_util.t_dropContainer(t, 0, cid);	// cleanup
		t_util.t_commit(t);
		t.close();

		PASS("P006");

	}

	/**
		P007

		this test exercises repeated updates on a 1K page

		2 rows (with 1 column) will be inserted into the page.
		We expand the row data in slot 0 by 1 byte until the page is completely full,
		and overflows the record to an overflow page.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	  */

	  protected void P007(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		// PART 1:
		// insert two 1-column rows into the page, expand the first row, until it overflows.
		long cid = t_util.t_addContainer(t, segment, 4096, 0, 1, false);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getLastPage(c);
	
		T_RawStoreRow row = new T_RawStoreRow(REC_001); // McLaren
		T_RawStoreRow row2 = new T_RawStoreRow(new String(new char[300])); 

		RecordHandle r1 = t_util.t_insertAtSlot(page, 0, row);
		RecordHandle r2 = t_util.t_insertAtSlot(page, 1, row2);

		// update the row size 1 byte larger, until the page is full
		String rowData = REC_001;
		// 900 is an estimated number, because for 1K page,
		// if you expand your row by 1 byte 900 times, the row will overflow for sure.
		for (int i = 0; i <= 900; i++) {
			t_util.t_checkFetch(page, r1, rowData);

			rowData = rowData + REC_008;	// "z"
			row = new T_RawStoreRow(rowData);
			page.updateAtSlot(0, row.getRow(), (FormatableBitSet) null);
		}

		t_util.t_dropContainer(t, segment, cid);	// cleanup

		// PART 2:
		// insert two 2-column rows into the page,
		// expand the first row by expanding the first column by 300 bytes,
		// and shrinking the second column by 300 bytes.  Update should secceed.
		cid = t_util.t_addContainer(t, segment, 4096, 0, 1, false);
		c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getLastPage(c);
		long pid = page.getPageNumber();

		row = new T_RawStoreRow(2);
		row.setColumn(0, REC_001);	// small column
		row.setColumn(1, new String (new char[400]));	// large column

		r1 = t_util.t_insertAtSlot(page, 0, row);
		r2 = t_util.t_insertAtSlot(page, 1, row2);

		row.setColumn(0, REC_001 + new String (new char[300]));
		row.setColumn(1, new String (new char[100]));

		page.updateAtSlot(0, row.getRow(), (FormatableBitSet) null);

		Page page2 = t_util.t_addPage(c);
		long pid2 = page2.getPageNumber();
		if (pid2 != (pid + 1))
			throw T_Fail.testFailMsg("The update should not have overflowed the record");

		// Now, shrink the first column by 300 bytes, and expand the second column by 300 bytes.
		// the update should also succeed.
		row.setColumn(0, REC_001);
		row.setColumn(1, new String (new char[400]));

		page.updateAtSlot(0, row.getRow(), (FormatableBitSet) null);

		Page page3 = t_util.t_addPage(c);
		long pid3 = page3.getPageNumber();
		if (pid3 != (pid2 + 1))
			throw T_Fail.testFailMsg("The update should not have overflowed the record");

		t_util.t_dropContainer(t, segment, cid);	// cleanup

		t_util.t_commit(t);
		t.close();

		PASS("P007");

	}

	/**
		P008

		this test exercises repeated inserts with small rows on a 1K page

		we will insert as many rows as possible into the page.  Then we reduce the row by 1 byte at a time,
		we will try to insert another smaller row.
		This test also tests spaceForInsert().

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	  */

	protected void P008(long segment) throws StandardException, T_Fail 
	{
		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096, 0, 1, false);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page1 = t_util.t_getLastPage(c);
	
		T_RawStoreRow row = new T_RawStoreRow(REC_001);		// McLaren

		t_util.t_insertAtSlot(page1, 0, row);

		int i = 0;
		while (page1.spaceForInsert(row.getRow(), (FormatableBitSet) null, 100))
		{
			// if it says there is enough room for this row, the insert should succeed.
			if (t_util.t_insertAtSlot(page1, 1, row) == null)
				throw T_Fail.testFailMsg("There is space for this insert.  It shouldn't have failed.  "
					+ "record #" + i);
			i++;
		}

		REPORT(i + " rows inserted.");

		// We got out of the while loop because there is no room for the insert.
		// So, if the insert succeed, then we have a problem.
		if (t_util.t_insertAtSlot(page1, 1, row) != null)
			throw T_Fail.testFailMsg("There is no space for this insert.  It should have failed.");

		// Now, we will try to fill the page with smaller rows.
		String[] s = new String[7];
		s[6] = "McLare";
		s[5] = "McLar";
		s[4] = "McLa";
		s[3] = "McL";
		s[2] = "Mc";
		s[1] = "M";
		s[0] = null;
		// reduce the row by 1 byte
		i = 6;
		boolean notDone = true;
		do
		{
			row = new T_RawStoreRow(s[i]);
			if (page1.spaceForInsert(row.getRow(), (FormatableBitSet) null, 100))
			{
				// If it says there is enough room for the row, then the insert should succed.
				if (t_util.t_insertAtSlot(page1, 1, row) == null)
					throw T_Fail.testFailMsg("There should be space for this insert, row is " + s[i]);
				else
					notDone = false;
			}
			else
				i--;
		} while ((notDone) && (i >= 0));


		page1.unlatch();

		t_util.t_dropContainer(t, segment, cid);	// cleanup

		t_util.t_commit(t);
		t.close();

		PASS("P008");
	}

	/**
		P009

		this test exercises repeated shrinking and expanding of fields using updateFieldBySlot

		we will insert as many rows as possible into the page. Then set some of the columns to null,
		That should not create more space on the page for inserts, because the extra space become
		reservedspace for the row.  So, the next insert should fail.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	  */

	protected void P009(long segment) 
		 throws StandardException, T_Fail 
	{
		int slot = 0;
		int i = 0;
		int j = 0;
		String field = REC_001;

		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, segment);

		// Get the first page & check the record counts are zero
		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		t_util.t_checkEmptyPage(page);

		// Create a 13-column row
		T_RawStoreRow row = new T_RawStoreRow(13);
		row.setColumn(0, (String) null);
		row.setColumn(1, REC_001);
		row.setColumn(2, REC_002);
		row.setColumn(3, REC_003);
		row.setColumn(4, REC_004);
		row.setColumn(5, REC_005);
		row.setColumn(6, REC_006);
		row.setColumn(7, REC_007);
		row.setColumn(8, (String) null);
		row.setColumn(9, (String) null);
		row.setColumn(10, REC_007);
		row.setColumn(11, (String) null);
		row.setColumn(12, REC_006);

		// insert the row into the page until the page is full
		int numRows = 0;
		slot = page.FIRST_SLOT_NUMBER;
		while (page.spaceForInsert(row.getRow(), (FormatableBitSet) null, 100)) {
			t_util.t_insert(page, row);
			numRows++;
		}
		REPORT(numRows + " rows inserted ");

		// update all the fields in the even number rows to null
		// set all the fields in the odd number rows to REC_001
		DataValueDescriptor col = new SQLChar();	// null
		for (i = page.FIRST_SLOT_NUMBER; i < (page.FIRST_SLOT_NUMBER + 2); i++) {

			for (slot = i; slot <= (numRows - 1); slot += 2) {

				for (j = 0; j <= 12; j++) {
					if (page.updateFieldAtSlot(slot, j, col, null) == null) {

						throw T_Fail.testFailMsg("Failed to update field " + j+ ", in row " + slot);
					}
				}
			}

			col = new SQLChar(REC_001);
		}

		// fetch all the fields, and see if they are correct
		DataValueDescriptor storedColumn = new SQLChar();
		field = null;
		for (i = page.FIRST_SLOT_NUMBER; i < (page.FIRST_SLOT_NUMBER + 2); i++) {

			for (slot = i; slot <= (numRows - 1); slot += 2) {

				for (j = 0; j <= 12; j++) {

					t_util.t_checkFetchColFromSlot(page, slot, j, storedColumn, false, field);

				}
			}

			field = REC_001;
		}

		// Now if we try to insert the old row again, there should still be no room
		if (page.spaceForInsert())
			throw T_Fail.testFailMsg("Did not get no room for record on page error");

		// update the first and last field of every row to REC_006
		col = new SQLChar(REC_006);
		for (slot = page.FIRST_SLOT_NUMBER; slot <= (numRows - 1); slot++) {
			if (page.updateFieldAtSlot(slot, 0, col, null) == null ||
					page.updateFieldAtSlot(slot, 12, col, null) == null) {

				throw T_Fail.testFailMsg("Failed to update fields to REC_006 in row " + slot);
			}
		}
		
		// update field 5 and 6 of every row to REC_007
		col = new SQLChar(REC_007);
		for (slot = page.FIRST_SLOT_NUMBER; slot <= (numRows - 1); slot++) {
			if (page.updateFieldAtSlot(slot, 5, col, null) == null ||
					page.updateFieldAtSlot(slot, 6, col, null) == null) {

				throw T_Fail.testFailMsg("Failed to update fields to REC_007 in row " + slot);
			}
		}

		// fetch all the fields again, and see if they are correct
		for (i = page.FIRST_SLOT_NUMBER; i < (page.FIRST_SLOT_NUMBER + 2); i++) {

			for (slot = i; slot <= (numRows - 1); slot += 2) {

				for (j = 0; j <= 12; j++) {

					switch (j) {
					case 0:
					case 12:
						field = REC_006;
						break;
					case 5:
					case 6:
						field = REC_007;
						break;
					default:
						if ((slot % 2) == 0)
							field = null;
						else
							field = REC_001;
						break;
					}

					t_util.t_checkFetchColFromSlot(page, slot, j, storedColumn, false, field);

				}
			}
		}

		// We now try to insert the old row one last time, there should still be no room
		if (page.spaceForInsert())
			throw T_Fail.testFailMsg("Did not get no room for record on page error");

		// now we want to increase row 0 and column 5 one byte at a time, until the page is full
		// but, every 5 increases we will reduce the field size by one byte
		field = REC_007;
		i = 0;
		String field_pre = null;
		while (true) {
			if ((i % 5) != 0) {
				field_pre = field;
				field += REC_008;
			} else {
				field = field_pre;
			}

			if (((i % 10) == 3) || ((i % 10) == 7)) {
				page.unlatch();
				page = null;

				factory.idle();

				page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			}

			col = new SQLChar(field);

			try {
				page.updateFieldAtSlot(0, 5, col, null);
			} catch (StandardException se) {
				// now we have filled the page
				if (i < 809) {
					throw T_Fail.testFailMsg("should be able to update Row 0 Column 5 809 times"
						+ ", but only updated " + i
						+ " times.  Note: you maybe getting this error if your page format has changed.");
				} else {
					REPORT("Row 0 Column 5 was updated " + i + " times.");
				}
				break;
			}
			i++;
		}
		
		// The page is completely full at this point.
		// update Row 1 Column 1 from REC_001 to REC_002.  They are the same length
		page.unlatch();
		page = null;
		factory.idle();
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		col = new SQLChar(REC_002);
		if (page.updateFieldAtSlot(1, 1, col, null) == null) {
			throw T_Fail.testFailMsg("update Row 1 and Column 1 to same length data failed.");
		}

		REPORT("updated col1 in row 1 to same length");

		// now expand update Row 1 Column 1 by one byte.  This should fail.
		page.unlatch();
		page = null;
		factory.idle();
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		field = REC_002 + REC_008;
		col = new SQLChar(field);
		try {
			page.updateFieldAtSlot(1, 1, col, null);
			throw T_Fail.testFailMsg("update Row 1 and Column 1 to longer length should have failed.");
		} catch (StandardException se) {
			;
		}


		// clean up
		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);
		t.close();

		PASS("P009: segment " + segment);
		
	}



	/**
		P011

		this test exercises insertAtSlot, (LogicalUndo)null

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	  */
	protected void P011(long segment)
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, segment);
		t_util.t_commit(t);

	
		// Get the first page
		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// REPORT("insert 2 records at FIRST_SLOT_NUMBER");
		T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
		T_RawStoreRow row2 = new T_RawStoreRow(REC_002);
		T_RawStoreRow row3 = new T_RawStoreRow(REC_003);
		T_RawStoreRow row4 = new T_RawStoreRow(REC_004);

		// try inserting at slot -1 and slot 1
		try {
			RecordHandle r = t_util.t_insertAtSlot(page, -1, row1);
			throw T_Fail.testFailMsg("insert at slot -1 succeeded");
		} catch (StandardException se) {
			// throw if not a statement exception.
            if (se.getSeverity() > ExceptionSeverity.STATEMENT_SEVERITY)
                throw se;
		}

		try {
			RecordHandle r = t_util.t_insertAtSlot(page, 1, row1);
			throw T_Fail.testFailMsg("insert at slot 1 succeeded");
		} catch (StandardException se) {
			// throw if not a statement exception.
            if (se.getSeverity() > ExceptionSeverity.STATEMENT_SEVERITY)
                throw se;
		}
		
		RecordHandle r1, r2, r3, r4;
		// first insert to a page must suceed
		r3 = t_util.t_insertAtSlot(page, Page.FIRST_SLOT_NUMBER, row3);
		t_util.t_checkFetch(page, r3, REC_003);
		t_util.t_checkFetchBySlot(page, Page.FIRST_SLOT_NUMBER, REC_003,false, false);			

		r1 = r2 = r4 = null;
		r1 = t_util.t_insertAtSlot(page, Page.FIRST_SLOT_NUMBER, row1);

		if (r1 != null) {
			t_util.t_checkFetch(page, r1, REC_001);
			t_util.t_checkFetchBySlot(page, Page.FIRST_SLOT_NUMBER, REC_001,false, false);
		} else {
			t_util.t_abort(t);
			t.close();
			REPORT("P011 not run - could not fit 4 rows on page");
			return;
		}

		// REPORT("insert a record at 2nd slot");
		r2 = t_util.t_insertAtSlot(page, Page.FIRST_SLOT_NUMBER+1, row2);

		if (r2 != null) {
			t_util.t_checkFetch(page, r2, REC_002);
			t_util.t_checkFetchBySlot(page, Page.FIRST_SLOT_NUMBER+1, REC_002,false, false);
		} else {
			t_util.t_abort(t);
			t.close();
			REPORT("P011 not completed - could not fit 4 rows on page");
			return;
		}

		// REPORT("insert a record at the end");
		r4 = t_util.t_insertAtSlot(page, 3, row4);
		if (r4 != null) {
			t_util.t_checkFetch(page, r4, REC_004);
			t_util.t_checkFetchBySlot(page, 3, REC_004,false, false);
		} else {
			t_util.t_abort(t);
			t.close();
			REPORT("P011 not completed - could not fit 4 rows on page");
			return;
		}

		// REPORT("make sure records are in the correct order");
		// order is REC_001 REC_002 REC_003 REC_004 


		t_util.t_checkFetchFirst(page, REC_001);
		t_util.t_checkFetchNext(page, r1, REC_002);
		t_util.t_checkFetchNext(page, r2, REC_003);
		t_util.t_checkFetchNext(page, r3, REC_004);
		t_util.t_checkFetchLast(page, REC_004);

		// check the fetch by slot interface
		t_util.t_checkFetchBySlot(page, Page.FIRST_SLOT_NUMBER, REC_001,false, true);
		t_util.t_checkFetchBySlot(page, Page.FIRST_SLOT_NUMBER+1, REC_002,false, false);
		t_util.t_checkFetchBySlot(page, Page.FIRST_SLOT_NUMBER+2, REC_003,false, true);
		t_util.t_checkFetchBySlot(page, Page.FIRST_SLOT_NUMBER+3, REC_004,false, false);

		// clean up

		t_util.t_dropContainer(t, segment, cid);	// cleanup

		t_util.t_commit(t);
		t.close();

		PASS("P011");

	}

	/**
	  P012

	  this test exercises updateAtSlot

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P012(long segment)
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, segment);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// REPORT("insert 3 records");
		T_RawStoreRow row1 = new T_RawStoreRow(REC_001);

		T_RawStoreRow row2 = new T_RawStoreRow(2);
		row2.setColumn(0, (String) null);
		row2.setColumn(1, REC_001);

		T_RawStoreRow row3 = new T_RawStoreRow(3);
		row3.setColumn(0, REC_001);
		row3.setColumn(1, REC_002);
		row3.setColumn(2, REC_003);

		RecordHandle r1, r2, r3;
		r1 = t_util.t_insertAtSlot(page, 0, row1);

		r2 = r3 = null;
		r2 = t_util.t_insertAtSlot(page, 1, row2);
	
		if (r2 == null) {
			REPORT("P012 not completed - cannot insert second row");
			return;
		}

		r3 = t_util.t_insertAtSlot(page, 2, row3);
		if (r3 == null) {
			REPORT("P012 not completed - cannot insert third row");
			return;
		}

		// check that they are inserted correctly
		t_util.t_checkFetch(page, r1, row1);
		t_util.t_checkFetch(page, r2, row2);
		t_util.t_checkFetch(page, r3, row3);

		// REPORT("update that grows the #columns in row");
		T_RawStoreRow upd1 = new T_RawStoreRow(2);
		upd1.setColumn(0, (String) null);
		upd1.setColumn(1, REC_001);

		r1 = page.updateAtSlot(0, upd1.getRow(), (FormatableBitSet) null);
		t_util.t_checkFetch(page, r1, upd1);
		t_util.t_checkFetch(page, r2, row2);
		t_util.t_checkFetch(page, r3, row3);

		// REPORT("update that shrinks the #columns in row");
		T_RawStoreRow upd2 = new T_RawStoreRow(REC_004);

		r2 = page.updateAtSlot(1, upd2.getRow(), (FormatableBitSet) null);
		t_util.t_checkFetch(page, r1, upd1);
		t_util.t_checkFetch(page, r2, upd2);
		t_util.t_checkFetch(page, r3, row3);

		// REPORT("update same #columns in row");
		T_RawStoreRow upd3 = new T_RawStoreRow(3);
		upd3.setColumn(0, REC_003);
		upd3.setColumn(1, REC_002);
		upd3.setColumn(2, REC_001);

		r3 = page.updateAtSlot(2, upd3.getRow(), (FormatableBitSet) null);
		t_util.t_checkFetch(page, r1, upd1);
		t_util.t_checkFetch(page, r2, upd2);
		t_util.t_checkFetch(page, r3, upd3);

		// clean up

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);
		t.close();

		PASS("P012");
	}

	/**
	  P013

	  this test exercises deleteAtSlot and isDeletedAtSlot
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P013()
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, 0);

		t_util.t_commit(t);

		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// REPORT("insert 2 records");
		T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
		T_RawStoreRow row2 = new T_RawStoreRow(REC_002);

		RecordHandle r1 = t_util.t_insertAtSlot(page, 0, row1);
		RecordHandle r2;
		r2 = t_util.t_insertAtSlot(page, 1, row2);
		if (r2 == null) {
			REPORT("P013 not completed - could not fit two rows on a page");
			return;
		}

		t_util.t_checkRecordCount(page, 2, 2);

		// REPORT("delete them one by one");
		page.deleteAtSlot(0, true, (LogicalUndo)null);

		t_util.t_checkRecordCount(page, 2, 1);

		if (!page.isDeletedAtSlot(0))
			throw T_Fail.testFailMsg("Failed to delete record 0");
		if (page.isDeletedAtSlot(1))
			throw T_Fail.testFailMsg("Record mistakenly deleted");

		page.deleteAtSlot(1, true, (LogicalUndo)null);
		t_util.t_checkRecordCount(page, 2, 0);
		if (!page.isDeletedAtSlot(1))
			throw T_Fail.testFailMsg("Failed to delete record 1");

		page.deleteAtSlot(0, false, (LogicalUndo)null);
		t_util.t_checkRecordCount(page, 2, 1);
		if (page.isDeletedAtSlot(0))
			throw T_Fail.testFailMsg("Failed to undelete record 0");
		if (!page.isDeletedAtSlot(1))
			throw T_Fail.testFailMsg("Record mistakenly undeleted");

		page.deleteAtSlot(1, false, (LogicalUndo)null);
		t_util.t_checkRecordCount(page, 2, 2);
		if (page.isDeletedAtSlot(1))
			throw T_Fail.testFailMsg("Failed to undelete record 1");

		// try the negative tests
		try {
			page.deleteAtSlot(0, false, (LogicalUndo)null);
			throw T_Fail.testFailMsg("undeleted on undeleted record succeeded");
		} catch (StandardException se) {
			// throw if not a statement exception.
            if (se.getSeverity() > ExceptionSeverity.STATEMENT_SEVERITY)
                throw se;
		}

		page.deleteAtSlot(0, true, (LogicalUndo)null);
		try {
			page.deleteAtSlot(0, true, (LogicalUndo)null);
			throw T_Fail.testFailMsg("deleted on deleted record succeeded");
		} catch (StandardException se) {
			// throw if not a statement exception.
            if (se.getSeverity() > ExceptionSeverity.STATEMENT_SEVERITY)
                throw se;
		}

		t_util.t_checkRecordCount(page, 2, 1);
		// clean up
		PASS("P013");

		t_util.t_dropContainer(t, 0, cid);	// cleanup



		t_util.t_commit(t);
		t.close();

		
	}

	/**
	  P014

	  this test exercises purgeAtSlot
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P014()
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t,0);
		t_util.t_commit(t);

	
		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// REPORT("insert 5 records");
		T_RawStoreRow row0 = new T_RawStoreRow(REC_001);
		T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
		T_RawStoreRow row2 = new T_RawStoreRow(REC_002);
		T_RawStoreRow row3 = new T_RawStoreRow(REC_003);
		T_RawStoreRow row4 = new T_RawStoreRow(REC_004);
		
		RecordHandle r0, r1, r2, r3, r4;
		r0 = t_util.t_insertAtSlot(page, 0, row0);
		r1 = t_util.t_insertAtSlot(page, 1, row1);
		r2 = t_util.t_insertAtSlot(page, 2, row2);
		r3 = t_util.t_insertAtSlot(page, 3, row3);
		r4 = t_util.t_insertAtSlot(page, 4, row4);

		if (r3 != null) page.deleteAtSlot(3, true, (LogicalUndo)null);

		// REPORT("commit it");
		t_util.t_commit(t);

		c = t_util.t_openContainer(t, 0, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		try 
		{
			page.purgeAtSlot(-1, 1, logDataForPurges);
			throw T_Fail.testFailMsg("negative slot number did not cause an exception");
		}
		catch (StandardException se) {}	// expected

		try
		{
			page.purgeAtSlot(4, 4, logDataForPurges);
			throw T_Fail.testFailMsg("purging more rows than is on page did not cause an exception");
		}
		catch (StandardException se) {}	// expected

		// if not all the rows are there, do minimal test
		if (r4 == null)
		{
			int rcount = page.recordCount();
			page.purgeAtSlot(0, 1, logDataForPurges);
			if (page.recordCount() != rcount-1)
				T_Fail.testFailMsg("failed to purge a record, expect " + 
								   (rcount-1) + " got " + page.recordCount());

			if (testRollback)
			{
				t_util.t_abort(t);

				c = t_util.t_openContainer(t, 0, cid, true);
				page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
				if(logDataForPurges)
					t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
				else
					t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
				if (page.recordCount() != rcount)
					T_Fail.testFailMsg("failed to rollback purge, expect " + 
								   rcount + " got " + page.recordCount());
			}
			else
			{
				t_util.t_commit(t);
			}
			PASS("minimal P014");
			return;
		}

		// REPORT("purge 2 records from middle");
		page.purgeAtSlot(1, 2, logDataForPurges);
		t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
		t_util.t_checkFetchBySlot(page, 1, REC_003,true, true);
		t_util.t_checkFetchBySlot(page, 2, REC_004,false, true);

		if (page.recordCount() != 3)
			T_Fail.testFailMsg("page expect to have 3 records, recordCount() = " +
							   page.recordCount());

		// REPORT("purge all records from the page");
		page.purgeAtSlot(0, 3, logDataForPurges);
		if (page.recordCount() != 0)
			T_Fail.testFailMsg("page expect to have 0 records, recordCount() = " +
							   page.recordCount());

		if (testRollback)
		{

			REPORT("testing rollback");
			t_util.t_abort(t);

			c = t_util.t_openContainer(t, 0, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			if(logDataForPurges){
				t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 2, REC_002,false, true);
				t_util.t_checkFetchBySlot(page, 3, REC_003,true, true);
				t_util.t_checkFetchBySlot(page, 4, REC_004,false, true);
			}else
			{
				t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 2, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 3, REC_NULL,true, true);
				t_util.t_checkFetchBySlot(page, 4, REC_NULL,false, true);
			}

			if (page.recordCount() != 5)
				T_Fail.testFailMsg("page expect to have 5 records, recordCount() = " +
								   page.recordCount());

			// REPORT("purge 3 records from the end");
			page.purgeAtSlot(2, 3, logDataForPurges);
			if(logDataForPurges)
			{
				t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_001,false, true);
			}else
			{
				t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_NULL,false, true);
			}
			if (page.recordCount() != 2)
				T_Fail.testFailMsg("page expect to have 2 records, recordCount() = " +
								   page.recordCount());

			// REPORT("rollback");
			t_util.t_abort(t);

			c = t_util.t_openContainer(t, 0, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			if(logDataForPurges){
				t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 2, REC_002,false, true);
				t_util.t_checkFetchBySlot(page, 3, REC_003,true, true);
				t_util.t_checkFetchBySlot(page, 4, REC_004,false, true);
			}else
			{
				t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 2, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 3, REC_NULL,true, true);
				t_util.t_checkFetchBySlot(page, 4, REC_NULL,false, true);	
			}

			if (page.recordCount() != 5)
				T_Fail.testFailMsg("page expect to have 5 records, recordCount() = " +
								   page.recordCount());

			// REPORT("make sure delete record is reconstituted as such");
			if (page.isDeletedAtSlot(1))
				T_Fail.testFailMsg("rolled back purged undeleted record cause record to be deleted");
			if (!page.isDeletedAtSlot(3))
				T_Fail.testFailMsg("rolled back purged deleted record cause record to be undeleted");
		}
		PASS("P014");

		t_util.t_dropContainer(t, 0, cid);	// cleanup
		t_util.t_commit(t);
		t.close();
	}


	/**
	  P015

	  this test exercises updateAtSlot

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P015()
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, 0);

		t_util.t_commit(t);


		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// REPORT("insert 3 records");
		T_RawStoreRow row1 = new T_RawStoreRow(REC_001);

		T_RawStoreRow row2 = new T_RawStoreRow(2);
		row2.setColumn(0, (String) null);
		row2.setColumn(1, REC_001);

		T_RawStoreRow row3 = new T_RawStoreRow(3);
		row3.setColumn(0, REC_001);
		row3.setColumn(1, REC_002);
		row3.setColumn(2, REC_003);

		RecordHandle r1, r2, r3;
		r1 = t_util.t_insertAtSlot(page, 0, row1);

		r2 = r3 = null;
		r2 = t_util.t_insertAtSlot(page, 1, row2);

		if (r2 == null) {
			REPORT("P015 not completed - cannot insert second row");
			return;
		}

		r3 = t_util.t_insertAtSlot(page, 2, row3);

		if (r3 == null) {
			REPORT("P015 not completed - cannot insert third row");
			return;
		}

		// check that they are inserted correctly
		t_util.t_checkFetch(page, r1, row1);
		t_util.t_checkFetch(page, r2, row2);
		t_util.t_checkFetch(page, r3, row3);

		// now update the middle row with a large value
		T_RawStoreRow row2u = new T_RawStoreRow(2);
		row2u.setColumn(0, "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
		row2u.setColumn(1, "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");

		page.updateAtSlot(1, row2u.getRow(), (FormatableBitSet) null);
		t_util.t_checkFetch(page, r2, row2u);


		// now update the field of the first record with a large value
		((T_RawStoreRow) row1).setColumn(0, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");

        FormatableBitSet validColumn = new FormatableBitSet(2);

        validColumn.clear();
        validColumn.set(0);

        page.updateAtSlot(0, row1.getRow(), validColumn);

		t_util.t_checkFetch(page, r1, row1);

		((T_RawStoreRow) row3).setColumn(1, "XXabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");

        validColumn.clear();
        validColumn.set(1);

        page.updateAtSlot(2, row3.getRow(), validColumn);
		t_util.t_checkFetch(page, r3, row3);

		// clean up
		PASS("P015");

		t_util.t_dropContainer(t, 0, cid);	// cleanup


		t_util.t_commit(t);
		t.close();

	}

	/*
		P016

		this test exercises copyAndPurge
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P016()
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, 0);
		long cid2 = t_util.t_addContainer(t, 0);

		t_util.t_commit(t);


		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);

		Page page1 = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		Page page2 = t_util.t_addPage(c);
		long pid1 = page1.getPageNumber();
		long pid2 = page2.getPageNumber();

		t_util.t_checkEmptyPage(page2);

		// first fill up page 1

		int i = 0;
		int deleted = 0;
		RecordHandle rh;

		T_RawStoreRow row;

		for (i = 0, row = new T_RawStoreRow("row at slot " + i);
			 page1.spaceForInsert();
			 i++, row = new T_RawStoreRow("row at slot " + i))
		{
			rh = t_util.t_insertAtSlot(page1, i, row );
			if (rh == null)
				break;
			
			// delete every third row
			if ((i % 3) == 1)
			{
				deleted++;
				page1.deleteAtSlot(i, true, null);
			}
		}

		int recordCount = i;

		// negative testing
		// copy into page of different container
		ContainerHandle c2 = t_util.t_openContainer(t, 0, cid2, true);
		Page wrongPage = t_util.t_getPage(c2, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			page1.copyAndPurge(wrongPage, 0, recordCount, 0);
			throw T_Fail.testFailMsg("copying to page from a different contaier should cause and exception");
		}
		catch (StandardException se) {} // expected

		try 
		{
			page1.copyAndPurge(page2, 1, 0, 0);
			throw T_Fail.testFailMsg("copying zero rows should cause an exception");
		}
		catch (StandardException se) {} // expected

		try
		{
			page1.copyAndPurge(page2, 1, recordCount, 0);
			throw T_Fail.testFailMsg("copying more rows than page contains should cause an exception");
		}
		catch (StandardException se) {} // expected

		try
		{
			page1.copyAndPurge(page2, 0, 1, 1);
			throw T_Fail.testFailMsg("copying rows to nonexistant slot should cause an exception");
		}
		catch (StandardException se) {} // expected


		// copy the whole page to page2
		page1.copyAndPurge(page2, 0, recordCount, 0);

		// check
		t_util.t_checkEmptyPage(page1);

		for (i = 0; i < recordCount; i++)
		{
			t_util.t_checkFetchBySlot(page2, i, "row at slot " + i,
									((i%3) == 1), true);
		}
		t_util.t_checkRecordCount(page2, recordCount, recordCount-deleted);


		t_util.t_commit(t);

		if (recordCount > 2)
		{
			// now copy and purge part of the page
			c = t_util.t_openContainer(t, 0, cid, true);
			page1 = t_util.t_getPage(c, pid1);
			page2 = t_util.t_getPage(c, pid2);


			// insert 2 rows into page1
			T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
			T_RawStoreRow row2 = new T_RawStoreRow(REC_002);
			t_util.t_insertAtSlot(page1, 0, row1);
			t_util.t_insertAtSlot(page1, 1, row2);

			page2.copyAndPurge(page1, 1, recordCount-2, 1);

			t_util.t_checkFetchBySlot(page2, 0, "row at slot " + 0,false, true);
			
			// need to figure out the delete status of the last row on page 2
			boolean tdeleted = ((recordCount-1)%3) == 1;
			t_util.t_checkFetchBySlot(page2, 1, "row at slot " + (recordCount-1),tdeleted, true);
			
			if (((recordCount-1) % 3) == 1)
				t_util.t_checkRecordCount(page2, 2, 1);	// last record on page2 was deleted
			else
				t_util.t_checkRecordCount(page2, 2, 2);	// last record on page2 was not deleted

			t_util.t_checkFetchBySlot(page1, 0, REC_001,false, false);
			for (i = 1; i < recordCount-1; i++)
			{
				t_util.t_checkFetchBySlot(page1, i, "row at slot " + i,
										((i%3)==1), false);
			}
			t_util.t_checkFetchBySlot(page1, recordCount-1, REC_002,false, false);
			if (((recordCount-1) % 3) == 1)
				// one (the last one) of the deleted rows did not get copied over
				t_util.t_checkRecordCount(page1, recordCount, recordCount-deleted+1);
			else
				t_util.t_checkRecordCount(page1, recordCount, recordCount-deleted);

			if (testRollback)
			{
				t_util.t_abort(t);

				c = t_util.t_openContainer(t, 0, cid, true);
				page1 = t_util.t_getPage(c, pid1);
				page2 = t_util.t_getPage(c, pid2);

				// the two inserted rows is rolled back by deletion
				t_util.t_checkFetchBySlot(page1, 0, REC_001,true, false);
				t_util.t_checkFetchBySlot(page1, 1, REC_002,true, false);
				t_util.t_checkRecordCount(page1, 2, 0);

				for (i = 0; i < recordCount; i++)
				{
					t_util.t_checkFetchBySlot(page2, i, "row at slot " + i,
											((i%3)==1), true);
				}
				t_util.t_checkRecordCount(page2, recordCount, recordCount-deleted);

				REPORT("tested roll back of copyAndPurge");
			}


			PASS("P016");
		}

		t_util.t_dropContainer(t, 0, cid);	// cleanup
		t_util.t_dropContainer(t, 0, cid2);	// cleanup
		t_util.t_commit(t);
		t.close();
	}


	/*
		P017
		this test getInvalidRecordHandle and makeRecordHandle 

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P017()		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		

		long cid = t_util.t_addContainer(t, 0);
		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);

		Page page1 = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		T_RawStoreRow row1 = new T_RawStoreRow(REC_001);

		RecordHandle valid = t_util.t_insert(page1, row1);

		RecordHandle[] rhs = new RecordHandle[RecordHandle.FIRST_RECORD_ID];
		rhs[0] = page1.getInvalidRecordHandle();
		rhs[1] = page1.makeRecordHandle(RecordHandle.RESERVED1_RECORD_HANDLE);
		rhs[2] = page1.makeRecordHandle(RecordHandle.DEALLOCATE_PROTECTION_HANDLE);
		rhs[3] = page1.makeRecordHandle(RecordHandle.PREVIOUS_KEY_HANDLE);
		rhs[4] = page1.makeRecordHandle(RecordHandle.RESERVED4_RECORD_HANDLE);
		rhs[5] = page1.makeRecordHandle(RecordHandle.RESERVED5_RECORD_HANDLE);

		for (int i = 0; i < RecordHandle.FIRST_RECORD_ID; i++)
		{
			try 
			{
				page1.recordExists(rhs[i], true);
				throw T_Fail.testFailMsg("record exists for invalid record " + rhs[i]);
			}
			catch (StandardException se)
			{ 
                /* expected */ 
            }


			try 
			{
				int slot = page1.getSlotNumber(rhs[i]);
				page1.fetchFromSlot(
					rhs[i], slot, new DataValueDescriptor[0], null, false);
				throw T_Fail.testFailMsg("fetched an invalid record " + rhs[i]);
			}
			catch (StandardException se)
			{ 
                /* expected */ 
            }

			try 
			{
				int slot = page1.getSlotNumber(rhs[i]);
				page1.updateAtSlot(slot, row1.getRow(), null);
				throw T_Fail.testFailMsg("updated an invalid record " + rhs[i]);
			}
			catch (StandardException se)
			{ 
                /* expected */ 
            }

			try 
			{
				int slot = page1.getSlotNumber(rhs[i]);
				page1.updateAtSlot(slot, row1.getRow(), BS_COL_0);
				throw T_Fail.testFailMsg("updated an invalid record field");
			}
			catch (StandardException se)
			{ 
                /* expected */ 
            }

			try 
			{
				int slot = page1.getSlotNumber(rhs[i]);
				page1.deleteAtSlot(slot, true, null);
				throw T_Fail.testFailMsg("delete an invalid record " + rhs[i]);
			}
			catch (StandardException se)
			{ 
                /* expected */ 
            }


			try 
			{
				page1.fetchNumFields(rhs[i]);
				throw T_Fail.testFailMsg("fetch num fields on invalid record " + rhs[i]);
			}
			catch (StandardException se)
			{ 
                /* expected */ 
            }

			try 
			{
				page1.getSlotNumber(rhs[i]);
				throw T_Fail.testFailMsg("got slot number of invalid record " + rhs[i]);
			}
			catch (StandardException se)
			{ 
                /* expected */ 
            }

		}
		PASS("P017");

		t_util.t_dropContainer(t, 0, cid);
		t_util.t_commit(t);	
		t.close();
	}

	/*
		P018

		this test exercises track # 590, test that copyRows successfully
        notices that a copy can't be done.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P018()
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();

        // create container with 0 spare space, 1 minimum record size to easily
        // force absolutely full page.  Record id's are not reusable.
		long cid = t_util.t_addContainer(t, 0, 4096, 0, 1, false);

		t_util.t_commit(t);

		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);

		Page page1 = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		Page page2 = t_util.t_addPage(c);
		long pid1 = page1.getPageNumber();
		long pid2 = page2.getPageNumber();

		t_util.t_checkEmptyPage(page2);

		// first fill up page 1

		int i = 0;
		int deleted = 0;
		RecordHandle rh;

		T_RawStoreRow row;

        // first insert and purge 100 rows, setting the next recid to be 
        // greater than 64.  This will cause the next
        // recid to be allocated to be greater than 64, this means 
        // that new recid's added to the page take 2 bytes rather than 1.
		for (i = 0; i < 100; i++)
		{
            row = new T_RawStoreRow("r" + i);

			rh = t_util.t_insertAtSlot(page1, 0, row);

            page1.purgeAtSlot(0, 1, logDataForPurges);
		}

        // fill up another page starting with "small" record id's.
		for (i = 0; true; i++)
		{
            row = new T_RawStoreRow("r" + i);

			rh = t_util.t_insertAtSlot(page2, i, row);

			if (rh == null)
				break;
		}

        // an attempt to copy all the rows should get an error, because the
        // recid's are bigger so all the records will not fit.
        try 
        {
            page2.copyAndPurge(page1, 0, page2.recordCount(), 0);

			throw T_Fail.testFailMsg(
                "copying rows with expanding recids should cause an exception");
        }
        catch (StandardException se)
        {
            // expect a out of space error.

        }

        // cleanup after first part of test.
		t_util.t_dropContainer(t, 0, cid);
		t_util.t_commit(t);

        // Now test that with the reusable record id's that the copy works.

        // create container with 0 spare space, 1 minimum record size to easily
        // force absolutely full page.  This container will allow 
        // reusable record id's which will mean the copy should succeed.
		cid = t_util.t_addContainer(t, 0, 4096, 0, 1, true);

		t_util.t_commit(t);

		c = t_util.t_openContainer(t, 0, cid, true);

		page1 = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		page2 = t_util.t_addPage(c);
		pid1 = page1.getPageNumber();
		pid2 = page2.getPageNumber();

		t_util.t_checkEmptyPage(page2);

		// first fill up page 1

		i = 0;

        // first insert and purge 100 rows, setting the next recid to be 
        // greater than 64.  This will cause the next
        // recid to be allocated to be greater than 64, this means 
        // that new recid's added to the page take 2 bytes rather than 1.
		for (i = 0; i < 100; i++)
		{
            row = new T_RawStoreRow("r" + i);

			rh = t_util.t_insertAtSlot(page1, 0, row);

            page1.purgeAtSlot(0, 1, logDataForPurges);
		}

        // fill up another page starting with "small" record id's.
		for (i = 0; true; i++)
		{
            row = new T_RawStoreRow("r" + i);

			rh = t_util.t_insertAtSlot(page2, i, row);

			if (rh == null)
				break;
		}
		long pnum2 = page2.getPageNumber();
		int numrows = page2.recordCount();

        // an attempt to copy all the rows should  get an error, 
        try 
        {
            // This copy should not succeed.
            page2.copyAndPurge(page1, 0, page2.recordCount(), 0);

			throw T_Fail.testFailMsg(
                "copying rows with expanding recids should cause an exception");
        }
        catch (StandardException se)
        {
            // expect a out of space error.
        }

		// now deallocated this page and get it to go thru a reuse cycle
		t_util.t_removePage(c, page1);
		t_util.t_commit(t);
		
		c = t_util.t_openContainer(t, 0, cid, true);
		page1 = t_util.t_addPage(c);
		int tries = 0;
		while(page1.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
		{
			REPORT("getting page " + page1.getPageNumber());

			t_util.t_commit(t);

			if (tries++ > 100)
				throw T_Fail.testFailMsg("failed to get back first page after "
										 + tries + " tries");
			c = t_util.t_openContainer(t, 0, cid, true);
			page1 = t_util.t_addPage(c);
		}
		page2 = t_util.t_getPage(c, pnum2);


		t_util.t_checkRecordCount(page2, numrows, numrows);
		t_util.t_checkEmptyPage(page1);

        // now the attempt to copy all the rows should succeed
        try 
        {
            page2.copyAndPurge(page1, 0, page2.recordCount(), 0);
        }
        catch (StandardException se)
        {
			throw T_Fail.testFailMsg(
                "copying rows with non-expanding recids should not cause an exception");
        }

		PASS("P018");

		t_util.t_dropContainer(t, 0, cid);	// cleanup
		t_util.t_commit(t);
		t.close();
	}

	/**
		Test bulk load and preallocation
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P019() throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, 0, 4096, 0, 1, false);
		t_util.t_commit(t);

		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);

		// add page for bulk load
		Page p1 = c.addPage(ContainerHandle.ADD_PAGE_BULK);	
		long pnum1 = p1.getPageNumber();
		p1.unlatch();

		// since the interface does not guarentee that anything special will
		// actually happen, can't really test that. Just make sure that
		// everything else works
		Page p2 = c.addPage();
		long pnum2 = p2.getPageNumber();
		p2.unlatch();

		Page p3 = c.addPage(ContainerHandle.ADD_PAGE_BULK);	
		long pnum3 = p3.getPageNumber();
		p3.unlatch();

		Page p = c.getFirstPage(); // this is the first page that came with the
								   // container when it was created

		try
		{
			long pnum0 = p.getPageNumber();
			p.unlatch();
			p = c.getNextPage(pnum0);
			if (p.getPageNumber() != pnum1)
				throw T_Fail.testFailMsg("expected pagenum " + pnum1 + " got " + p.getPageNumber());
			p.unlatch();
			p = null;

			p = c.getNextPage(pnum1);
			if (p.getPageNumber() != pnum2)
				throw T_Fail.testFailMsg("expected pagenum " + pnum2 + " got " + p.getPageNumber());
			p.unlatch();
			p = null;

			p = c.getNextPage(pnum2);
			if (p.getPageNumber() != pnum3)
				throw T_Fail.testFailMsg("expected pagenum " + pnum3 + " got " + p.getPageNumber());
			p.unlatch();
			p = null;

			p = c.getNextPage(pnum3);
			if (p != null)
				throw T_Fail.testFailMsg("expected null page after " + pnum3 +
										 " got " + p.getPageNumber());

			// make sure rollback is unaffected
			if (testRollback)
			{
				t_util.t_abort(t);
				c = t_util.t_openContainer(t, 0, cid, true);
				p = t_util.t_getPage(c, pnum0);
				t_util.t_checkEmptyPage(p);
				p.unlatch();
				p = null;
			
				p = t_util.t_getPage(c, pnum1);
				t_util.t_checkEmptyPage(p);
				p.unlatch();
				p = null;

				p = t_util.t_getPage(c, pnum2);
				t_util.t_checkEmptyPage(p);
				p.unlatch();
				p = null;

				p = t_util.t_getPage(c, pnum3);
				t_util.t_checkEmptyPage(p);
				p.unlatch();
				p = null;

				p = t_util.t_getLastPage(c);
				if (p.getPageNumber() != pnum3)
					throw T_Fail.testFailMsg("expect last page to be " + pnum3
											 + " got " + p.getPageNumber());
				p.unlatch();
				p = null;
			}

			t_util.t_dropContainer(t, 0, cid);	// cleanup

		}
		finally
		{
			if (p != null)
				p.unlatch();
			p = null;
			t_util.t_commit(t);
			t.close();
		}
		PASS("P019 - container " + cid);

	}

	/**
		Test create container with initial page set to 100 pages
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P020() throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		Properties tableProperties = new Properties();
		tableProperties.put(Property.PAGE_SIZE_PARAMETER, Integer.toString(4096));
		tableProperties.put(RawStoreFactory.CONTAINER_INITIAL_PAGES, Integer.toString(100));

		long cid = t_util.t_addContainer(t, 0, tableProperties);
		if (cid < 0)
			throw T_Fail.testFailMsg("addContainer");

		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);

		Page p1 = c.getFirstPage();
		if (p1.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
			throw T_Fail.testFailMsg("expect first page to have FIRST_PAGE_NUMBER");
		p1.unlatch();

		if (c.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
			throw T_Fail.testFailMsg("expect to have only 1 page allocated");

		t_util.t_dropContainer(t, 0, cid);	// cleanup
		t_util.t_commit(t);
		t.close();
		PASS("P020 - container " + cid);
	}

	/**
		Test preAllocate
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P021() throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, 0, 4096);
		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);

		// now preallocate 10 pages
		c.preAllocate(10);

		Page p1 = c.getFirstPage();
		if (p1.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
			throw T_Fail.testFailMsg("expect first page to have FIRST_PAGE_NUMBER");
		p1.unlatch();

		if (c.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
			throw T_Fail.testFailMsg("expect to have only 1 page allocated");

		t_util.t_dropContainer(t, 0, cid);	// cleanup
		t_util.t_commit(t);
		t.close();
		PASS("P021 - container " + cid);
	}

	/**
		Test minimumRecordSize: this is to make sure that logRow and storeRecord
		are consistent with each other when it comes to reserve space.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P022()
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();

        // create container with 4096 page size, 0 spare space, 9 minimum record size
		long cid = t_util.t_addContainer(t, 0, 4096, 0, 9, false);

		t_util.t_commit(t);

		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);

		Page page1 = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		RecordHandle rh;
		T_RawStoreRow row;

        // insert records to fill the page.
		for (int i = 0; i < 60; i++) {
            row = new T_RawStoreRow("r" + i);
			rh = t_util.t_insertAtSlot(page1, 0, row);
		}

        // cleanup after first part of test.
		t_util.t_dropContainer(t, 0, cid);	// cleanup
		t_util.t_commit(t);
		t.close();
		PASS("P022");
	}
		
	/**
		Test overflowThreshold: this is to make sure that logRow and storeRecord
		are consistent with each other when it comes to reserve space.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P023(int segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();
		// create a container with 1K page, 0 spareSpace, and 0 minimumRecordSize
		long cid = t_util.t_addContainer(t, segment, 4096, 0, 0, false);
		t_util.t_commit(t);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		int overflowThreshold = 50;

		t_util.t_checkEmptyPage(page);

		// use default insert, not allowing overflow
		int insertFlag = Page.INSERT_INITIAL | Page.INSERT_DEFAULT;

		// test 1:
		// create a row that's under the threshold
		T_RawStoreRow r1 = new T_RawStoreRow(1);
		r1.setColumn(0, 200, REC_001);
		// insert the row twice, should fit on 1 page
		RecordHandle rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag, overflowThreshold);
		if (rh1 == null)
			throw T_Fail.testFailMsg("insert of first long row failed.");
		RecordHandle rh2 = t_util.t_insertAtSlot(page, 1, r1, (byte) insertFlag, overflowThreshold);	
		if (rh2 == null)
			throw T_Fail.testFailMsg("insert of second long row failed.");
		t_util.t_checkFetch(page, rh1, r1);
		t_util.t_checkFetch(page, rh2, r1);
		page.unlatch();
		page = null;
		REPORT("test 1: 2 rows under threshold inserted...");

		// test 2:
		// get a new page
		page = t_util.t_addPage(c);
		// create a row that's over the threshold
		T_RawStoreRow r2 = new T_RawStoreRow(1);
		r2.setColumn(0, 2000, REC_001);
		// insert the row twice, should fail both inserts
		rh1 = t_util.t_insertAtSlot(page, 0, r2, (byte) insertFlag, overflowThreshold);
		if (rh1 != null)
        {
			throw T_Fail.testFailMsg("insert of 1st over threshold row should failed.");
        }
		rh2 = t_util.t_insertAtSlot(page, 0, r2, (byte) insertFlag, overflowThreshold);	
		if (rh2 != null)
			throw T_Fail.testFailMsg("insert of 2nd over threshold row should failed.");
		page.unlatch();
		page = null;
		REPORT("test 2: 2 rows over threshold not inserted...");

		// test 3:
		// get a new page
		page = t_util.t_addPage(c);
		// create a row with 2 columns, each column is under the threshold,
		// and the row is also under the threshold
		T_RawStoreRow r3 = new T_RawStoreRow(2);
		// create a row that's under the threshold
		r3.setColumn(0, 400, REC_001);
		r3.setColumn(1, 400, REC_001);
		// insert the row twice, should fit on 1 page
		rh1 = t_util.t_insertAtSlot(page, 0, r3, (byte) insertFlag, overflowThreshold);
		if (rh1 == null)
			throw T_Fail.testFailMsg("insert of 1st 2-column row failed.");
		rh2 = t_util.t_insertAtSlot(page, 1, r3, (byte) insertFlag, overflowThreshold);	
		if (rh2 == null)
			throw T_Fail.testFailMsg("insert of 2nd 2-column row failed.");
		page.unlatch();
		page = null;
		REPORT("test 3: 2 rows with 2 columns under the threshold inserted...");

		// test 4:
		// get a new page
		page = t_util.t_addPage(c);
		// create a row with 2 columns, each column is under the threshold,
		// but the row is over the threshold
		T_RawStoreRow r4 = new T_RawStoreRow(2);
		// create a row that's under the threshold
		r4.setColumn(0, 800, REC_001);
		r4.setColumn(1, 800, REC_001);
		// insert the row twice, should fit on 1 page
		rh1 = t_util.t_insertAtSlot(page, 0, r4, (byte) insertFlag, overflowThreshold);
		if (rh1 != null)
        {
            SanityManager.DEBUG_PRINT("bug", "page = " + page);
			throw T_Fail.testFailMsg("insert of 1st 2-column row (OT) should failed.");
        }
		rh2 = t_util.t_insertAtSlot(page, 0, r4, (byte) insertFlag, overflowThreshold);	
		if (rh2 != null)
			throw T_Fail.testFailMsg("insert of 2nd 2-column row (OT) should failed.");
		page.unlatch();
		page = null;
		REPORT("test 4: 2 rows with 2 columns over the threshold not inserted...");

        // cleanup after first part of test.
		t_util.t_dropContainer(t, segment, cid);	// cleanup
		t_util.t_commit(t);
		t.close();
		PASS("P023");
	}

	/**
	 * Test that latches are exclusive.
	 *
	 * @exception T_Fail Unexpected behaviour from the API
	 * @exception StandardException Unexpected exception from the implementation
	 */
	protected void P024(long segment) throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, segment, 4096, 0, 1, false);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);

		Page page1 = t_util.t_getLastPage(c);
		Page page2 = t_util.t_addPage(c);

		long p1 = page1.getPageNumber();
		long p2 = page2.getPageNumber();

		// check that we cannot get any of the latched pages
		t_util.t_checkGetLatchedPage(c, p1);
		t_util.t_checkGetLatchedPage(c, p2);

		page1.unlatch();

		// check that we still cannot get page2
		t_util.t_checkGetLatchedPage(c, p2);

		// we should be able to get page1
		page1 = t_util.t_getPage(c, p1);

		page1.unlatch();
		page2.unlatch();

		// cleanup
		t_util.t_dropContainer(t, segment, cid);

		t_util.t_commit(t);
		t.close();

		PASS("P024");
	}
		
	/**
		Insert small rows and update them so that they overflow a page.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P030(long segment) throws StandardException, T_Fail {

	 	Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		T_RawStoreRow r0 = new T_RawStoreRow(0);
		T_RawStoreRow r1 = new T_RawStoreRow((String) null);
		T_RawStoreRow r2 = new T_RawStoreRow("0123456789");

		t_util.t_insertAtSlot(page, 0, r0);
		t_util.t_insertAtSlot(page, 1, r1);
		t_util.t_insertAtSlot(page, 2, r2);

		t_util.t_checkRecordCount(page, 3, 3);
		page.unlatch();
		page = null;

		// check there is only one page
		if (c.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
			throw T_Fail.testFailMsg("an extra page has appeared in the container");
		t_util.t_commit(t);

		//
		// Update the row at slot 1 so that it fills most of the page
		//
		c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		t_util.t_checkStringLengthFetch(page, 1, -1);
		t_util.t_checkStringLengthFetch(page, 2, 10);

		t_util.t_checkFieldCount(page, 0, 0);
		t_util.t_checkFieldCount(page, 1, 1);
		t_util.t_checkFieldCount(page, 2, 1);

		T_RawStoreRow r1u = new T_RawStoreRow(String.valueOf(new char[1937]));
		page.updateAtSlot(1, r1u.getRow(), (FormatableBitSet) null);
		t_util.t_checkStringLengthFetch(page, 1, 1937);  // on page 1
		t_util.t_checkStringLengthFetch(page, 2, 10);	  // on page 1
		t_util.t_checkFieldCount(page, 0, 0);
		t_util.t_checkFieldCount(page, 1, 1);
		t_util.t_checkFieldCount(page, 2, 1);
		page.unlatch();
		// check there is only one page
		if (c.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
			throw T_Fail.testFailMsg("an extra page has appeared in the container");
		t_util.t_commit(t);

		//
		// Update the row at slot 2 so that it overflows
		//
		c = t_util.t_openContainer(t, segment, cid, true);
		T_RawStoreRow r2u = new T_RawStoreRow(String.valueOf(new char[1099])); // stored length is twice string lenght + 2
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		page.updateAtSlot(2, r2u.getRow(), (FormatableBitSet) null);
		t_util.t_checkStringLengthFetch(page, 1, 1937); // on page 1
		t_util.t_checkStringLengthFetch(page, 2, 1099); // on first overflow page
		t_util.t_checkFieldCount(page, 0, 0);
		t_util.t_checkFieldCount(page, 1, 1);
		t_util.t_checkFieldCount(page, 2, 1);
		page.unlatch();
		// check there is only one page
		if (c.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
			throw T_Fail.testFailMsg("an extra page has appeared in the container");
		t_util.t_commit(t);

		c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkStringLengthFetch(page, 1, 1937); // on page 1
		t_util.t_checkStringLengthFetch(page, 2, 1099); // on first overflow page
		t_util.t_checkFieldCount(page, 0, 0);
		t_util.t_checkFieldCount(page, 1, 1);
		t_util.t_checkFieldCount(page, 2, 1);
		// check there is only one page
		if (c.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
			throw T_Fail.testFailMsg("an extra page has appeared in the container");
		t_util.t_commit(t);

		//
		// Update the row at slot 0 so that it overflows onto the same page as the first
		// overflow.
		//
		c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		T_RawStoreRow r0u = new T_RawStoreRow(String.valueOf(new char[423]));
		page.updateAtSlot(0, r0u.getRow(), (FormatableBitSet) null);
		t_util.t_checkStringLengthFetch(page, 0, 423); // on first overflow page
		t_util.t_checkStringLengthFetch(page, 1, 1937); // on page 1
		t_util.t_checkStringLengthFetch(page, 2, 1099); // on first overflow page
		t_util.t_checkFieldCount(page, 0, 1);
		t_util.t_checkFieldCount(page, 1, 1);
		t_util.t_checkFieldCount(page, 2, 1);
		page.unlatch();
		// check there is only one page
		if (c.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
			throw T_Fail.testFailMsg("an extra page has appeared in the container");

		t_util.t_commit(t);

		//
		// Update the row at slot 0 that has already been overflowed
		// but keeping it on the same page
		//
		c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		r0u = new T_RawStoreRow(String.valueOf(new char[399]));
		page.updateAtSlot(0, r0u.getRow(), (FormatableBitSet) null);
		t_util.t_checkStringLengthFetch(page, 0, 399); // on first overflow page
		t_util.t_checkStringLengthFetch(page, 1, 1937); // on page 1
		t_util.t_checkStringLengthFetch(page, 2, 1099); // on first overflow page
		t_util.t_checkFieldCount(page, 0, 1);
		t_util.t_checkFieldCount(page, 1, 1);
		t_util.t_checkFieldCount(page, 2, 1);
		page.unlatch();
		// check there is only one page
		if (c.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
			throw T_Fail.testFailMsg("an extra page has appeared in the container");

		//
		// Update the row at slot 0 that has already been overflowed
		// but moving it to a new page
		//
		c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		r0u = new T_RawStoreRow(String.valueOf(new char[1400]));
		page.updateAtSlot(0, r0u.getRow(), (FormatableBitSet) null);
		t_util.t_checkStringLengthFetch(page, 0, 1400); // on second overflow page
		t_util.t_checkStringLengthFetch(page, 1, 1937); // on page 1
		t_util.t_checkStringLengthFetch(page, 2, 1099); // on first overflow page
		t_util.t_checkFieldCount(page, 0, 1);
		t_util.t_checkFieldCount(page, 1, 1);
		t_util.t_checkFieldCount(page, 2, 1);
		page.unlatch();
		// check there is only one page
		if (c.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
			throw T_Fail.testFailMsg("an extra page has appeared in the container");

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);

		t.close();

		PASS("P030: segment = " + segment);
	}

	/**
		Insert 4-column long rows into 1K pages, each column is less than a page.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P031(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		T_RawStoreRow r0 = new T_RawStoreRow(4);
		r0.setColumn(0, 256, REC_001);
		r0.setColumn(1, 256, REC_002);
		r0.setColumn(2, 256, REC_003);
		r0.setColumn(3, 256, REC_004);

		int insertFlag = Page.INSERT_INITIAL;
		insertFlag |= Page.INSERT_OVERFLOW;

		RecordHandle rh0 = null;
		try {
			rh0 = t_util.t_insertAtSlot(page, 0, r0, (byte) insertFlag);	
		} catch (StandardException se) {
			throw T_Fail.testFailMsg("insert of long row failed.");
		}

		if (rh0 == null) 
			throw T_Fail.testFailMsg("insert of first long row failed.");
		else {
			REPORT("about to check fetch...");
			DataValueDescriptor column = new SQLChar();
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 0, column, false, REC_001, 256);
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 1, column, false, REC_002, 256);
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 2, column, false, REC_003, 256);
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 3, column, false, REC_004, 256);
		}

		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);

		t.close();

		PASS("P031: segment = " + segment);
	}

	/**
		Insert 60-column long rows into 1K pages, each column is less than a page.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P032(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		int insertFlag = Page.INSERT_INITIAL;
		insertFlag |= Page.INSERT_OVERFLOW;

		T_RawStoreRow r0 = new T_RawStoreRow(60);
		for (int i = 0; i < 60; i++) {
			r0.setColumn(i, 1200, REC_001);
		}

		RecordHandle rh0 = null;
		try {
			rh0 = t_util.t_insertAtSlot(page, 0, r0, (byte) insertFlag);	
		} catch (StandardException se) {
			throw T_Fail.testFailMsg("insert of first long row failed.");
		}

		if (rh0 == null)
			throw T_Fail.testFailMsg("insert of a 60-column (300 bytes per column) row failed.");
		else {
			REPORT("about to check fetch the first long row inserted...");
			DataValueDescriptor column = new SQLChar();
			for (int i = 0; i < 60; i++) {
				t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, i, column, false, REC_001, 1200);
			}
		}

		// create a new row with 60 columns, and each column has REC_001 = "McLaren"
		for (int i = 0; i < 60; i++) {
			r0.setColumn(i, REC_001);
		}

		RecordHandle rh1 = null;
		try {
			rh1 = t_util.t_insertAtSlot(page, 1, r0, (byte) insertFlag);
		} catch (StandardException se) {
			throw T_Fail.testFailMsg("insert of second long row failed.");
		}

		if (rh1 == null) {
			throw T_Fail.testFailMsg("insert of a 60-column (~10 bytes per column) row failed.");
		} else {
			REPORT("about to check fetch the second long row inserted ...");
			DataValueDescriptor column = new SQLChar();
			for (int i = 0; i < 60; i++) {
				t_util.t_checkFetchColFromSlot(page, 1, i, column, false, REC_001);
			}
		}

		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);

		t.close();

		PASS("P032: segment = " + segment);
	}

	/**
		Insert 100-column long rows into 1K pages, each column is less than a page.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P033(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			t_util.t_checkEmptyPage(page);

			T_RawStoreRow r0 = new T_RawStoreRow(100);
			for (int i = 0; i < 100; i++) {
				r0.setColumn(i, REC_007);
			}

			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW;

			RecordHandle rh0 = null;
			try {
				rh0 = t_util.t_insertAtSlot(page, 0, r0, (byte) insertFlag);	
			} catch (StandardException se) {
				throw T_Fail.testFailMsg("insert of long row failed.");
			}

			if (rh0 == null) 
				throw T_Fail.testFailMsg("insert of first long row failed.");
			else {
				REPORT("about to check fetch...");
				DataValueDescriptor column = new SQLChar();
				for (int i = 0; i < 100; i++) {
					t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, i, column, false, REC_007);
				}
			}

			page.unlatch();
			page = null;
			if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
				t_util.t_dropContainer(t, segment, cid);	// cleanup
			}

		}
		finally
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}

		PASS("P033: segment = " + segment);
	}

	/**
		Insert 401 column long row with many small columns in the beginning,
		and one large column at the end into 4K pages.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P034(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			t_util.t_checkEmptyPage(page);

			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW;

			T_RawStoreRow r1 = new T_RawStoreRow(401);
			for (int i = 0; i < 400; i++)
				r1.setColumn(i, REC_001);
			r1.setColumn(400, 1500, REC_001);
			RecordHandle rh = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			t_util.t_checkFetch(page, rh, r1);
			page.unlatch();
			page = null;
			if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
				t_util.t_dropContainer(t, segment, cid);	// cleanup
			}

		}
		finally
		{
			if (page != null)
				page.unlatch();

			t_util.t_commit(t);
			t.close();
		}

		PASS("P034: segment = " + segment);
	}

	/**
		Insert a single long column long row into a 1K page.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P035(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			t_util.t_checkEmptyPage(page);

			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW;

			T_RawStoreRow r1 = new T_RawStoreRow(1);
			// insert a long column
			r1.setColumn(0, 500, REC_001);
			RecordHandle rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			t_util.t_checkFetch(page, rh1, r1);
			REPORT("row 1 inserted...");

			// insert a 6 column row, every other column is long
			T_RawStoreRow r2 = new T_RawStoreRow(6);
			r2.setColumn(0, 400, REC_001); // this takes 800 bytes
			r2.setColumn(1, 500, REC_002); // this takes 1000 bytes
			r2.setColumn(2, 400, REC_001);
			r2.setColumn(3, 500, REC_002);
			r2.setColumn(4, 400, REC_001);
			r2.setColumn(5, 500, REC_002);
			RecordHandle rh2 = t_util.t_insertAtSlot(page, 0, r2, (byte) insertFlag);	
			t_util.t_checkFetch(page, rh2, r2);
			REPORT("row 2 inserted...");

			// insert a long column
			r1.setColumn(0, 1500, REC_001);
			RecordHandle rh3 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			if (rh3 != null)
				throw T_Fail.testFailMsg("expect the 3rd row to not fit on page");

			page.unlatch();
			page = null;

			if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
				t_util.t_dropContainer(t, segment, cid);	// cleanup
			}

		}
		finally
		{
			if (page != null)
				page.unlatch();

			t_util.t_commit(t);
			t.close();
		}


		PASS("P035: segment = " + segment);
	}

	/**
		Test space reclaimation - purging of a long row gets back all
		the row pieces.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P036() throws StandardException, T_Fail
	{
		long segment = 0;
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			t_util.t_checkEmptyPage(page);

			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW;

			// insert a row with 400 columns from 200 to 400 bytes each and make it
			// sprawl across many pages.
			T_RawStoreRow r1 = new T_RawStoreRow(400);
			for (int i = 0; i < 400; i++)
				r1.setColumn(i, 100+i, REC_001);

			RecordHandle rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte)insertFlag);
			t_util.t_checkFetch(page, rh1, r1);

			Page nextPage = t_util.t_addPage(c);
			long nextPageNumber = nextPage.getPageNumber();
			// deallocate it
			t_util.t_removePage(c, nextPage);

			REPORT("P036 - Nextpage is " + nextPageNumber);
			page.unlatch();
			page = null;
			t_util.t_commit(t);

			// See what the next page is.
			c = t_util.t_openContainer(t, segment, cid, true);

			// Now purge that first row.
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkRecordCount(page, 1, 1);
			page.purgeAtSlot(0, 1, logDataForPurges);

			t_util.t_checkEmptyPage(page);
			page.unlatch();
			page = null;
			t_util.t_commit(t);

			// give some time for post commit to finish
			t_util.t_wait(10);		// wait 10 milliseconds.

			// reinsert r1, it should use no extra page than last time.
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			RecordHandle rh2 = t_util.t_insertAtSlot(page, 0, r1, (byte)insertFlag);
			t_util.t_checkFetch(page, rh2, r1);
			page.unlatch();
			page = null;

			// now verify that it used up no more page than last time
			nextPage = t_util.t_addPage(c);
			long checkNextPageNumber = nextPage.getPageNumber();
			nextPage.unlatch();

			if (nextPageNumber != checkNextPageNumber)
				throw T_Fail.testFailMsg("fail to reuse row pieces expect next page=" + 
					nextPageNumber + " but got " + checkNextPageNumber );


			t_util.t_commit(t);

			// Purge them and roll them back via savepoint.  These should not
			// be reclaimed.
			c = t_util.t_openContainer(t, segment, cid, true);
			t.setSavePoint(SP1, null);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			t_util.t_checkRecordCount(page, 1, 1);
			page.purgeAtSlot(0, 1, logDataForPurges);
			page.unlatch();
			page = null;

			// make sure we cannot get our hands on a page that is freed up by
			// the purge
			Page testPage = t_util.t_addPage(c);
			T_RawStoreRow testRow = new T_RawStoreRow(REC_001);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			t.rollbackToSavePoint(SP1, null);

			testPage = t_util.t_addPage(c);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			t_util.t_commit(t);
			t_util.t_wait(10);
			
			c = t_util.t_openContainer(t, segment, cid, true);

			testPage = t_util.t_addPage(c);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			//when container is in unlogged mode, the check is untru,
			//because rollback to save point would have done nothing.
			//so purge was not rolled back. The row does not exist any more
			if((openMode & ContainerHandle.MODE_UNLOGGED) == 0)
			{
				page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
				if(logDataForPurges)
				{
					t_util.t_checkFetch(page, rh2, r1);			
				}else
				{
					//when data is not logged for purges ,
					//in this particular first four columns becomes null becuase
					//first 4 fileds data are on the 1st page and do not get 
                    //logged during pruge and
					//the rest of the columns gets the data back because they
					//are removed page by page.
					T_RawStoreRow r1_wnl = new T_RawStoreRow(400);
					for (int i = 0; i < 18; i++)
						r1_wnl.setColumn(i, 4, REC_NULL);
					for (int i = 18; i < 400; i++)
						r1_wnl.setColumn(i, 100+i, REC_001);
					t_util.t_checkFetch(page, rh2, r1_wnl);		
				}
				page.unlatch();
				page = null;
			}


			t_util.t_dropContainer(t, segment, cid);	// cleanup

		}
		finally	
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}

		PASS("P036");
	}


	/**
		Test space reclaimation - purging of a row with serveral long columns
		get back all the column chains.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P037() throws StandardException, T_Fail
	{
		// Insert the 3 rows in P035, then purge them and reinsert them and
		// make sure it reuses all the pages from last time.

		long segment = 0;
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			t_util.t_checkEmptyPage(page);

			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW;
			T_RawStoreRow r1 = new T_RawStoreRow(1);
			// insert a long column
			r1.setColumn(0, 5500, REC_001);
			RecordHandle rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			t_util.t_checkFetch(page, rh1, r1);

			// insert a 6 column row, every other column is long, sizes 
            // picked so that 2 rows fit, but 3rd row won't fit even if whole
            // row is overflowed.
			T_RawStoreRow r2 = new T_RawStoreRow(6);
			r2.setColumn(0, 660, REC_001); // this takes ~1320 bytes
			r2.setColumn(1, 5000, REC_002); // this takes ~10000 bytes
			r2.setColumn(2, 660, REC_001);
			r2.setColumn(3, 5000, REC_002);
			r2.setColumn(4, 660, REC_001);
			r2.setColumn(5, 5000, REC_002);
			RecordHandle rh2 = t_util.t_insertAtSlot(page, 0, r2, (byte) insertFlag);	
			t_util.t_checkFetch(page, rh2, r2);


			// insert a long column - this should fail
			RecordHandle rh3 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			if (rh3 != null)
            {
                throw T_Fail.testFailMsg("expect the 3rd row to not fit on page");
            }

			page.unlatch();
			page = null;

			Page nextPage = t_util.t_addPage(c);
			long nextPageNumber = nextPage.getPageNumber();
			// deallocate it
			t_util.t_removePage(c, nextPage);

			REPORT("P037 - Nextpage is " + nextPageNumber);

			t_util.t_commit(t);

			// now purge them
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkRecordCount(page, 2, 2);
			page.purgeAtSlot(0, 2, logDataForPurges);
			t_util.t_checkEmptyPage(page);
			page.unlatch();
			page = null;

			t_util.t_commit(t);

			// give some time for post commit to finish
			t_util.t_wait(10);		// wait 10 milliseconds.

			// reinsert all 3 of them again, exactly the same way.
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			rh2 = t_util.t_insertAtSlot(page, 0, r2, (byte) insertFlag);	
			rh3 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			t_util.t_checkFetch(page, rh1, r1);
			t_util.t_checkFetch(page, rh2, r2);
			if (rh3 != null)
				throw T_Fail.testFailMsg("expect the 3rd row to not fit on page");
			page.unlatch();
			page = null;

			nextPage = t_util.t_addPage(c);
			long checkNextPageNumber = nextPage.getPageNumber();
			nextPage.unlatch();

			if (nextPageNumber != checkNextPageNumber)
				throw T_Fail.testFailMsg("fail to reuse row pieces expect next page=" + 
					 nextPageNumber + " but got " + checkNextPageNumber );

			t_util.t_commit(t);

			// Purge them and roll them back via savepoint.  These should not
			// be reclaimed.
			c = t_util.t_openContainer(t, segment, cid, true);

			t.setSavePoint(SP1, null);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			
			t_util.t_checkRecordCount(page, 2, 2);
			page.purgeAtSlot(0, 2, logDataForPurges);
			t_util.t_checkEmptyPage(page);

			page.unlatch();
			page = null;

			// make sure we cannot get our hands on a page that is freed up by
			// the purge
			Page testPage = t_util.t_addPage(c);
			T_RawStoreRow testRow = new T_RawStoreRow(REC_001);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			t.rollbackToSavePoint(SP1, null);

			testPage = t_util.t_addPage(c);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			t_util.t_commit(t);

			// give some time for post commit to finish
			t_util.t_wait(10);

			// check to make sure post commit did not reclaim those rows.
			c = t_util.t_openContainer(t, segment, cid, true);

			testPage = t_util.t_addPage(c);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			
			t_util.t_checkRecordCount(page, 2, 2);
			t_util.t_checkFetch(page, rh1, r1);
		
			if(logDataForPurges)
				t_util.t_checkFetch(page, rh2, r2);
			else{
				
				// During purges when data is not logged when slots are purged
				// they become null on rollback and some cases like long columns
				// we remove the wholepage on rollback we get the data back.
				T_RawStoreRow r2_wnl = new T_RawStoreRow(6);
				r2_wnl.setColumn(0, 4, REC_NULL); 
				r2_wnl.setColumn(1, 5000, REC_002); 
				r2_wnl.setColumn(2, 4, REC_NULL);
				r2_wnl.setColumn(3, 5000, REC_002);
				r2_wnl.setColumn(4, 4, REC_NULL);
				r2_wnl.setColumn(5, 5000, REC_002);
				t_util.t_checkFetch(page, rh2, r2_wnl);
			}
				
			page.unlatch();
			page = null;

			t_util.t_dropContainer(t, segment, cid);	// cleanup

		}
		finally
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}

		PASS("P037");

	}

	/**
		Test space reclaimation - rollback of an insert (with purge) of a row
		that overflows and with long column get back all the space in the row
		and column chain. 

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P038() throws StandardException, T_Fail
	{
		long segment = 0;

		// Insert the 3 rows in P035, then abort the insert.
		// Reinsert them and make sure it reuses all the pages from last time. 
		Transaction t = t_util.t_startTransaction();		
		long cid = t_util.t_addContainer(t, segment, 4096);
		t_util.t_commit(t);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			t_util.t_checkEmptyPage(page);

			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW |
				Page.INSERT_UNDO_WITH_PURGE; 

			T_RawStoreRow r1 = new T_RawStoreRow(1);
			// insert a long column
			r1.setColumn(0, 1500, REC_001);
			RecordHandle rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	

			// insert a 6 column row, every other column is long
			T_RawStoreRow r2 = new T_RawStoreRow(6);
			r2.setColumn(0, 400, REC_001); // this takes ~800 bytes
			r2.setColumn(1, 500, REC_002); // this takes ~1000 bytes
			r2.setColumn(2, 400, REC_001);
			r2.setColumn(3, 500, REC_002);
			r2.setColumn(4, 400, REC_001);
			r2.setColumn(5, 500, REC_002);
			RecordHandle rh2 = t_util.t_insertAtSlot(page, 0, r2, (byte) insertFlag);	

			// insert a long column
			RecordHandle rh3 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			if (rh3 != null)
				throw T_Fail.testFailMsg("expect the 3rd row to not fit on page");
			page = null;

			Page nextPage = t_util.t_addPage(c);
			long nextPageNumber = nextPage.getPageNumber();
			// deallocate it
			t_util.t_removePage(c, nextPage);

			REPORT("P038 - Nextpage is " + nextPageNumber);

			t_util.t_abort(t);

			// the abort rolled back the removal of nextPage also, redo the removed
			c = t_util.t_openContainer(t, segment, cid, true);		
			nextPage = t_util.t_getPage(c, nextPageNumber);
			t_util.t_removePage(c, nextPage);
			t_util.t_commit(t);

			// reinsert the 3 rows, they should not take up any more space than
			// last time.
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkEmptyPage(page);

			rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			rh2 = t_util.t_insertAtSlot(page, 0, r2, (byte) insertFlag);	
			rh3 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
		
			t_util.t_checkFetch(page, rh1, r1);
			t_util.t_checkFetch(page, rh2, r2);
			if (rh3 != null)
				throw T_Fail.testFailMsg("expect the 3rd row to not fit on page");

			page.unlatch();
			page = null;

			nextPage = t_util.t_addPage(c);
			long checkNextPageNumber = nextPage.getPageNumber();
			nextPage.unlatch();


			if (nextPageNumber != checkNextPageNumber)
				throw T_Fail.testFailMsg("fail to reuse row pieces expect next page=" + 
					nextPageNumber + " but got " + checkNextPageNumber );

			t_util.t_dropContainer(t, segment, cid);	// cleanup

		}
		finally	
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}

		PASS("P038");
	}

	/**
		Test space reclaimation - shrink a head row piece.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P039() throws StandardException, T_Fail
	{
		// insert 3 2K rows of 3 columns,  size (100, 1500, 400), into an 8K
		// page, then fill up the page with 1K rows.  
		// 
		// 1. Update the first 2K row so that the 2nd and 3rd column gets moved
		// to another page.  See that we can insert at least 1 more 1K row into
		// the page.
		// 
		// 2. Update the second 2K row so that the 2nd column becomes a long
		// column.  See that we can insert at least 1 more 1K row into the
		// page. 
		//
		// 3. Update the third 2K row so that the column size shrinks to (200,
		// 200, 200).  See that we can insert at least 1 more 1K row into the
		// page.

		long segment = 0;
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, segment, 8*1024);

		T_RawStoreRow bigRow = new T_RawStoreRow(3);
		bigRow.setColumn(0,  50, REC_001); // remember each char takes 2 bytes
		bigRow.setColumn(1, 750, REC_002);
		bigRow.setColumn(2, 200, REC_003);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			RecordHandle rh1 = t_util.t_insert(page, bigRow);
			RecordHandle rh2 = t_util.t_insert(page, bigRow);
			RecordHandle rh3 = t_util.t_insert(page, bigRow);

			t_util.t_checkFetch(page, rh1, bigRow);
			t_util.t_checkFetch(page, rh2, bigRow);
			t_util.t_checkFetch(page, rh3, bigRow);

			// now fill up the page with smaller rows
			T_RawStoreRow smallRow = new T_RawStoreRow(1);
			smallRow.setColumn(0, 500, REC_004);

			while(page.spaceForInsert())
			{
				if (t_util.t_insert(page, smallRow) == null)
					break;
			}
			REPORT("P039: " + (page.recordCount()-3) + " small rows have been inserted");
			page.unlatch();
			page = null;

			t_util.t_commit(t);
		
			// (1) update rh1 so that column 2 and 3 are moved off page
			bigRow.setColumn(1, 2000, REC_005);
			c = t_util.t_openContainer(t, segment, cid, true);

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			int slot1 = page.getSlotNumber(rh1);
			page.updateAtSlot(slot1, bigRow.getRow(), null);
			t_util.t_checkFetch(page, rh1, bigRow);
			page.unlatch();
			page = null;
			t_util.t_commit(t);

			t_util.t_wait(10);		// wait for post commit to get processed.

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			if (t_util.t_insert(page, smallRow) == null)
				throw T_Fail.testFailMsg("expect row to have shrunk (1)");

			// fill it up again 
			while(page.spaceForInsert())
			{
				if (t_util.t_insert(page, smallRow) == null)
					break;
			}
			REPORT("P039: " + (page.recordCount()-3) + " small rows have been inserted");
			
			page.unlatch();
			page = null;

			t_util.t_commit(t);

			// (2) update rh2 so that column 2 becomes a long column
			FormatableBitSet colList = new FormatableBitSet(2);
			colList.set(1);			// update column 1, the second column
            // use sparse rows
			T_RawStoreRow partialRow = new T_RawStoreRow(2);
			partialRow.setColumn(1, 8000, REC_006);

			c = t_util.t_openContainer(t, segment, cid, true);

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			int slot2 = page.getSlotNumber(rh2);
			page.updateAtSlot(slot2, partialRow.getRow(), colList);

			bigRow.setColumn(1, 8000, REC_006);
			t_util.t_checkFetch(page, rh2, bigRow);
			page.unlatch();
			page = null;
			t_util.t_commit(t);

			t_util.t_wait(10);		// wait for post commit to get processed.

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			if (t_util.t_insert(page,smallRow) == null)
				throw T_Fail.testFailMsg("expect row to have shrunk (2)");

			// fill it up again 
			while(page.spaceForInsert())
			{
				if (t_util.t_insert(page, smallRow) == null)
					break;
			}
			REPORT("P039: " + (page.recordCount()-3) + " small rows have been inserted");

			page.unlatch();
			page = null;

			t_util.t_commit(t);

			// (3) - update rh3 to have (200, 400, 400) bytes columns
			bigRow.setColumn(0, 100, REC_001);
			bigRow.setColumn(1, 200, REC_002);
			bigRow.setColumn(2, 200, REC_003);

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			int slot3 = page.getSlotNumber(rh3);
			page.updateAtSlot(slot3, bigRow.getRow(), null);
			t_util.t_checkFetch(page, rh3, bigRow);
			page.unlatch();
			page = null;
			t_util.t_commit(t);

			t_util.t_wait(10);		// wait for post commit to get processed.

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			if (t_util.t_insert(page,smallRow) == null)
				throw T_Fail.testFailMsg("expect row to have shrunk (3)");
			page.unlatch();
			page = null;

			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}
		finally	
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}

		PASS("P039");
	}

	/**
		Test space reclaimation - shrink a non head row piece.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P040() throws StandardException, T_Fail
	{
		// Manufacture a row that has a small head row piece, a large 2nd row
		// piece and a small third row piece.
		// Using the same head page, add a second row that has a small head row
		// piece and a medium sized 2nd row piece, a new overflow page should
		// be allocated.
		// Update the first row to now have a small 2nd row piece.
		// Using the same head page, add a third row that has a small head row
		// piece and a medium sized 2nd row piece, no new overflow page should
		// be allocated.

		long segment = 0;
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, 0, 4096);
		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);

		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW |
				Page.INSERT_UNDO_WITH_PURGE;

			T_RawStoreRow row1 = new T_RawStoreRow(3);
			row1.setColumn(0, 400, REC_001);
			row1.setColumn(1, 800, REC_002); // this takes ~1600 bytes
			row1.setColumn(2, 400, REC_003);
			RecordHandle rh1 = t_util.t_insertAtSlot(page, 0, row1, (byte)insertFlag);

			t_util.t_checkFetch(page, rh1, row1);

			page.unlatch();
			page = null;
			t_util.t_commit(t);

			c = t_util.t_openContainer(t, segment, cid, true);
			Page nextPage = t_util.t_addPage(c);

			// remember where next page is
			long nextPageNumber = nextPage.getPageNumber();
			t_util.t_removePage(c, nextPage);
			t_util.t_commit(t);

			T_RawStoreRow row2 = new T_RawStoreRow(3);
			row2.setColumn(0, 1200, REC_001);
			row2.setColumn(1, 1200, REC_002);
			row2.setColumn(2, 400, REC_003);

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			RecordHandle rh2 = t_util.t_insertAtSlot(page, 1, row2, (byte)insertFlag);

			t_util.t_checkFetch(page, rh2, row2);
			page.unlatch();
			page = null;

			// this should have allocated more overflow page
			nextPage = t_util.t_addPage(c);
			long checkNextPageNumber = nextPage.getPageNumber();
			if (checkNextPageNumber == nextPageNumber)
				throw T_Fail.testFailMsg("expected to allocate more pages");
			t_util.t_removePage(c, nextPage);
			t_util.t_commit(t);

			// now this is the next free page
			nextPageNumber = checkNextPageNumber;

			// shrink first row 2nd column, and second row 1st column so we
			// have space on both the first and the second page on the row
			// chain.
            // use sparse rows
			T_RawStoreRow partialRow = new T_RawStoreRow(2);
			partialRow.setColumn(1, 400, REC_004);

			T_RawStoreRow partialRow2 = new T_RawStoreRow(2);
			partialRow2.setColumn(0, 400, REC_004);

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			FormatableBitSet colList = new FormatableBitSet(2);
			colList.set(1);		// update first row column 1, the second column
			int slot1 = page.getSlotNumber(rh1);
			page.updateAtSlot(slot1, partialRow.getRow(), colList);

			colList.clear(1);
			colList.set(0);		// update second row column 0, the first column
			int slot2 = page.getSlotNumber(rh2);
			page.updateAtSlot(slot2, partialRow2.getRow(), colList);

			// verify the update worked.
			row1.setColumn(1, 400, REC_004);
			row2.setColumn(0, 400, REC_004);
			t_util.t_checkFetch(page, rh1, row1);
			t_util.t_checkFetch(page, rh2, row2);

			page.unlatch();
			page = null;

			t_util.t_commit(t);
			t_util.t_wait(10);	// give post commit a chance to work

			// We think the head row should have 2 200 bytes row.
			// One of the overflow row piece chain has an overflow page with a
			// 200 bytes row followed by another overflow page with a 200 bytes
			// row.
			// The other overflow row piece should have 1 600 bytes row and no
			// other overflow page.
			T_RawStoreRow row3 = new T_RawStoreRow(2);
			row3.setColumn(0, 400, REC_001);
			row3.setColumn(1, 800, REC_002);
			// We think this should select the first overflow chain.
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			if (!page.spaceForInsert())
				throw T_Fail.testFailMsg("No space for insert after shrink row");

			RecordHandle rh3 = t_util.t_insertAtSlot(page, 1, row3, (byte)insertFlag);
			t_util.t_checkFetch(page, rh3, row3);

			page.unlatch();
			page = null;

			// this should not allocate more overflow pages
			nextPage = t_util.t_addPage(c);
			checkNextPageNumber = nextPage.getPageNumber();
			if (checkNextPageNumber != nextPageNumber)
				throw T_Fail.testFailMsg("not expected to allocate more pages "
										 + nextPageNumber + "," + checkNextPageNumber);

			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}
		finally
		{
			if (page != null)
				page.unlatch();

			t_util.t_commit(t);
			t.close();
		}
		PASS("P040");
	}

	/**
		Test space reclaimation - update a long column to another long column.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P041() throws StandardException, T_Fail
	{
		// Make a row with several long columns, on different row pieces.
		// Update these long columns - to other long columns or to short
		// columns.  Remember what the next page is.
		// Update these long columns to the original long column (in length),
		// we shouldn't be adding any more pages.

		long segment = 0;
		Transaction t = t_util.t_startTransaction();		
		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			t_util.t_checkEmptyPage(page);

			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW;

			// insert a 6 column row, every other column is long
			T_RawStoreRow r1 = new T_RawStoreRow(6);
			r1.setColumn(0, 400, REC_001); // this takes ~800 bytes
			r1.setColumn(1, 500, REC_002); // this takes ~1000 bytes
			r1.setColumn(2, 400, REC_001);
			r1.setColumn(3, 500, REC_002);
			r1.setColumn(4, 400, REC_001);
			r1.setColumn(5, 500, REC_002);
			RecordHandle rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			t_util.t_checkFetch(page, rh1, r1);

			// update column 0,1,2 to short columns, columns 3, 4, 5 to other
			// long columns.
			T_RawStoreRow r2 = new T_RawStoreRow(6);
			r2.setColumn(0, 100, REC_003);
			r2.setColumn(1, 100, REC_004);
			r2.setColumn(2, 100, REC_003);
			r2.setColumn(3, 500, REC_005);
			r2.setColumn(4, 500, REC_006);
			r2.setColumn(5, 500, REC_005);

			int slot1 = page.getSlotNumber(rh1);
			page.updateAtSlot(slot1, r2.getRow(), null);
			t_util.t_checkFetch(page, rh1, r2);

			page.unlatch();
			page = null;

			Page nextpage = t_util.t_addPage(c);
			long nextPageNumber = nextpage.getPageNumber();
			t_util.t_removePage(c, nextpage);

			t_util.t_commit(t);
			t_util.t_wait(10);	// let post commit work
			
			// now update to original long rows, should not take any more
			// space.
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			t_util.t_checkFetch(page, rh1, r2);
			
			t.setSavePoint(SP1, null);

			slot1 = page.getSlotNumber(rh1);
			page.updateAtSlot(slot1, r1.getRow(), null);
			t_util.t_checkFetch(page, rh1, r1);
			page.unlatch();
			page = null;

			nextpage = t_util.t_addPage(c);
			long checkNextPageNumber = nextpage.getPageNumber();
			nextpage.unlatch();
			if (checkNextPageNumber != nextPageNumber)
				throw T_Fail.testFailMsg("expect next page to be unchanged");

			// now roll back the update via savepoint.
			t.rollbackToSavePoint(SP1, null);

			t_util.t_commit(t);
			t_util.t_wait(10);	// make sure post commit don't 
								// reclaim things that are not garbage.

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			t_util.t_checkFetch(page, rh1, r2);
			page.unlatch();
			page = null;

			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}
		finally
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}

		PASS("P041");

	}

	/**
		Test space reclaimation - rollback of an update that create a long
		column. 

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P042() throws StandardException, T_Fail
	{
		// Make a row with a short column.  Remember the next page.
		// Update it to a long column, roll back.  See that the next page goes
		// back to before the update.
		//
		// Update the row so that it overflows to another page and have long
		// column there.  Remember the next page.  Update the long column to
		// another long column.  Rollback the update.  See that the next page
		// goes back to before the update.
		// 
		long segment = 0;
		Transaction t = t_util.t_startTransaction();		
		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		try
		{
			T_RawStoreRow smallRow = new T_RawStoreRow(REC_001);
			RecordHandle rh1 = t_util.t_insert(page, smallRow);
			t_util.t_commit(t);

			c = t_util.t_openContainer(t, segment, cid, true);
			Page nextPage = t_util.t_addPage(c);
			long nextPageNumber = nextPage.getPageNumber();
			// deallocate it
			t_util.t_removePage(c, nextPage);
			t_util.t_commit(t);			

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			T_RawStoreRow bigRow = new T_RawStoreRow(1);
			bigRow.setColumn(0, 6400, REC_001);
			int slot1 = page.getSlotNumber(rh1);
			page.updateAtSlot(slot1, bigRow.getRow(), null);
			t_util.t_checkFetch(page,rh1, bigRow);
			page.unlatch();
			page = null;

			Page checkGrow = t_util.t_addPage(c);
			long checkGrowPageNumber = checkGrow.getPageNumber();
			if (checkGrowPageNumber == nextPageNumber)
				throw T_Fail.testFailMsg("expect to have allocated more pages");
			t_util.t_removePage(c, checkGrow);

			t_util.t_abort(t);

			t_util.t_wait(10);
			c = t_util.t_openContainer(t, segment, cid, true);

			// the abort rolled back the removePage, remove it again.
			checkGrow = t_util.t_getPage(c, checkGrowPageNumber);
			t_util.t_removePage(c, checkGrow);

			nextPage = t_util.t_addPage(c);
			if (nextPage.getPageNumber() != nextPageNumber)
				throw T_Fail.testFailMsg(
				"rollback of update to long column did not release the long column chain pages");

			t_util.t_removePage(c, nextPage);
			t_util.t_commit(t);

			T_RawStoreRow row2 = new T_RawStoreRow(6);
			row2.setColumn(0, 1600, REC_001); // this takes ~3200 bytes
			row2.setColumn(1, 2000, REC_002); // this takes ~4000 bytes
			row2.setColumn(2, 1600, REC_001);
			row2.setColumn(3, 2000, REC_002);
			row2.setColumn(4, 1600, REC_001);
			row2.setColumn(5, 2000, REC_002);

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t.setSavePoint(SP1, null);
			slot1 = page.getSlotNumber(rh1);
			page.updateAtSlot(slot1, row2.getRow(), null);

			nextPage = t_util.t_addPage(c);
			nextPageNumber = nextPage.getPageNumber();
			t_util.t_removePage(c, nextPage);			

			t.rollbackToSavePoint(SP1, null); // this should free up some pages

			nextPage = t_util.t_getPage(c, nextPageNumber);
			t_util.t_removePage(c, nextPage);			

			t_util.t_commit(t);	
			t_util.t_wait(10);

			c = t_util.t_openContainer(t, segment, cid, true);
			Page checkNextPage = t_util.t_addPage(c);
			if (checkNextPage.getPageNumber() == nextPageNumber)
				throw T_Fail.testFailMsg(
					"expect some pages to be freed by update rollback");
			t_util.t_removePage(c, checkNextPage);
			t_util.t_commit(t);

			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			t_util.t_checkFetch(page, rh1, smallRow);

			// update row so that it has overflow rows and long columns
			slot1 = page.getSlotNumber(rh1);
			page.updateAtSlot(slot1, row2.getRow(), null);

			// remember the next page
			nextPage = t_util.t_addPage(c);
			nextPageNumber = nextPage.getPageNumber();
			t_util.t_removePage(c, nextPage);

			t_util.t_commit(t);

			// now update columns 0, 1, 4  to long columns and roll it back. 
			T_RawStoreRow row3 = new T_RawStoreRow(5);
			row3.setColumn(0, 4000, REC_003);
			row3.setColumn(1, 4000, REC_004);
			row3.setColumn(2, REC_001);
			row3.setColumn(3, REC_001);
			row3.setColumn(4, 4000, REC_003);
			
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			slot1 = page.getSlotNumber(rh1);
			page.updateAtSlot(slot1, row3.getRow(), null);
			t_util.t_checkFetch(page, rh1, row3);
			page.unlatch();
			page = null;

			t_util.t_abort(t);
			t_util.t_wait(10);

			c = t_util.t_openContainer(t, segment, cid, true);
			nextPage = t_util.t_addPage(c);
			if (nextPage.getPageNumber() != nextPageNumber)
				throw T_Fail.testFailMsg("expect pages to be freed by update rollback");
			nextPage.unlatch();

			t_util.t_dropContainer(t, segment, cid);
		}
		finally	
		{
			if (page != null && page.isLatched())
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}
		PASS("P042");

	}

	/**
		Test space reclaimation - rollback of an update that create a new row
		piece. 
	 */
	protected void P043()
	{
		// this space cannot be reclaimed.
	}


	/** 
		Test that post commit processor does not stubbify a drop table that is
		rolled back in a savepoint
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/
	protected void P050()
		 throws StandardException, T_Fail
	{
		if (!testRollback)
			return;

		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t,0);
		t_util.t_commit(t);

		t.setSavePoint(SP1, null);

		t.dropContainer(new ContainerKey(0, cid));
		t.rollbackToSavePoint(SP1, null);

		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
		t_util.t_addPage(c);
		t_util.t_commit(t);

		long cid2 = t_util.t_addContainer(t, 0);
		c = t_util.t_openContainer(t, 0, cid2, true);
		t_util.t_addPage(c);
		t_util.t_addPage(c);
		t_util.t_addPage(c);
		t_util.t_addPage(c);
		t_util.t_commit(t);

		c = t_util.t_openContainer(t, 0, cid, false); // it should not be stubbified...

		PASS("P050");

		t_util.t_dropContainer(t, 0, cid);	// cleanup - commit it for real
		t_util.t_dropContainer(t, 0, cid2);	// cleanup - commit it for real

		t_util.t_commit(t);
		t.close();

	}

	/**
		Test rollback of Page.insert
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/
	protected void P051()
		 throws StandardException, T_Fail
	{
		if (!testRollback)
			return;

		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t,0);
		t_util.t_commit(t);


		T_RawStoreRow row = new T_RawStoreRow(REC_001);
		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// first insert and check that an abort leaves the row there
		RecordHandle rh1 = t_util.t_insert(page, row);

		t_util.t_commit(t);

		c = t_util.t_openContainer(t, 0, cid, true);

		t_util.t_checkFetch(c, rh1, REC_001);

		row = new T_RawStoreRow(REC_002);

		RecordHandle rh2 = t_util.t_insert(c, row);

		t_util.t_checkFetch(c, rh1, REC_001);
		t_util.t_checkFetch(c, rh2, REC_002);

		t_util.t_abort(t);

		c = t_util.t_openContainer(t, 0, cid, true);
		t_util.t_checkFetch(c, rh1, REC_001);

		page = t_util.t_getPage(c, rh2.getPageNumber());
		if (page.recordExists(rh2, false)) {
			throw T_Fail.testFailMsg("record insert was not undone");
		}
		page.unlatch();

		PASS("P051");

		t_util.t_dropContainer(t, 0, cid);	// cleanup

		t_util.t_commit(t);
		t.close();
	}

	/**
		Test insertAtSlot that rolls back with a purge

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/
	protected void P053()
		 throws StandardException, T_Fail
	{
		if (!testRollback)
			return;
		Transaction t = t_util.t_startTransaction();

		try
		{
			long cid = t_util.t_addContainer(t,0);
			t_util.t_commit(t);

			
			ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
			Page page = t_util.t_addPage(c);

			T_RawStoreRow row0 = new T_RawStoreRow(REC_001);
			T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
			T_RawStoreRow row2 = new T_RawStoreRow(REC_002);
			T_RawStoreRow row3 = new T_RawStoreRow(REC_003);
			T_RawStoreRow row4 = new T_RawStoreRow(REC_004);
			
			t_util.t_insertAtSlot(page, 0, row0, Page.INSERT_UNDO_WITH_PURGE);

			if (t_util.t_insertAtSlot(page, 1, row1) == null)
				return;

			if (t_util.t_insertAtSlot(page, 2, row2, Page.INSERT_UNDO_WITH_PURGE) == null)
				return;

			if (t_util.t_insertAtSlot(page, 3, row3) == null)
				return;
	
			if (t_util.t_insertAtSlot(page, 4, row4, Page.INSERT_UNDO_WITH_PURGE) == null)
				return;
	
			int fillerRows = 0;
			while (page.spaceForInsert())
			{
				t_util.t_insertAtSlot(page, 4, row4);
				fillerRows++;
			}

			t_util.t_checkRecordCount(page, fillerRows + 5, fillerRows + 5);
			t_util.t_abort(t);

			c = t_util.t_openContainer(t, 0, cid, true);
			page = t_util.t_getLastPage(c);

			// 2 + fillerRows deleted, 3 purged, 0 nondeleted
			t_util.t_checkRecordCount(page, 2 + fillerRows, 0);

			// since I just purged them, there must be space for re-inserting them
			t_util.t_insert(page, row0);
			t_util.t_insert(page, row2);
			t_util.t_insert(page, row4);

			t_util.t_checkRecordCount(page, 5 + fillerRows, 3);

			page.unlatch();
			PASS("P053");

			t_util.t_dropContainer(t, 0, cid);	// cleanup
		}
		finally
		{
			t_util.t_commit(t);
			t.close();
		}
	}

	/**
		Test internal transaction 

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/
	protected void P054()
		 throws StandardException, T_Fail
	{
		if (!testRollback)
			return;

		ContextManager previousCM = contextService.getCurrentContextManager();

		ContextManager cm1 = contextService.newContextManager();
		contextService.setCurrentContextManager(cm1);

		Transaction tuser = t_util.t_startTransaction();
		Transaction tinternal = null;

		try
		{

			long cid1 = t_util.t_addContainer(tuser, 0);
			ContainerHandle c1 = t_util.t_openContainer(tuser, 0, cid1, true);
			Page p1 = t_util.t_addPage(c1);
			t_util.t_commit(tuser);

			// insert a row using user transaction 
			T_RawStoreRow row = new T_RawStoreRow(REC_001);

			c1 = t_util.t_openContainer(tuser, 0, cid1, true);
			p1 = t_util.t_getLastPage(c1);
			RecordHandle r1 = t_util.t_insert(p1, row);

			REPORT("starting internal transaction");

			tinternal = t_util.t_startInternalTransaction();
			long cid2 = t_util.t_addContainer(tinternal, 0);
			ContainerHandle c2 = t_util.t_openContainer(tinternal, 0, cid2, true);
			Page p2 = t_util.t_addPage(c2);
			RecordHandle r2 = t_util.t_insert(p2, row);

			// commit internal transaction
			tinternal.commit();
			tinternal.abort();	// this will close the container and release
								// the page
			tinternal.close();
			tinternal = null;

			REPORT("commit internal transaction");

			// abort user transaction
			t_util.t_abort(tuser);

			REPORT("rollback user transaction");

			c1 = t_util.t_openContainer(tuser, 0, cid1, true);

			p1 = t_util.t_getPage(c1, r1.getPageNumber());
			if (p1.recordExists(r1, false))
				throw T_Fail.testFailMsg("user transaction failed to rollback");


			c2 = t_util.t_openContainer(tuser, 0, cid2, true);
			t_util.t_checkFetch(c2, r2, REC_001); // this should be unaffected by the
										 // user transaction rollback
			p2 = t_util.t_getLastPage(c2);

			T_RawStoreRow row2 = new T_RawStoreRow(REC_002);

			if (!p2.spaceForInsert())
			{
				REPORT("P054 not run, page cannot accomodate 2 rows");
				return;
			}
			RecordHandle r21 = t_util.t_insert(p2, row2);

			// throw an exception, make sure everything is aborted.
			tinternal = t_util.t_startInternalTransaction();
			long cid3 = t_util.t_addContainer(tinternal, 0);
			ContainerHandle c3 = t_util.t_openContainer(tinternal, 0, cid3, true);
			Page p3 = t_util.t_addPage(c3);
			RecordHandle r3 = t_util.t_insert(p3, row);
			try
			{
				// this will throw a data statement exception
				t_util.t_insertAtSlot(p3, 100, row);
			}
			catch (StandardException se)
			{
				REPORT("cleanup on error");
                //Assume database is not active. DERBY-4856 thread dump
                cm1.cleanupOnError(se, false);
				REPORT("done cleanup on error");
			}

			tinternal = null;
			// 	tuser = t_util.t_startTransaction();
			c2 = t_util.t_openContainer(tuser, 0, cid2, true);
			t_util.t_checkFetch(c2, r2, REC_001);

			p2 = t_util.t_getPage(c2, r21.getPageNumber());
			if (p2.recordExists(r21, false))
				throw T_Fail.testFailMsg("expect user transaction to rollback");

			// this should fail
			ContainerKey id3 = new ContainerKey(0, cid3);
			c3 = tuser.openContainer(id3, ContainerHandle.MODE_READONLY);
			if (c3 != null)
				throw T_Fail.testFailMsg("expect internal transaction to rollback");

			LockingPolicy nolock =
                tuser.newLockingPolicy(LockingPolicy.MODE_NONE, 0, false);

			RawContainerHandle stub =
				((RawTransaction)tuser).openDroppedContainer(
					id3, nolock);

			if (stub == null)
				throw T_Fail.testFailMsg("expect container to be dropped");

			if (stub.getContainerStatus() != RawContainerHandle.COMMITTED_DROP)
				throw T_Fail.testFailMsg("expect container to be committed dropped");

			// this should fail
			p3 = stub.getPage(r3.getPageNumber());

			if (p3 != null)
				throw T_Fail.testFailMsg("should not getpage with committed dropped container");

			PASS("P054");


			t_util.t_dropContainer(tuser, 0, cid2); // cleanup
			t_util.t_dropContainer(tuser, 0, cid1); // cleanup

			if (tinternal != null)
			{
				t_util.t_abort(tinternal);
				tinternal.close();
			}

			if (tuser != null)
			{
				t_util.t_commit(tuser);
				tuser.close();
			}
		}
		finally
		{

			contextService.resetCurrentContextManager(cm1);
		}

	}


	/**
        Test rollback of partial row update.
        Create a long row with 10 columns on 2 pages (5 columns on each page).
        Update the 1st column on the 2nd page (the 6th column) which causes the
        last column (10th column) to move off the page. Then abort and make sure
        that all the original columns are there and correct.

        NOTE: stored length is twice string length + 2

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P055(long segment) throws StandardException, T_Fail {

		if (!testRollback)
			return;

		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

        int colSize = 90;
		T_RawStoreRow r0 = new T_RawStoreRow(10);
		r0.setColumn(0, colSize, REC_001);
		r0.setColumn(1, colSize, REC_002);
		r0.setColumn(2, colSize, REC_003);
		r0.setColumn(3, colSize, REC_004);
		r0.setColumn(4, colSize, REC_005);
		r0.setColumn(5, colSize, REC_009);
        r0.setColumn(6, colSize, REC_010);
		r0.setColumn(7, colSize, REC_011);
        r0.setColumn(8, colSize, REC_012);
		r0.setColumn(9, colSize, REC_013);

		int insertFlag = Page.INSERT_INITIAL;
		insertFlag |= Page.INSERT_OVERFLOW;

		RecordHandle rh0 = null;
		try {
			rh0 = t_util.t_insertAtSlot(page, 0, r0, (byte) insertFlag);
		} catch (StandardException se) {
			throw T_Fail.testFailMsg("insert of long row failed.");
		}

		if (rh0 == null)
			throw T_Fail.testFailMsg("insert of first long row failed.");
		else {
			REPORT("about to check fetch...");
			DataValueDescriptor column = new SQLChar();
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 0, column, false, REC_001, colSize);
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 1, column, false, REC_002, colSize);
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 2, column, false, REC_003, colSize);
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 3, column, false, REC_004, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 4, column, false, REC_005, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 5, column, false, REC_009, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 6, column, false, REC_010, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 7, column, false, REC_011, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 8, column, false, REC_012, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 9, column, false, REC_013, colSize);
		}

   		t_util.t_commit(t);


        // update col 5 (the 6th column, the first column on the 2nd overflow page), which causes
        // the last column (col 9, the 10th column) to move off the page.

        c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		T_RawStoreRow updateRow = new T_RawStoreRow(10);
		for (int i = 0; i < 10; i++)
			updateRow.setColumn(i, (String) null);
        updateRow.setColumn(5, colSize*2, REC_009);
		FormatableBitSet colList = new FormatableBitSet(10);
		colList.set(5);
		page.updateAtSlot(0, updateRow.getRow(), colList);

        REPORT("about to check fetch after update ...");
        DataValueDescriptor column = new SQLChar();
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 0, column, false, REC_001, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 1, column, false, REC_002, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 2, column, false, REC_003, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 3, column, false, REC_004, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 4, column, false, REC_005, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 5, column, false, REC_009, colSize*2);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 6, column, false, REC_010, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 7, column, false, REC_011, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 8, column, false, REC_012, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 9, column, false, REC_013, colSize);
        page.unlatch();

        t_util.t_abort(t);

        REPORT("about to check fetch after abort ...");
		c = t_util.t_openContainer(t, segment, cid, false);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 0, column, false, REC_001, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 1, column, false, REC_002, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 2, column, false, REC_003, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 3, column, false, REC_004, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 4, column, false, REC_005, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 5, column, false, REC_009, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 6, column, false, REC_010, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 7, column, false, REC_011, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 8, column, false, REC_012, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 9, column, false, REC_013, colSize);
        page.unlatch();


		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);
        t.close();

		PASS("P055: segment = " + segment);
	}


	/**
        Test rollback of partial row update.
        Create a long row with 15 columns on 3 pages (5 columns on each page).
        Update the 1st column on the 2nd page (the 6th column) which causes the
        last column of that page (10th column) to move off the page. Then abort
        and make sure that all the original columns are there and correct.

        NOTE: stored length is twice string length + 2

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P056(long segment) throws StandardException, T_Fail {

		if (!testRollback)
			return;

		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

        int colSize = 90;
		T_RawStoreRow r0 = new T_RawStoreRow(15);
		r0.setColumn(0, colSize, REC_001);
		r0.setColumn(1, colSize, REC_002);
		r0.setColumn(2, colSize, REC_003);
		r0.setColumn(3, colSize, REC_004);
		r0.setColumn(4, colSize, REC_005);
		r0.setColumn(5, colSize, REC_009);
        r0.setColumn(6, colSize, REC_010);
		r0.setColumn(7, colSize, REC_011);
        r0.setColumn(8, colSize, REC_012);
		r0.setColumn(9, colSize, REC_013);
		r0.setColumn(10, colSize, REC_014);
        r0.setColumn(11, colSize, REC_015);
		r0.setColumn(12, colSize, REC_016);
        r0.setColumn(13, colSize, REC_017);
		r0.setColumn(14, colSize, REC_018);


		int insertFlag = Page.INSERT_INITIAL;
		insertFlag |= Page.INSERT_OVERFLOW;

		RecordHandle rh0 = null;
		try {
			rh0 = t_util.t_insertAtSlot(page, 0, r0, (byte) insertFlag);
		} catch (StandardException se) {
			throw T_Fail.testFailMsg("insert of long row failed.");
		}

		if (rh0 == null)
			throw T_Fail.testFailMsg("insert of first long row failed.");
		else {
			REPORT("about to check fetch...");
			DataValueDescriptor column = new SQLChar();
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 0, column, false, REC_001, colSize);
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 1, column, false, REC_002, colSize);
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 2, column, false, REC_003, colSize);
			t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 3, column, false, REC_004, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 4, column, false, REC_005, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 5, column, false, REC_009, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 6, column, false, REC_010, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 7, column, false, REC_011, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 8, column, false, REC_012, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 9, column, false, REC_013, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 10, column, false, REC_014, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 11, column, false, REC_015, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 12, column, false, REC_016, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 13, column, false, REC_017, colSize);
            t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 14, column, false, REC_018, colSize);
		}

   		t_util.t_commit(t);


        // update col 5 (the 6th column, the first column on the 2nd overflow page), which causes
        // the last column (col 9, the 10th column) to move off the page.

        c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		T_RawStoreRow updateRow = new T_RawStoreRow(15);
		for (int i = 0; i < 15; i++)
			updateRow.setColumn(i, (String) null);
        updateRow.setColumn(5, colSize*2, REC_009);
		FormatableBitSet colList = new FormatableBitSet(15);
		colList.set(5);
		page.updateAtSlot(0, updateRow.getRow(), colList);

        REPORT("about to check fetch after update ...");
        DataValueDescriptor column = new SQLChar();
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 0, column, false, REC_001, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 1, column, false, REC_002, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 2, column, false, REC_003, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 3, column, false, REC_004, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 4, column, false, REC_005, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 5, column, false, REC_009, colSize*2);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 6, column, false, REC_010, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 7, column, false, REC_011, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 8, column, false, REC_012, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 9, column, false, REC_013, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 10, column, false, REC_014, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 11, column, false, REC_015, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 12, column, false, REC_016, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 13, column, false, REC_017, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 14, column, false, REC_018, colSize);
        page.unlatch();

        t_util.t_abort(t);


        REPORT("about to check fetch after abort ...");
		c = t_util.t_openContainer(t, segment, cid, false);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 0, column, false, REC_001, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 1, column, false, REC_002, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 2, column, false, REC_003, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 3, column, false, REC_004, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 4, column, false, REC_005, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 5, column, false, REC_009, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 6, column, false, REC_010, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 7, column, false, REC_011, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 8, column, false, REC_012, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 9, column, false, REC_013, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 10, column, false, REC_014, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 11, column, false, REC_015, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 12, column, false, REC_016, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 13, column, false, REC_017, colSize);
        t_util.t_checkFetchColFromSlot(page, page.FIRST_SLOT_NUMBER, 14, column, false, REC_018, colSize);
        page.unlatch();


		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}
		t_util.t_commit(t);
        t.close();

		PASS("P056: segment = " + segment);
	}




	/**
	   Sparse row test.
	   Test sparse representation of rows using the FormatableBitSet class.
	   Insert, fetch and update a row having gaps.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P061() throws StandardException, T_Fail
	{
		long segment = 0;
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, segment);

		int numCols = 6;
		T_RawStoreRow row1 = new T_RawStoreRow(numCols);
		row1.setColumn(0,  (String) null);
		row1.setColumn(1,  REC_001);
		row1.setColumn(2,  (String) null);
		row1.setColumn(3,  REC_002);
		row1.setColumn(4,  (String) null);
		row1.setColumn(5,  REC_003);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			RecordHandle rh1 = t_util.t_insert(page, row1);

			t_util.t_checkFetchCol(page, rh1, 1, numCols, REC_001);
			t_util.t_checkFetchCol(page, rh1, 3, numCols, REC_002);
			t_util.t_checkFetchCol(page, rh1, 5, numCols, REC_003);

			t_util.t_checkUpdateCol(page, rh1, 1, numCols, "woody");
			t_util.t_checkUpdateCol(page, rh1, 3, numCols, "buzz");
			t_util.t_checkUpdateCol(page, rh1, 5, numCols, "andy");

			t_util.t_checkUpdateCol(page, rh1, 2, numCols, "dino");

			page.unlatch();
			page = null;

			t_util.t_commit(t);
		}
		finally
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}

		PASS("P061");
	}


	/**
	   Serializable column test.
       Want to make sure we hit some otherwise dead code in StoredPage, used
       for storing/reading Serializable/Externalizable data to/from a page.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P071() throws StandardException, T_Fail
	{
        /*
		long segment = 0;
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, segment);

		int numCols = 1;
		T_RawStoreRow row1 = new T_RawStoreRow(numCols);
		row1.setColumn(0,  new T_Serializable(REC_001));

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			RecordHandle rh1 = t_util.t_insert(page, row1);

			t_util.t_checkFetchSerCol(page, rh1, 0, numCols, new T_Serializable(REC_001));

			page.unlatch();
			page = null;

			t_util.t_commit(t);
		}
		finally
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}
        */

		PASS("P071");
	}



	/*
	** Update and update partial tests aimed at long rows
	*/

	/**
		Insert a single row and keep updating it, adding columns
		not using partial rows.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P701(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		T_RawStoreRow row = new T_RawStoreRow(0);
		RecordHandle rh = t_util.t_insertAtSlot(page, 0, row, (byte) (Page.INSERT_INITIAL | Page.INSERT_OVERFLOW));
		t_util.t_checkFetch(page, rh, row);

		page.unlatch();
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);


		for (int i = 0; i < 10;i++) {

			REPORT("P701 - iteration " + i);
			
			row = new T_RawStoreRow(i);

			for (int j = 0; j < i; j++) {
				row.setColumn(j, 256, "XX" + j + "YY");
			}

			int slot = page.getSlotNumber(rh);
			page.updateAtSlot(slot, row.getRow(), null);
			page.unlatch();
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkFetch(page, rh, row);
		}

		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}


		t_util.t_commit(t);

		t.close();

		PASS("P701: segment = " + segment);
	}
	/*
	** Update and update partial tests aimed at long rows
	*/

	/**
		Insert a single row and keep updating it, adding columns
		using partial rows.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P702(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		T_RawStoreRow row = new T_RawStoreRow(0);
		RecordHandle rh = t_util.t_insertAtSlot(page, 0, row, (byte) (Page.INSERT_INITIAL | Page.INSERT_OVERFLOW));
		t_util.t_checkFetch(page, rh, row);

		page.unlatch();
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);


		for (int i = 0; i < 10;i++) {

			REPORT("P702 - iteration " + i);

			FormatableBitSet colList = new FormatableBitSet(i+1);
			colList.set(i);

			T_RawStoreRow rowU = new T_RawStoreRow(i+1);
			rowU.setColumn(i, 256, "XX" + i + "YY");

			int slot = page.getSlotNumber(rh);
			page.updateAtSlot(slot, rowU.getRow(), colList);
			page.unlatch();

			T_RawStoreRow rowF = new T_RawStoreRow(i+1);

			for (int j = 0; j <= i; j++) {
				rowF.setColumn(j, 256, "XX" + j + "YY");
			}

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkFetch(page, rh, rowF);
		}
		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);

		t.close();

		PASS("P702: segment = " + segment);
	}

	/**
		Simple set of partial row updates on a singel page with
		shrinking and expanding columns.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/

	protected void P703(long segment)
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		REPORT("P703 - start ");
		T_RawStoreRow row = new T_RawStoreRow(2);
		row.setColumn(0, REC_001);
		row.setColumn(1, REC_002);
		RecordHandle rh = t_util.t_insertAtSlot(page, 0, row, (byte) (Page.INSERT_INITIAL | Page.INSERT_OVERFLOW));
		t_util.t_checkFetch(page, rh, row);
		REPORT("P703 - insert Ok ");

		page.unlatch();
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// Perform 10 tests
		// 1  update col0 to grow
		// 2  update col1 to grow
		// 3  update col0 to shrink
		// 4  update col1 to shrink
		// 5  update col0 to null
		// 6  update col1 to null
		// 7  update col0 to non-null
		// 8  update col1 to non-null
		// 9  update no columns
		// 10 update both cols

		P703Helper(page, rh, 0, REC_006, REC_002);
		REPORT("P703 - case 1 passed");

		P703Helper(page, rh, 1, REC_007, REC_006);
		REPORT("P703 - case 2 passed");

		P703Helper(page, rh, 0, REC_003, REC_007);
		REPORT("P703 - case 3 passed");

		P703Helper(page, rh, 1, REC_004, REC_003);
		REPORT("P703 - case 4 passed");

		P703Helper(page, rh, 0, null, REC_004);
		REPORT("P703 - case 5 passed");

		P703Helper(page, rh, 1, null, null);
		REPORT("P703 - case 6 passed");

		P703Helper(page, rh, 0, REC_002, null);
		REPORT("P703 - case 7 passed");

		P703Helper(page, rh, 1, REC_001, REC_002);
		REPORT("P703 - case 8 passed");



		P703Helper(page, rh, -1, REC_002, REC_001);
		REPORT("P703 - case 9 passed");

		FormatableBitSet colList = new FormatableBitSet(2);
		colList.set(0);
		colList.set(1);
		row.setColumn(0, REC_004);
		row.setColumn(1, REC_003);
		int slot = page.getSlotNumber(rh);
		page.updateAtSlot(slot, row.getRow(), colList);
		t_util.t_checkFetch(page, rh, row);


		REPORT("P703 - case 10 passed");


		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t.commit();

		t.close();

		PASS("P703: segment = " + segment);
	}

	private void P703Helper(Page page, RecordHandle rh, int colNum, String newVal, String unchangedCol)
		throws StandardException, T_Fail {

		FormatableBitSet colList = new FormatableBitSet(2);
		T_RawStoreRow rowU = new T_RawStoreRow(2);

		// -1 indicates no columns set in bit set
		if (colNum != -1) {
			colList.grow(colNum+1);
			colList.set(colNum);
			rowU.setColumn(colNum, newVal);
		} else {
			colNum = 0; // only used for read from now on
		}
		int slot = page.getSlotNumber(rh);
		page.updateAtSlot(slot, rowU.getRow(), colList);

		T_RawStoreRow row = new T_RawStoreRow(2);
		row.setColumn(colNum, newVal);
		row.setColumn(colNum == 0 ? 1 : 0, unchangedCol);

		t_util.t_checkFetch(page, rh, row);
	}


	/**
		Insert a single row with multiple portions.
		Update fields in the various portions that grow.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P704(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		// row has 15 cols, each with 200 (ish) bytes (100 null chars)
		// thus we would expect at least 3 pages
		T_RawStoreRow row = new T_RawStoreRow(15);
		for (int i = 0; i < 15; i++) {
			row.setColumn(i, 100, "XX" + i + "YY");
		}

		RecordHandle rh = t_util.t_insertAtSlot(page, 0, row, (byte) (Page.INSERT_INITIAL | Page.INSERT_OVERFLOW));
		t_util.t_checkFetch(page, rh, row);

		page.unlatch();
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);


		// update the each column to grow to be a single page (800 bytes ish)
		for (int i = 0; i < 15;i++) {

			REPORT("P704 - col " + i);

			FormatableBitSet colList = new FormatableBitSet(i+1);
			colList.set(i);

			T_RawStoreRow rowU = new T_RawStoreRow(i+1);
			rowU.setColumn(i, 400, "WW" + i + "UU");

			int slot = page.getSlotNumber(rh);
			page.updateAtSlot(slot, rowU.getRow(), colList);
			page.unlatch();

			row.setColumn(i, 400, "WW" + i + "UU");

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkFetch(page, rh, row);
		}
		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);

		t.close();

		PASS("P704: segment = " + segment);
	}

	/**
		Same as 704 but update fields in the reverse order.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P705(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		// row has 15 cols, each with 200 (ish) bytes (100 null chars)
		// thus we would expect at least 3 pages
		T_RawStoreRow row = new T_RawStoreRow(15);
		for (int i = 0; i < 15; i++) {
			row.setColumn(i, 100, "XX" + i + "YY");
		}

		RecordHandle rh = t_util.t_insertAtSlot(page, 0, row, (byte) (Page.INSERT_INITIAL | Page.INSERT_OVERFLOW));
		t_util.t_checkFetch(page, rh, row);

		page.unlatch();
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);


		// update the each column to grow to be a single page (800 bytes ish)
		for (int i = 14; i >=0; i--) {

			REPORT("P705 - col " + i);

			FormatableBitSet colList = new FormatableBitSet(i+1);
			colList.set(i);

			T_RawStoreRow rowU = new T_RawStoreRow(i+1);
			rowU.setColumn(i, 400, "WW" + i + "UU");

			int slot = page.getSlotNumber(rh);
			page.updateAtSlot(slot, rowU.getRow(), colList);
			page.unlatch();

			row.setColumn(i, 400, "WW" + i + "UU");

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkFetch(page, rh, row);
		}
		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);

		t.close();

		PASS("P705: segment = " + segment);
	}

	/**
		Insert a single row with single or multiple portions.
		Update every other field with a long col
		The update each column back to a null

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P706(long segment, boolean multiPortion) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		// row has 15 cols, each with 200 (ish) bytes (100 null chars)
		// thus we would expect at least 3 pages
		T_RawStoreRow row = new T_RawStoreRow(15);
		for (int i = 0; i < 15; i++) {
	
			row.setColumn(i, multiPortion ? 100 : 10, "XX" + i + "YY");
		}

		RecordHandle rh = t_util.t_insertAtSlot(page, 0, row, (byte) (Page.INSERT_INITIAL | Page.INSERT_OVERFLOW));
		t_util.t_checkFetch(page, rh, row);

		page.unlatch();
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// update  every other column to be a long column
		for (int i = 0; i < 15;i++) {

			if ((i % 2) == 0) {		
				continue;
			}

			REPORT("P706 : multiPortion " + multiPortion + " - col " + i);

			FormatableBitSet colList = new FormatableBitSet(i+1);
			colList.set(i);

			T_RawStoreRow rowU = new T_RawStoreRow(i+1);
			rowU.setColumn(i, 3000, "WW" + i + "UU"); // longer than 4096 page length

			int slot = page.getSlotNumber(rh);
			page.updateAtSlot(slot, rowU.getRow(), colList);
			page.unlatch();

			row.setColumn(i, 3000, "WW" + i + "UU");

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkFetch(page, rh, row);
		}

		t_util.t_commit(t);

		// update  every column to a null
		c = t_util.t_openContainer(t, segment, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		for (int i = 0; i < 15;i++) {

			REPORT("P706 : update to null " + multiPortion + " - col " + i);

			FormatableBitSet colList = new FormatableBitSet(i+1);
			colList.set(i);

			T_RawStoreRow rowU = new T_RawStoreRow(i+1);
			rowU.setColumn(i, (String) null);

			int slot = page.getSlotNumber(rh);
			page.updateAtSlot(slot, rowU.getRow(), colList);
			page.unlatch();

			row.setColumn(i, (String) null);

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkFetch(page, rh, row);
		}
		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);

		t.close();

		PASS("P706: multiPortion " + multiPortion + " segment = " + segment);
	}

	/**
		Insert a single record that has several chunks
		and every other column is a long column
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P707(long segment) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		T_RawStoreRow row = new T_RawStoreRow(20);
		for (int i = 0; i < 20; i++) {
			if ((i % 2) ==0)
				row.setColumn(i, 200, "XX" + i + "YY");	// big but first within a page
			else
				row.setColumn(i, 4000, "XX" + i + "YY"); // long column
		}

		RecordHandle rh = t_util.t_insertAtSlot(page, 0, row, (byte) (Page.INSERT_INITIAL | Page.INSERT_OVERFLOW));
		t_util.t_checkFetch(page, rh, row);

		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}


		t_util.t_commit(t);

		t.close();

		PASS("P707: segment = " + segment);
	}

	/**
		Insert a single row with single or multiple portions.
		Update every other field with a long col
		rollback.
		The update each column back to a null and rollback

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void P708(long segment, boolean multiPortion) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();

		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		// row has 15 cols, each with 200 (ish) bytes (100 null chars)
		// thus we would expect at least 3 pages
		T_RawStoreRow row = new T_RawStoreRow(15);
		for (int i = 0; i < 15; i++) {

			row.setColumn(i, multiPortion ? 100 : 10, "XX" + i + "YY");
		}

		RecordHandle rh = t_util.t_insertAtSlot(page, 0, row, (byte) (Page.INSERT_INITIAL | Page.INSERT_OVERFLOW));
		t_util.t_checkFetch(page, rh, row);

		page.unlatch();
		t_util.t_commit(t);
		c = t_util.t_openContainer(t, segment, cid, true);

		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// update  every other column to be a long column
		for (int i = 0; i < 15;i++) {

			if ((i % 2) == 0) {
				continue;
			}

			REPORT("P708 : multiPortion " + multiPortion + " - col " + i);

			FormatableBitSet colList = new FormatableBitSet(i+1);
			colList.set(i);

			T_RawStoreRow rowU = new T_RawStoreRow(i+1);
			rowU.setColumn(i, 3000, "WW" + i + "UU"); // longer than 4096 page length

			int slot = page.getSlotNumber(rh);
			page.updateAtSlot(slot, rowU.getRow(), colList);
		}

		t_util.t_abort(t);

		c = t_util.t_openContainer(t, segment, cid, false);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkFetch(page, rh, row);
		page.unlatch();

		if (segment != ContainerHandle.TEMPORARY_SEGMENT) {
			t_util.t_dropContainer(t, segment, cid);	// cleanup
		}

		t_util.t_commit(t);

		t.close();

		PASS("P708: multiPortion " + multiPortion + " segment = " + segment);
	}


	/**
	  P709:
	  this test exercises purgeAtSlot , rollsback and purges the slot again,
	  to make sure not logging the data does not have any impact on repurging
	  the rollbacked purges.
	  @exception T_Fail Unexpected behaviour from the API
	  @exception StandardException Unexpected exception from the implementation
	*/
	protected void P709()
		 throws StandardException, T_Fail
	{
		logDataForPurges = false;
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t,0);
		t_util.t_commit(t);

	
		ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		// REPORT("insert 5 records");
		T_RawStoreRow row0 = new T_RawStoreRow(REC_001);
		T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
		T_RawStoreRow row2 = new T_RawStoreRow(REC_002);
		T_RawStoreRow row3 = new T_RawStoreRow(REC_003);
		T_RawStoreRow row4 = new T_RawStoreRow(REC_004);
		
		RecordHandle r0, r1, r2, r3, r4;
		r0 = t_util.t_insertAtSlot(page, 0, row0);
		r1 = t_util.t_insertAtSlot(page, 1, row1);
		r2 = t_util.t_insertAtSlot(page, 2, row2);
		r3 = t_util.t_insertAtSlot(page, 3, row3);
		r4 = t_util.t_insertAtSlot(page, 4, row4);

		if (r3 != null) page.deleteAtSlot(3, true, (LogicalUndo)null);

		// REPORT("commit it");
		t_util.t_commit(t);

		c = t_util.t_openContainer(t, 0, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		try 
		{
			page.purgeAtSlot(-1, 1, logDataForPurges);
			throw T_Fail.testFailMsg("negative slot number did not cause an exception");
		}
		catch (StandardException se) {}	// expected

		try
		{
			page.purgeAtSlot(4, 4, logDataForPurges);
			throw T_Fail.testFailMsg("purging more rows than is on page did not cause an exception");
		}
		catch (StandardException se) {}	// expected

		// if not all the rows are there, do minimal test
		if (r4 == null)
		{
			int rcount = page.recordCount();
			page.purgeAtSlot(0, 1, logDataForPurges);
			if (page.recordCount() != rcount-1)
				T_Fail.testFailMsg("failed to purge a record, expect " + 
								   (rcount-1) + " got " + page.recordCount());

			if (testRollback)
			{
				t_util.t_abort(t);

				c = t_util.t_openContainer(t, 0, cid, true);
				page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
				if(logDataForPurges)
					t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
				else
					t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
				if (page.recordCount() != rcount)
					T_Fail.testFailMsg("failed to rollback purge, expect " + 
								   rcount + " got " + page.recordCount());
			}
			else
			{
				t_util.t_commit(t);
			}
			PASS("mimimal purging P709");
			return;
		}

		// REPORT("purge 2 records from middle");
		page.purgeAtSlot(1, 2, logDataForPurges);
		t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
		t_util.t_checkFetchBySlot(page, 1, REC_003,true, true);
		t_util.t_checkFetchBySlot(page, 2, REC_004,false, true);

		if (page.recordCount() != 3)
			T_Fail.testFailMsg("page expect to have 3 records, recordCount() = " +
							   page.recordCount());

		// REPORT("purge all records from the page");
		page.purgeAtSlot(0, 3, logDataForPurges);
		if (page.recordCount() != 0)
			T_Fail.testFailMsg("page expect to have 0 records, recordCount() = " +
							   page.recordCount());

		if (testRollback)
		{

			REPORT("testing rollback");
			t_util.t_abort(t);

			c = t_util.t_openContainer(t, 0, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			if(logDataForPurges){
				t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 2, REC_002,false, true);
				t_util.t_checkFetchBySlot(page, 3, REC_003,true, true);
				t_util.t_checkFetchBySlot(page, 4, REC_004,false, true);
			}else
			{
				t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 2, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 3, REC_NULL,true, true);
				t_util.t_checkFetchBySlot(page, 4, REC_NULL,false, true);
			}

			if (page.recordCount() != 5)
				T_Fail.testFailMsg("page expect to have 5 records, recordCount() = " +
								   page.recordCount());

			// REPORT("purge 3 records from the end");
			page.purgeAtSlot(2, 3, logDataForPurges);
			if(logDataForPurges)
			{
				t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_001,false, true);
			}else
			{
				t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_NULL,false, true);
			}
			if (page.recordCount() != 2)
				T_Fail.testFailMsg("page expect to have 2 records, recordCount() = " +
								   page.recordCount());

			// REPORT("rollback");
			t_util.t_abort(t);

			c = t_util.t_openContainer(t, 0, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			if(logDataForPurges){
				t_util.t_checkFetchBySlot(page, 0, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_001,false, true);
				t_util.t_checkFetchBySlot(page, 2, REC_002,false, true);
				t_util.t_checkFetchBySlot(page, 3, REC_003,true, true);
				t_util.t_checkFetchBySlot(page, 4, REC_004,false, true);
			}else
			{
				t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 1, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 2, REC_NULL,false, true);
				t_util.t_checkFetchBySlot(page, 3, REC_NULL,true, true);
				t_util.t_checkFetchBySlot(page, 4, REC_NULL,false, true);	
			}

			if (page.recordCount() != 5)
				T_Fail.testFailMsg("page expect to have 5 records, recordCount() = " +
								   page.recordCount());

			// REPORT("make sure delete record is reconstituted as such");
			if (page.isDeletedAtSlot(1))
				T_Fail.testFailMsg("rolled back purged undeleted record cause record to be deleted");
			if (!page.isDeletedAtSlot(3))
				T_Fail.testFailMsg("rolled back purged deleted record cause record to be undeleted");
		}

		REPORT("purging again the purges rolled back earlier");
		//purge again and this time do commit , instead of rollback.
		// REPORT("purge 2 records from middle");
		page.purgeAtSlot(1, 2, logDataForPurges);
		t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
		t_util.t_checkFetchBySlot(page, 1, REC_NULL,true, true);
		t_util.t_checkFetchBySlot(page, 2, REC_NULL,false, true);

		if (page.recordCount() != 3)
			T_Fail.testFailMsg("page expect to have 3 records, recordCount() = " +
							   page.recordCount());

		// REPORT("purge all records from the page");
		page.purgeAtSlot(0, 3, logDataForPurges);
		if (page.recordCount() != 0)
			T_Fail.testFailMsg("page expect to have 0 records, recordCount() = " +
							   page.recordCount());
		
		
		t_util.t_abort(t);

		c = t_util.t_openContainer(t, 0, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		if (page.recordCount() != 5)
			T_Fail.testFailMsg("page expect to have 5 records, recordCount() = " +
							   page.recordCount());

		// REPORT("purge 3 records from the end");
		page.purgeAtSlot(2, 3, logDataForPurges);
		t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
		t_util.t_checkFetchBySlot(page, 1, REC_NULL,false, true);
		if (page.recordCount() != 2)
			T_Fail.testFailMsg("page expect to have 2 records, recordCount() = " +
							   page.recordCount());

		// REPORT("commit");
		t_util.t_commit(t);

		c = t_util.t_openContainer(t, 0, cid, true);
		page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkFetchBySlot(page, 0, REC_NULL,false, true);
		t_util.t_checkFetchBySlot(page, 1, REC_NULL,false, true);

		if (page.recordCount() != 2)
				T_Fail.testFailMsg("page expect to have 2 records, recordCount() = " +
								   page.recordCount());

		
		PASS("P709");

		t_util.t_dropContainer(t, 0, cid);	// cleanup
		t_util.t_commit(t);
		t.close();
	}

	
	/**
		Test space reclaimation - purging of a long rows with a rollback and
        purging againg with no data logging for purges
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P710() throws StandardException, T_Fail
	{
		long segment = 0;
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			t_util.t_checkEmptyPage(page);

			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW;

			// insert a row with 100 columns from 200 to 400 bytes each and make it
			// sprawl across many pages.
			T_RawStoreRow r1 = new T_RawStoreRow(100);
			for (int i = 0; i < 100; i++)
				r1.setColumn(i, 100+i, REC_001);

			RecordHandle rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte)insertFlag);
			t_util.t_checkFetch(page, rh1, r1);

			Page nextPage = t_util.t_addPage(c);
			long nextPageNumber = nextPage.getPageNumber();
			// deallocate it
			t_util.t_removePage(c, nextPage);

			REPORT("P710 - Nextpage is " + nextPageNumber);
			page.unlatch();
			page = null;
			t_util.t_commit(t);

			// See what the next page is.
			c = t_util.t_openContainer(t, segment, cid, true);

			// Now purge that first row.
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkRecordCount(page, 1, 1);
			page.purgeAtSlot(0, 1, logDataForPurges);

			t_util.t_checkEmptyPage(page);
			page.unlatch();
			page = null;
			t_util.t_commit(t);

			// give some time for post commit to finish
			t_util.t_wait(10);		// wait 10 milliseconds.

			// reinsert r1, it should use no extra page than last time.
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			RecordHandle rh2 = t_util.t_insertAtSlot(page, 0, r1, (byte)insertFlag);
			t_util.t_checkFetch(page, rh2, r1);
			page.unlatch();
			page = null;

			// now verify that it used up no more page than last time
			nextPage = t_util.t_addPage(c);
			long checkNextPageNumber = nextPage.getPageNumber();
			nextPage.unlatch();

			if (nextPageNumber != checkNextPageNumber)
				throw T_Fail.testFailMsg("fail to reuse row pieces expect next page=" + 
					nextPageNumber + " but got " + checkNextPageNumber );


			t_util.t_commit(t);

			// Purge them and roll them back via savepoint.  These should not
			// be reclaimed.
			c = t_util.t_openContainer(t, segment, cid, true);
			t.setSavePoint(SP1, null);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			t_util.t_checkRecordCount(page, 1, 1);
			page.purgeAtSlot(0, 1, logDataForPurges);
			page.unlatch();
			page = null;

			// make sure we cannot get our hands on a page that is freed up by
			// the purge
			Page testPage = t_util.t_addPage(c);
			T_RawStoreRow testRow = new T_RawStoreRow(REC_001);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			t.rollbackToSavePoint(SP1, null);

			testPage = t_util.t_addPage(c);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			t_util.t_commit(t);
			t_util.t_wait(10);
			
			c = t_util.t_openContainer(t, segment, cid, true);

			testPage = t_util.t_addPage(c);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			t_util.t_checkRecordCount(page, 1, 1);

			//repurge again.
			page.purgeAtSlot(0, 1, logDataForPurges);
			t_util.t_abort(t);
			//				t_util.t_checkFetch(page, rh2, r1);			
			page = null;
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			t_util.t_checkRecordCount(page, 1, 1);
			//repurge again and do commit
			page.purgeAtSlot(0, 1, logDataForPurges);
			page.unlatch();
			page = null;
			t_util.t_commit(t);
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			t_util.t_checkRecordCount(page, 0, 0);
			page.unlatch();
			page = null;
			t_util.t_dropContainer(t, segment, cid);	// cleanup

		}
		finally	
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}

		PASS("P710");
	}

	
	/**
		Test space reclaimation - purging of a row with serveral long columns
	    rollback and repurge them again.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	 */
	protected void P711() throws StandardException, T_Fail
	{

		long segment = 0;
		Transaction t = t_util.t_startTransaction();
		long cid = t_util.t_addContainer(t, segment, 4096);

		ContainerHandle c = t_util.t_openContainer(t, segment, cid, true);
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		try
		{
			t_util.t_checkEmptyPage(page);

			int insertFlag = Page.INSERT_INITIAL | Page.INSERT_OVERFLOW;
			T_RawStoreRow r1 = new T_RawStoreRow(1);
			// insert a long column
			r1.setColumn(0, 5000, REC_001);
			RecordHandle rh1 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			t_util.t_checkFetch(page, rh1, r1);

			// insert a 6 column row, every other column is long
			T_RawStoreRow r2 = new T_RawStoreRow(6);
			r2.setColumn(0, 600, REC_001); // this takes ~1200 bytes
			r2.setColumn(1, 5000, REC_002); // this takes ~10000 bytes
			r2.setColumn(2, 600, REC_001);
			r2.setColumn(3, 5000, REC_002);
			r2.setColumn(4, 600, REC_001);
			r2.setColumn(5, 5000, REC_002);
			RecordHandle rh2 = t_util.t_insertAtSlot(page, 0, r2, (byte) insertFlag);	
			t_util.t_checkFetch(page, rh2, r2);

			// insert a long column - this should fail
			RecordHandle rh3 = t_util.t_insertAtSlot(page, 0, r1, (byte) insertFlag);	
			if (rh3 != null)
            {
				throw T_Fail.testFailMsg("expect the 3rd row to not fit on page");
            }
			page.unlatch();
			page = null;

			Page nextPage = t_util.t_addPage(c);
			long nextPageNumber = nextPage.getPageNumber();
			// deallocate it
			t_util.t_removePage(c, nextPage);

			REPORT("P711 - Nextpage is " + nextPageNumber);

			t_util.t_commit(t);

			// now purge them
			c = t_util.t_openContainer(t, segment, cid, true);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkRecordCount(page, 2, 2);
			page.purgeAtSlot(0, 2, logDataForPurges);
			t_util.t_checkEmptyPage(page);
			page.unlatch();
			page = null;

			t_util.t_abort(t);

			// give some time for post commit to finish
			t_util.t_wait(10);		// wait 10 milliseconds.


			// Purge them again and roll them back via savepoint.  These should not
			// be reclaimed.
			c = t_util.t_openContainer(t, segment, cid, true);

			t.setSavePoint(SP1, null);
			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			
			t_util.t_checkRecordCount(page, 2, 2);
			page.purgeAtSlot(0, 2, logDataForPurges);
			t_util.t_checkEmptyPage(page);

			page.unlatch();
			page = null;

			// make sure we cannot get our hands on a page that is freed up by
			// the purge
			Page testPage = t_util.t_addPage(c);
			T_RawStoreRow testRow = new T_RawStoreRow(REC_001);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			t.rollbackToSavePoint(SP1, null);

			testPage = t_util.t_addPage(c);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			t_util.t_commit(t);

			// give some time for post commit to finish
			t_util.t_wait(10);

			// check to make sure post commit did not reclaim those rows.
			c = t_util.t_openContainer(t, segment, cid, true);

			testPage = t_util.t_addPage(c);
			t_util.t_insert(testPage, testRow);
			testPage.unlatch();

			page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
			

			t_util.t_checkRecordCount(page, 2, 2);
			t_util.t_checkFetch(page, rh1, r1);
		

			// During purges when data is not logged when slots are purged
			// they become null on rollback and some cases like long columns
			// we remove the wholepage on rollback we get the data back.
			T_RawStoreRow r2_wnl = new T_RawStoreRow(6);
			r2_wnl.setColumn(0, 4, REC_NULL); 
			r2_wnl.setColumn(1, 5000, REC_002); 
			r2_wnl.setColumn(2, 4, REC_NULL);
			r2_wnl.setColumn(3, 5000, REC_002);
			r2_wnl.setColumn(4, 4, REC_NULL);
			r2_wnl.setColumn(5, 5000, REC_002);
			t_util.t_checkFetch(page, rh2, r2_wnl);
				
			page.unlatch();
			page = null;

			t_util.t_dropContainer(t, segment, cid);	// cleanup

		}
		finally
		{
			if (page != null)
				page.unlatch();
			t_util.t_commit(t);
			t.close();
		}

		PASS("P711");

	}



	// test writing out large log records
	protected void L001()
		 throws StandardException, T_Fail
	{
		Transaction t = t_util.t_startTransaction();

		// if runing multi threaded, only have 1 thread log these large record
		// or we may get out of memeory error
		int loop = 10;
		int logSize = (threadNumber == 0) ? 50000 : 50;

		try
		{
			for (int i = 0; i < loop; i++)
			{
				Loggable l = new T_Undoable(t.getGlobalId(), -1, -1, 
											T_Undoable.REMOVE_NONE,
											0, //LWM ignored
											true,10,false,i*logSize,false);
				t.logAndDo(l);
			}
			t.commit();
			t.close();
			t = null;

			t = t_util.t_startTransaction();
			for (int i = 0; i < loop; i++)
			{
				Loggable l = new T_Undoable(t.getGlobalId(), -1, -1, 
											T_Undoable.REMOVE_NONE,
											0, //LWM ignored
											true,10,false,i*logSize,false);

				t.logAndDo(l);
			}

			PASS("L001");
		}
		finally
		{
			t.commit();
			t.close();
		}
	}


	/**
		Test checkpoint
		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void CP001()
		 throws StandardException, T_Fail
	{
		if (!testRollback)
			return;

		ContextManager previousCM = contextService.getCurrentContextManager();
		Transaction longtran = null;

		ContextManager cm1 = null;
		Transaction t1 = null;

		ContextManager cm2 = null;
		Transaction t2 = null;

		// ContextManager cpm = null; // reserved for the checkpoint transaction
		try {

			T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
			T_RawStoreRow row2 = new T_RawStoreRow(REC_002);
			T_RawStoreRow row3 = new T_RawStoreRow(REC_003);
			T_RawStoreRow row4 = new T_RawStoreRow(REC_004);
			T_RawStoreRow row5 = new T_RawStoreRow(REC_005);

			// start a long running transaction that spans multiple checkpoints
			// make sure it can be rolled back a the end
			longtran = t_util.t_startTransaction();

			long cid = t_util.t_addContainer(longtran, 0);
			ContainerHandle c = t_util.t_openContainer(longtran, 0, cid, true);
			RecordHandle r1 = t_util.t_insert(c, row1);
			RecordHandle r2 = t_util.t_insert(c, row2);
			t_util.t_commit(longtran);

			c = t_util.t_openContainer(longtran, 0, cid, true);
			Page p2 = t_util.t_getPage(c, r2.getPageNumber());
			int slot2 = p2.getSlotNumber(r2);
			p2.updateAtSlot(slot2, row5.getRow(), null);
			p2.unlatch();


			// a bunch of short running transactions that criss cross the
			// checkpoints 

			cm1 = contextService.newContextManager();
			contextService.setCurrentContextManager(cm1);
			t1 = t_util.t_startTransaction();

			long cid1 = t_util.t_addContainer(t1, 0);
			ContainerHandle c1 = t_util.t_openContainer(t1, 0, cid1, true);
			RecordHandle r3 = t_util.t_insert(c1, row3);
			RecordHandle r4 = t_util.t_insert(c1, row4);
			contextService.resetCurrentContextManager(cm1);

			cm2 = contextService.newContextManager();
			contextService.setCurrentContextManager(cm2);
			t2 = t_util.t_startTransaction();

			long cid2 = t_util.t_addContainer(t2, 0);
			ContainerHandle c2 = t_util.t_openContainer(t2, 0, cid2, true);
			RecordHandle r5 = t_util.t_insert(c2, row1);
			t_util.t_commit(t2);
			c2 = t_util.t_openContainer(t2, 0, cid2, true);
			Page p5 = t_util.t_getPage(c2, r5.getPageNumber());
			int slot5 = p5.getSlotNumber(r5);
			p5.updateAtSlot(slot5, row5.getRow(), null);
			p5.unlatch();

			//		cpm = contextService.newContextManager();
			//		contextService.setCurrentContextManager(cpm);
			factory.checkpoint();
			contextService.resetCurrentContextManager(cm2);


			// make sure checkpoint did not destroy any data
			contextService.setCurrentContextManager(previousCM);
			t_util.t_checkFetch(c, r1, REC_001);
			t_util.t_checkFetch(c, r2, REC_005);
			contextService.resetCurrentContextManager(previousCM);

			contextService.setCurrentContextManager(cm1);
			t_util.t_checkFetch(c1, r3, REC_003);
			t_util.t_checkFetch(c1, r4, REC_004);
			contextService.resetCurrentContextManager(cm1);

			contextService.setCurrentContextManager(cm2);
			t_util.t_checkFetch(c2, r5, REC_005);

			// two consecutive checkpoints
			//		contextService.setCurrentContextManager(cpm);
			factory.checkpoint();
			contextService.resetCurrentContextManager(cm2);

			// we can insert some more
			contextService.setCurrentContextManager(previousCM);
			Page page = t_util.t_addPage(c);
			RecordHandle r6 = t_util.t_insertAtSlot(page, 0, row1, Page.INSERT_UNDO_WITH_PURGE);
			page.unlatch();
			contextService.resetCurrentContextManager(previousCM);

			// commit/abort everything except the long running transaction
			contextService.setCurrentContextManager(cm1);
			t_util.t_commit(t1);
			contextService.resetCurrentContextManager(cm1);

			contextService.setCurrentContextManager(cm2);
			t_util.t_abort(t2);
			contextService.resetCurrentContextManager(cm2);

			contextService.setCurrentContextManager(previousCM);
			t_util.t_checkFetch(c, r1, REC_001);
			t_util.t_checkFetch(c, r2, REC_005);
			t_util.t_checkFetch(c, r6, REC_001);
			contextService.resetCurrentContextManager(previousCM);

			contextService.setCurrentContextManager(cm1);
			c1 = t_util.t_openContainer(t1, 0, cid1, true);
			t_util.t_checkFetch(c1, r3, REC_003);
			t_util.t_checkFetch(c1, r4, REC_004);
			contextService.resetCurrentContextManager(cm1);

			contextService.setCurrentContextManager(cm2);
			c2 = t_util.t_openContainer(t2, 0, cid2, true);
			t_util.t_checkFetch(c2, r5, REC_001);

			// checkpoint again
			//		contextService.setCurrentContextManager(cpm);
			factory.checkpoint();
			contextService.resetCurrentContextManager(cm2);

			contextService.setCurrentContextManager(previousCM);
			t_util.t_abort(longtran);
			c = t_util.t_openContainer(longtran, 0, cid, true);
			t_util.t_checkFetch(c, r1, REC_001);
			t_util.t_checkFetch(c, r2, REC_002);

			Page p6 = t_util.t_getPage(c, r6.getPageNumber());
			t_util.t_checkEmptyPage(p6);
			p6.unlatch();

			t_util.t_dropContainer(longtran, 0, cid); // cleanup
			contextService.resetCurrentContextManager(previousCM);

			contextService.setCurrentContextManager(cm1);
			t_util.t_checkFetch(c1, r3, REC_003);
			t_util.t_checkFetch(c1, r4, REC_004);
			t_util.t_dropContainer(t1, 0, cid1);
			contextService.resetCurrentContextManager(cm1);

			contextService.setCurrentContextManager(cm2);
			t_util.t_checkFetch(c2, r5, REC_001);
			t_util.t_dropContainer(t2, 0, cid2);

			// checkpoint again
			//		contextService.setCurrentContextManager(cpm);
		    factory.checkpoint();
			contextService.resetCurrentContextManager(cm2);

			PASS("CP001");


		}
		catch (Throwable t)
		{
			t.printStackTrace(System.err);

			if (cm1 != null)
                //Assume database is not active. DERBY-4856 thread dump
                cm1.cleanupOnError(t, false);
			if (cm2 != null)
                cm2.cleanupOnError(t, false);
			//		if (cpm != null)
            //			cpm.cleanupOnError(t, false);

		} finally {

			if (t2 != null)
			{
				contextService.setCurrentContextManager(cm2);
				t_util.t_commit(t2);
				t2.close();
				contextService.resetCurrentContextManager(cm2);
			}

			if (t1 != null)
			{
				contextService.setCurrentContextManager(cm1);
				t_util.t_commit(t1);
				t1.close();
				contextService.resetCurrentContextManager(cm1);
			}

			if (longtran != null)
			{
				contextService.setCurrentContextManager(previousCM);
				t_util.t_commit(longtran);
				longtran.close();
				contextService.resetCurrentContextManager(previousCM);
			}

			//DJD contextService.setCurrentContextManager(previousCM);
		}
	}


	/**
		TC001 - Test the drop on commit mode for temp containers.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation

	*/
	protected void TC001() throws T_Fail, StandardException {

		Transaction t = t_util.t_startTransaction();

		// open a container with drop on commit and see if it disappears
		long cid = t_util.t_addContainer(t, ContainerHandle.TEMPORARY_SEGMENT);
		t_util.setOpenMode(openMode | ContainerHandle.MODE_DROP_ON_COMMIT);
		ContainerHandle c = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);
		t_util.t_commit(t);

		ContainerKey id = new ContainerKey(ContainerHandle.TEMPORARY_SEGMENT, cid);
		c = t.openContainer(id, ContainerHandle.MODE_READONLY);
		if (c != null)
			throw T_Fail.testFailMsg("Temp Container should not exist");

		// open a container with drop on commit, close it, check it is still there and see if it disappears on a commit
		cid = t_util.t_addContainer(t, ContainerHandle.TEMPORARY_SEGMENT);
		c = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);
		c.close();
		c = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);
		c.close();
		t_util.t_commit(t);

		id = new ContainerKey(ContainerHandle.TEMPORARY_SEGMENT, cid);
		c = t.openContainer(id, ContainerHandle.MODE_READONLY);
		if (c != null)
			throw T_Fail.testFailMsg("Temp Container should not exist");

		// open a container with drop on commit, abort the transaction, and see if it disappears
		cid = t_util.t_addContainer(t, ContainerHandle.TEMPORARY_SEGMENT);
		t_util.setOpenMode(openMode | ContainerHandle.MODE_DROP_ON_COMMIT);
		c = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);
		t_util.t_abort(t);

		id = new ContainerKey(ContainerHandle.TEMPORARY_SEGMENT, cid);
		c = t.openContainer(id, ContainerHandle.MODE_READONLY);
		if (c != null)
			throw T_Fail.testFailMsg("Temp Container should not exist");

		t_util.t_commit(t);
		t.close();
		PASS("TC001");

	}

	// code to populate a temp table for some temp tests
	private int[] populateTempTable(ContainerHandle c)  throws StandardException, T_Fail  {
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);
		t_util.t_checkEmptyPage(page);

		RecordHandle rh;
		T_RawStoreRow row;
		int[]	recordCount = {0,0,0};

		for (int i = 0; i < 3;) {

			for (;;) {

				row = new T_RawStoreRow(REC_001 + i + "X" + recordCount[i]);
				rh = t_util.t_insert(page, row);

				if (rh == null)
					break;

				recordCount[i]++;
				t_util.t_checkRecordCount(page, recordCount[i], recordCount[i]);
			}

			page.unlatch();
			page = null;

			if (++i < 3) {
				page = t_util.t_addPage(c);
				t_util.t_checkEmptyPage(page);
			}
		}

		return recordCount;
	}

	/**
		A clone of P002 for temporary containers.
		Insert rows on the first page until the page is full, then add a page
		and repeat the test (for a total of three pages with full rows).
		Fetch the rows back by handle methods.
		Commit or abort the transaction, and see if table is empty.
		Can be used as follows:

		<PRE>
		mode                   doCommit

        TRUNCATE_ON_COMMIT     true       Ensure the table has only one empty page after commit
		TRUNCATE_ON_COMMIT     false      Ensure the table has only one empty page after abort
		0                      false      Ensure the table has only one empty page after abort

		</PRE>

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void TC002(int mode, boolean doCommit) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, ContainerHandle.TEMPORARY_SEGMENT);

		REPORT("TC002 container id = " + cid);

		t_util.setOpenMode(openMode | mode);
		
		ContainerHandle c = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);

		int[] recordCount = populateTempTable(c);

		for (int i = 0; i < recordCount.length; i++) {
			REPORT("RecordCount on page " + i + "=" + recordCount[i]);
		}



		// now check that we read the same number of records back
		// using the handle interface

		long pageNumber = ContainerHandle.FIRST_PAGE_NUMBER;
		for (int i = 0; i < recordCount.length; i++, pageNumber++) {
			Page page = t_util.t_getPage(c, pageNumber);
			t_util.t_checkRecordCount(page, recordCount[i], recordCount[i]);
			RecordHandle rh = t_util.t_checkFetchFirst(page, REC_001 + i + "X" + 0);
			for (int j = 1; j < recordCount[i]; j++)
				rh = t_util.t_checkFetchNext(page, rh, REC_001 + i + "X" + j);

            try
            {
                rh = page.fetchFromSlot(
                        null, recordCount[i], new DataValueDescriptor[0], 
                        (FetchDescriptor) null,
                        false);

                throw T_Fail.testFailMsg(
                        "reading more rows on page than were written");
            }
            catch (StandardException se)
            {
                // expected exception.
            }


			rh = t_util.t_checkFetchLast(page, REC_001 + i + "X" + (recordCount[i] - 1));
			for (int j = recordCount[i] - 2; j >= 0; j--)
				rh = t_util.t_checkFetchPrevious(page, rh, REC_001 + i + "X" + j);

			page.unlatch();
			page = null;
		}

		c.close();

		// this commit or abort will truncate the table
		if (doCommit)
			t_util.t_commit(t);
		else
			t_util.t_abort(t);

		t_util.setOpenMode(openMode);

		c = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);		
		
		Page page = t_util.t_getPage(c, ContainerHandle.FIRST_PAGE_NUMBER);

		t_util.t_checkEmptyPage(page);
		page.unlatch();
		page = null;

		page = c.getPage(ContainerHandle.FIRST_PAGE_NUMBER + 1);

		if (page != null)
			throw T_Fail.testFailMsg("truncate of temp container did not succeed");

		t_util.t_commit(t);

		t.close();

		PASS("TC002 " + mode + " " + doCommit);
	}


	/**

		Add a number of rows to a temp table opened in various modes,
		and drop it before commit/abort.

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void TC003(int mode, boolean doCommit) throws StandardException, T_Fail {

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, ContainerHandle.TEMPORARY_SEGMENT);

		REPORT("TC003 container id = " + cid);

		t_util.setOpenMode(openMode | mode);
		
		ContainerHandle c = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);
		populateTempTable(c);

		// table is populated, drop it ...
		t_util.t_dropContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid);
		// table should have disappeared ...
		ContainerKey id = new ContainerKey(ContainerHandle.TEMPORARY_SEGMENT, cid);
		ContainerHandle ce = t.openContainer(id, ContainerHandle.MODE_READONLY);
		if (ce != null)
			throw T_Fail.testFailMsg("Dropped Container should not open");

		if (doCommit)
			t_util.t_commit(t);
		else
			t_util.t_abort(t);

		// table should have disappeared ...
		ContainerHandle cd = t.openContainer(id, ContainerHandle.MODE_READONLY);
		if (cd != null)
			throw T_Fail.testFailMsg("Dropped Container should not open");

		t_util.t_commit(t);

		t.close();

		PASS("TC003 " + mode + " " + doCommit);
	}

	/**
		Open a temp table several times with different modes and ensure the
		correct behaviour (most severe open wins).

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void TC004all() throws StandardException, T_Fail {
		int[] modes = {
			0,
			ContainerHandle.MODE_DROP_ON_COMMIT,
			ContainerHandle.MODE_TRUNCATE_ON_COMMIT
		};

		for (int m1 = 0; m1 < modes.length; m1++) {
			for (int m2 = 0; m2 < modes.length; m2++) {
				for (int m3 = 0; m3 < modes.length; m3++) {

					TC004(m1, m2, m3, false, false);
					TC004(m1, m2, m3, false, true);
					TC004(m1, m2, m3, true, false);
					TC004(m1, m2, m3, true, false);
				}
			}

		}
	}


	/**
		Open a temp table several time swith different modes and ensure the
		correct behaviour (most severe open wins).

		@exception T_Fail Unexpected behaviour from the API
		@exception StandardException Unexpected exception from the implementation
	*/
	protected void TC004(int mode1, int mode2, int mode3, boolean doCommit, boolean closeThem) throws StandardException, T_Fail {

		String testInfo = "TC004 mode1 " + mode1 + " mode2 " + mode2 + " mode3 " + mode3 +
			" doCommit " + doCommit + " closeThem "  + closeThem;
		REPORT("start " + testInfo);

		Transaction t = t_util.t_startTransaction();		

		long cid = t_util.t_addContainer(t, ContainerHandle.TEMPORARY_SEGMENT);

		REPORT("TC004 container id = " + cid);

		t_util.setOpenMode(openMode | mode1);	
		ContainerHandle c1 = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);
		populateTempTable(c1);
		if (closeThem)
			c1.close();

		t_util.setOpenMode(openMode | mode2);
		ContainerHandle c2 = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);
		if (closeThem)
			c2.close();

		t_util.setOpenMode(openMode | mode3);
		ContainerHandle c3 = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);
		if (closeThem)
			c2.close();

		if (doCommit)
			t_util.t_commit(t);
		else
			t_util.t_abort(t);

		int fullMode = mode1 | mode2 | mode3;

		if ((fullMode & ContainerHandle.MODE_DROP_ON_COMMIT) == ContainerHandle.MODE_DROP_ON_COMMIT) {
			// table should have disappeared ...
			ContainerKey id = new ContainerKey(ContainerHandle.TEMPORARY_SEGMENT, cid);
			ContainerHandle cd = t.openContainer(id, ContainerHandle.MODE_READONLY);
			if (cd != null)
				throw T_Fail.testFailMsg("Dropped Container should not open");

		} else if (!doCommit 
			|| ((fullMode & ContainerHandle.MODE_TRUNCATE_ON_COMMIT) == ContainerHandle.MODE_TRUNCATE_ON_COMMIT)) {
			// table should be empty
			ContainerHandle ce = t_util.t_openContainer(t, ContainerHandle.TEMPORARY_SEGMENT, cid, true);		
			
			Page page = t_util.t_getPage(ce, ContainerHandle.FIRST_PAGE_NUMBER);

			t_util.t_checkEmptyPage(page);
			page.unlatch();
			page = null;
		}

		t_util.t_commit(t);

		t.close();

		PASS(testInfo);
	}

    
    /**
     * Privileged lookup of the ContextService. Must be private so that user code
     * can't call this entry point.
     */
    private  static  ContextService    getContextService()
    {
        return AccessController.doPrivileged
            (
             new PrivilegedAction<ContextService>()
             {
                 public ContextService run()
                 {
                     return ContextService.getFactory();
                 }
             }
             );
    }

    
    /**
     * Privileged Monitor lookup. Must be private so that user code
     * can't call this entry point.
     */
    private  static  ModuleFactory  getMonitor()
    {
        return AccessController.doPrivileged
            (
             new PrivilegedAction<ModuleFactory>()
             {
                 public ModuleFactory run()
                 {
                     return Monitor.getMonitor();
                 }
             }
             );
    }

    /**
     * Privileged startup. Must be private so that user code
     * can't call this entry point.
     */
    private  static  Object createPersistentService( final String factoryInterface, final String serviceName, final Properties properties ) 
        throws StandardException
    {
        try {
            return AccessController.doPrivileged
                (
                 new PrivilegedExceptionAction<Object>()
                 {
                     public Object run()
                         throws StandardException
                     {
                         return Monitor.createPersistentService( factoryInterface, serviceName, properties );
                     }
                 }
                 );
        } catch (PrivilegedActionException pae)
        {
            throw StandardException.plainWrapException( pae );
        }
    }

}

