Package org.apache.derby.impl.sql.catalog

Source Code of org.apache.derby.impl.sql.catalog.TabInfoImpl

/*

   Derby - Class org.apache.derby.impl.sql.catalog.TabInfoImpl

   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.derby.impl.sql.catalog;

import org.apache.derby.iapi.services.io.FormatableBitSet;
import org.apache.derby.iapi.services.sanity.SanityManager;
import org.apache.derby.iapi.services.io.StreamStorable;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.sql.dictionary.CatalogRowFactory;
import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
import org.apache.derby.iapi.sql.execute.ExecIndexRow;
import org.apache.derby.iapi.sql.execute.ExecRow;
import org.apache.derby.iapi.sql.execute.RowChanger;
import org.apache.derby.iapi.sql.execute.TupleFilter;
import org.apache.derby.iapi.sql.Activation;

import org.apache.derby.iapi.store.access.ConglomerateController;
import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
import org.apache.derby.iapi.store.access.Qualifier;
import org.apache.derby.iapi.store.access.ScanController;
import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
import org.apache.derby.iapi.store.access.TransactionController;

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

import org.apache.derby.iapi.types.RowLocation;
import java.util.Properties;

/**
* A poor mans structure used in DataDictionaryImpl.java.
* Used to save heapId, name pairs for non core tables.
*
*/
class TabInfoImpl
{
    /**
     * ROWNOTDUPLICATE is out of range for a row
     * number.  If a return code does not equal
     * this value, then it refers to the row
     * that is a duplicate.
     */
    static  final   int     ROWNOTDUPLICATE = -1;

  private IndexInfoImpl[]        indexes;
  private long            heapConglomerate;
  private int              numIndexesSet;
  private boolean            heapSet;
  private final CatalogRowFactory      crf;

  /**
   * Constructor
   *
   * @param crf        the associated CatalogRowFactory
   */
  TabInfoImpl(CatalogRowFactory crf)
  {
    this.heapConglomerate = -1;
    this.crf = crf;

    int numIndexes = crf.getNumIndexes();

    if (numIndexes > 0)
    {
      indexes = new IndexInfoImpl[numIndexes];

      /* Init indexes */
      for (int indexCtr = 0; indexCtr < numIndexes; indexCtr++)
      {
        indexes[indexCtr] = new IndexInfoImpl(
                      indexCtr,
                      crf);
      }
    }
  }

    /**
     * Get the conglomerate for the heap.
     *
     * @return long     The conglomerate for the heap.
     */
  long getHeapConglomerate()
  {
    return heapConglomerate;
  }

    /**
     * Set the heap conglomerate for this.
     *
     * @param heapConglomerate  The new heap conglomerate.
     */
  void setHeapConglomerate(long heapConglomerate)
  {
    this.heapConglomerate = heapConglomerate;
    heapSet = true;
  }

    /**
     * Get the conglomerate for the specified index.
     *
     * @return long     The conglomerate for the specified index.
     */
  long getIndexConglomerate(int indexID)
  {
    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT(indexes != null,
        "indexes is expected to be non-null");
            if (indexID >= indexes.length)
            {
                SanityManager.THROWASSERT(
                    "indexID (" + indexID + ") is out of range(0-" +
                    indexes.length + ")");
            }
    }

    return indexes[indexID].getConglomerateNumber();
  }

    /**
     * Set the index conglomerate for the table.
     *
     * @param index             Index number for index for table
     * @param indexConglomerate The conglomerate for that index
     */
  void setIndexConglomerate(int index, long indexConglomerate)
  {
    /* Index names must be set before conglomerates.
     * Also verify that we are not setting the same conglomerate
     * twice.
     */
    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT(indexes[index] != null,
        "indexes[index] expected to be non-null");
      SanityManager.ASSERT(indexes[index].getConglomerateNumber() == -1,
        "indexes[index] expected to be -1");
    }
    indexes[index].setConglomerateNumber(indexConglomerate);

    /* We are completely initialized when all indexes have
     * their conglomerates initialized
     */
    numIndexesSet++;
  }

    /**
     * Set the index conglomerate for the table.
     *
     * @param cd    The ConglomerateDescriptor for one of the index
     *              for this table.
     */
    void setIndexConglomerate(ConglomerateDescriptor cd)
  {
    int    index;
    String  indexName = cd.getConglomerateName();

    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT(indexes != null,
        "indexes is expected to be non-null");
    }

    for (index = 0; index < indexes.length; index++)
    {
      /* All index names expected to be set before
       * any conglomerate is set.
       */
      if (SanityManager.DEBUG)
      {
        SanityManager.ASSERT(indexes[index] != null,
          "indexes[index] expected to be non-null");
        SanityManager.ASSERT(indexes[index].getIndexName() != null,
          "indexes[index].getIndexName() expected to be non-null");
      }

      /* Do we have a match? */
      if (indexes[index].getIndexName().equals(indexName))
      {
        indexes[index].setConglomerateNumber(cd.getConglomerateNumber());
        break;
      }
    }

    if (SanityManager.DEBUG)
    {
      if (index == indexes.length)
      {
        SanityManager.THROWASSERT("match not found for " + indexName);
      }
    }

    /* We are completely initialized when all indexIds are initialized */
    numIndexesSet++;
  }

    /**
     * Get the table name.
     *
     * @return String   The table name.
     */
  String getTableName()
  {
    return crf.getCatalogName();
  }

    /**
     * Get the index name.
     *
     * @param indexId   Index number for index for table
     *
     * @return String   The index name.
     */
  String getIndexName(int indexId)
  {
    return indexes[indexId].getIndexName();
  }

    /**
     * Get the CatalogRowFactory for this.
     *
     * @return CatalogRowFactory    The CatalogRowFactory for this.
     */
  CatalogRowFactory getCatalogRowFactory()
  {
    return crf;
  }

    /**
     * Is this fully initialized. 
     * (i.e., is all conglomerate info initialized)
     *
     * @return boolean  Whether or not this is fully initialized.
     */
  boolean isComplete()
  {
    /* We are complete when heap conglomerate and all
     * index conglomerates are set.
     */
    if (! heapSet)
    {
      return false;
    }
    return (indexes == null ||  indexes.length == numIndexesSet);
  }

    /**
     * Get the column count for the specified index number.
     *
     * @param indexNumber   The index number.
     *
     * @return int          The column count for the specified index.
     */
  int getIndexColumnCount(int indexNumber)
  {
    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT(indexes != null,
        "indexes is expected to be non-null");

      if (!(indexNumber < indexes.length))
      {
        SanityManager.THROWASSERT("indexNumber (" + indexNumber + ") is out of range(0-" +
        indexes.length + ")");
      }
    }

    return indexes[indexNumber].getColumnCount();
  }

    /**
     * Get the IndexRowGenerator for the specified index number.
     *
     * @param indexNumber   The index number.
     *
     * @return IndexRowGenerator    The IRG for the specified index number.
     */
  IndexRowGenerator getIndexRowGenerator(int indexNumber)
  {
    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT(indexes != null,
        "indexes is expected to be non-null");
            if (indexNumber >= indexes.length)
            {
                SanityManager.THROWASSERT(
                    "indexNumber (" + indexNumber + ") is out of range(0-" +
                    indexes.length + ")");
            }
    }
    return indexes[indexNumber].getIndexRowGenerator();
  }

    /**
     * Set the IndexRowGenerator for the specified index number.
     *
     * @param indexNumber   The index number.
     * @param irg           The IndexRowGenerator for the specified index number.
     */
  void setIndexRowGenerator(int indexNumber, IndexRowGenerator irg)
  {
    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT(indexes != null,
        "indexes is expected to be non-null");
            if (indexNumber >= indexes.length)
            {
                SanityManager.THROWASSERT(
                    "indexNumber (" + indexNumber + ") is out of range(0-" +
                    indexes.length + ")");
            }
    }

    indexes[indexNumber].setIndexRowGenerator(irg);
  }

    /**
     * Get the number of indexes on this catalog.
     *
     * @return int  The number of indexes on this catalog.
     */
  int getNumberOfIndexes()
  {
    if (indexes == null)
    {
      return 0;
    }
    else
    {
      return indexes.length;
    }
  }

    /**
     * Get the base column position for a column within a catalog
     * given the (0-based) index number for this catalog and the
     * (0-based) column number for the column within the index.
     *
     * @param indexNumber   The index number
     * @param colNumber     The column number within the index
     *
     * @return int      The base column position for the column.
     */
  int getBaseColumnPosition(int indexNumber, int colNumber)
  {
    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT(indexes != null,
        "indexes is expected to be non-null");
      if (indexNumber >= indexes.length)
      {
        SanityManager.THROWASSERT("indexNumber (" + indexNumber + ") is out of range(0-" +
          indexes.length + ")");
      }
    }

    return indexes[indexNumber].getBaseColumnPosition(colNumber);
  }

    /**
     * Return whether or not this index is declared unique
     *
     * @param indexNumber   The index number
     *
     * @return boolean      Whether or not this index is declared unique
     */
  boolean isIndexUnique(int indexNumber)
  {
    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT(indexes != null,
        "indexes is expected to be non-null");

      if (indexNumber >= indexes.length)
      {
        SanityManager.THROWASSERT("indexNumber (" + indexNumber + ") is out of range(0-" +
          indexes.length + ")");
      }
    }

    return indexes[indexNumber].isIndexUnique();
  }

  /**
   * Inserts a base row into a catalog and inserts all the corresponding
   * index rows.
   *
   *  @param  row      row to insert
   *  @param  tc      transaction
   *  @return  row number (>= 0) if duplicate row inserted into an index
   *      ROWNOTDUPLICATE otherwise
   *
   * @exception StandardException    Thrown on failure
   */
  int insertRow( ExecRow row, TransactionController tc)
    throws StandardException
  {

    RowLocation[]       notUsed = new RowLocation[1];

    return insertRowListImpl(new ExecRow[] {row},tc,notUsed);
  }

  /**
   * Inserts a list of base rows into a catalog and inserts all the corresponding
   * index rows.
   *
   *  @param  rowList    List of rows to insert
   *  @param  tc      transaction controller
   *
   *
   *  @return  row  number (>= 0) if duplicate row inserted into an index
   *      ROWNOTDUPLICATE otherwise
   *
   * @exception StandardException    Thrown on failure
   */
  int insertRowList(ExecRow[] rowList, TransactionController tc )
    throws StandardException
  {
    RowLocation[]       notUsed = new RowLocation[1];

    return insertRowListImpl(rowList,tc,notUsed);
  }

  /**
    Insert logic to insert a list of rows into a table. This logic has two
    odd features.

    <OL>
    <LI>Returns an indication if any returned row was a duplicate.
    <LI>Returns the RowLocation of the last row inserted.
    </OL>
    @param rowList the list of rows to insert
    @param tc  transaction controller
    @param rowLocationOut on output rowLocationOut[0] is set to the
           last RowLocation inserted.
    @return row number (>= 0) if duplicate row inserted into an index
          ROWNOTDUPLICATE otherwise
   */
  private int insertRowListImpl(ExecRow[] rowList, TransactionController tc,
                                  RowLocation[] rowLocationOut)
    throws StandardException
  {
    ConglomerateController    heapController;
    RowLocation          heapLocation;
    ExecIndexRow        indexableRow;
    int              insertRetCode;
    int              retCode = ROWNOTDUPLICATE;
    int              indexCount = crf.getNumIndexes();
    ConglomerateController[]  indexControllers = new ConglomerateController[ indexCount ];

    // Open the conglomerates
    heapController =
            tc.openConglomerate(
                getHeapConglomerate(),
                false,
        TransactionController.OPENMODE_FORUPDATE,
                TransactionController.MODE_RECORD,
                TransactionController.ISOLATION_REPEATABLE_READ);
   
    /* NOTE: Due to the lovely problem of trying to add
     * a new column to syscolumns and an index on that
     * column during upgrade, we have to deal with the
     * issue of the index not existing yet.  So, it's okay
     * if the index doesn't exist yet.  (It will magically
     * get created at a later point during upgrade.)
     */

    for ( int ictr = 0; ictr < indexCount; ictr++ )
    {
      long conglomNumber = getIndexConglomerate(ictr);
      if (conglomNumber > -1)
      {
        indexControllers[ ictr ] =
                tc.openConglomerate(
                  conglomNumber,
                        false,
            TransactionController.OPENMODE_FORUPDATE,
              TransactionController.MODE_RECORD,
            TransactionController.ISOLATION_REPEATABLE_READ);
      }
    }

    heapLocation = heapController.newRowLocationTemplate();
    rowLocationOut[0]=heapLocation;

    // loop through rows on this list, inserting them into system table
    for (int rowNumber = 0; rowNumber < rowList.length; rowNumber++)
    {
      ExecRow row = rowList[rowNumber];
      // insert the base row and get its new location
      heapController.insertAndFetchLocation(row.getRowArray(), heapLocation);
     
      for ( int ictr = 0; ictr < indexCount; ictr++ )
        {
        if (indexControllers[ ictr ] == null)
        {
          continue;
        }

        // Get an index row based on the base row
        indexableRow = getIndexRowFromHeapRow( getIndexRowGenerator(ictr),
                             heapLocation,
                             row );

        insertRetCode =
                    indexControllers[ ictr ].insert(indexableRow.getRowArray());

        if ( insertRetCode == ConglomerateController.ROWISDUPLICATE )
        {
          retCode = rowNumber;
        }
      }

    }  // end loop through rows on list

    // Close the open conglomerates
    for ( int ictr = 0; ictr < indexCount; ictr++ )
    {
      if (indexControllers[ ictr ] == null)
      {
        continue;
      }

      indexControllers[ ictr ].close();
    }
    heapController.close();

    return  retCode;
  }


    /**
      * Given a key row, delete all matching heap rows and their index
      * rows.
      * <p>
      * LOCKING: row locking if there is a key; otherwise,
      * table locking.
      *
      * @param  tc          transaction controller
      * @param  key         key to delete by.
      * @param  indexNumber Key is appropriate for this index.
      * @return the number of rows deleted. If key is not unique,
      *         this may be more than one.
      * @exception StandardException        Thrown on failure
      */
  int deleteRow( TransactionController tc, ExecIndexRow key, int indexNumber )
    throws StandardException
  {
    // Always row locking
    return  deleteRows(tc,
               key,
               ScanController.GE,
               null,
               null,
               key,
               ScanController.GT,
               indexNumber,
               true);
  }

  int deleteRow( TransactionController tc, ExecIndexRow key,
              int indexNumber, boolean wait)
    throws StandardException
  {
    //  Always row locking
    return  deleteRows(tc,
               key,
               ScanController.GE,
               null,
               null,
               key,
               ScanController.GT,
               indexNumber,
               wait);
  }
 
    /**
      * Delete the set of rows defined by a scan on an index
      * from the table. Most of the parameters are simply passed
      * to TransactionController.openScan. Please refer to the
      * TransactionController documentation for details.
      * <p>
      * LOCKING: row locking if there is a start and a stop
      * key; otherwise, table locking
      *
      * @param  tc          transaction controller
      * @param  startKey    key to start the scan.
      * @param  startOp     operation to start the scan.
      * @param  stopKey     key to start the scan.
      * @param  qualifier   a qualifier for the scan.
      * @param  filter      filter on base rows
      * @param  stopOp      operation to start the scan.
      * @param  indexNumber Key is appropriate for this index.
      * @return the number of rows deleted.
      * @exception StandardException        Thrown on failure
      * @see TransactionController#openScan
      */
  int deleteRows(TransactionController tc,
              ExecIndexRow startKey,
              int startOp,
              Qualifier[][] qualifier,
              TupleFilter filter,
              ExecIndexRow stopKey,
              int stopOp,
              int indexNumber) throws StandardException
    {
    return  deleteRows(tc,
           startKey,
           startOp,
           qualifier,
           filter,
           stopKey,
           stopOp,
           indexNumber,
           true);
    }

  /**
   * @inheritDoc
   */
  private int deleteRows(TransactionController tc,
              ExecIndexRow startKey,
              int startOp,
              Qualifier[][] qualifier,
              TupleFilter filter,
              ExecIndexRow stopKey,
              int stopOp,
              int indexNumber,
              boolean wait)
     throws StandardException
  {
    ConglomerateController    heapCC;
    ScanController        drivingScan;
    ExecIndexRow         drivingIndexRow;
    RowLocation          baseRowLocation;
    RowChanger           rc;
    ExecRow            baseRow = crf.makeEmptyRow();
    int                         rowsDeleted = 0;
    boolean            passedFilter = true;
   
    rc = getRowChanger( tc, (int[])null,baseRow );

    /*
    ** If we have a start and a stop key, then we are going to
    ** get row locks, otherwise, we are getting table locks.
    ** This may be excessive locking for the case where there
    ** is a start key and no stop key or vice versa.
    */
    int lockMode = ((startKey != null) && (stopKey != null)) ?
        tc.MODE_RECORD :
        tc.MODE_TABLE;

    /*
    ** Don't use level 3 if we have the same start/stop key.
    */
    int isolation =
            ((startKey != null) && (stopKey != null) && (startKey == stopKey)) ?
        TransactionController.ISOLATION_REPEATABLE_READ :
        TransactionController.ISOLATION_SERIALIZABLE;

    // Row level locking
    rc.open(lockMode, wait);

    DataValueDescriptor[] startKeyRow =
            startKey == null ? null : startKey.getRowArray();

    DataValueDescriptor[] stopKeyRow =
            stopKey == null  ? null : stopKey.getRowArray();

    /* Open the heap conglomerate */
    heapCC = tc.openConglomerate(
                    getHeapConglomerate(),
                    false,
                    (TransactionController.OPENMODE_FORUPDATE |
                            ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
                    lockMode,
                    TransactionController.ISOLATION_REPEATABLE_READ);

    drivingScan = tc.openScan(
      getIndexConglomerate(indexNumber)// conglomerate to open
      false, // don't hold open across commit
      (TransactionController.OPENMODE_FORUPDATE |
        ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
            lockMode,
      isolation,
      (FormatableBitSet) null, // all fields as objects
      startKeyRow,   // start position - first row
            startOp,      // startSearchOperation
      qualifier, //scanQualifier
      stopKeyRow,   // stop position - through last row
            stopOp);     // stopSearchOperation

    // Get an index row based on the base row
    drivingIndexRow = getIndexRowFromHeapRow(
      getIndexRowGenerator( indexNumber ),
      heapCC.newRowLocationTemplate(),
      crf.makeEmptyRow());

    while (drivingScan.fetchNext(drivingIndexRow.getRowArray()))
    {
      baseRowLocation = (RowLocation)
            drivingIndexRow.getColumn(drivingIndexRow.nColumns());

      boolean base_row_exists =
                heapCC.fetch(
                    baseRowLocation, baseRow.getRowArray(), (FormatableBitSet) null);

            if (SanityManager.DEBUG)
            {
                // it can not be possible for heap row to disappear while
                // holding scan cursor on index at ISOLATION_REPEATABLE_READ.
                SanityManager.ASSERT(base_row_exists, "base row not found");
            }

      // only delete rows which pass the base-row filter
      if ( filter != null ) { passedFilter = filter.execute( baseRow ).equals( true ); }
      if ( passedFilter )
      {
        rc.deleteRow( baseRow, baseRowLocation );
        rowsDeleted++;
      }
    }

    heapCC.close();
    drivingScan.close();
    rc.close();
   
    return rowsDeleted;
  }

    /**
      * Given a key row, return the first matching heap row.
      * <p>
      * LOCKING: shared row locking.
      *
      * @param  tc          transaction controller
      * @param  key         key to read by.
      * @param  indexNumber Key is appropriate for this index.
      * @exception StandardException        Thrown on failure
      */
  ExecRow getRow( TransactionController tc,
            ExecIndexRow key,
            int indexNumber )
    throws StandardException
  {
    ConglomerateController    heapCC;

    /* Open the heap conglomerate */
    heapCC = tc.openConglomerate(
                    getHeapConglomerate(),
                    false,
                    0,             // for read only
                    TransactionController.MODE_RECORD,
                    TransactionController.ISOLATION_REPEATABLE_READ);

    try { return getRow( tc, heapCC, key, indexNumber ); }
    finally { heapCC.close(); }
  }

  /**
   * Given an index row and index number return the RowLocation
   * in the heap of the first matching row.
   * Used by the autoincrement code to get the RowLocation in
   * syscolumns given a <tablename, columname> pair.
   *
   * @see DataDictionaryImpl#computeRowLocation(TransactionController, TableDescriptor, String)
   *
   * @param tc      Transaction Controller to use.
   * @param key      Index Row to search in the index.
   * @param indexNumber Identifies the index to use.
   *
   * @exception      StandardException thrown on failure.
   */
  RowLocation getRowLocation(TransactionController tc,
                    ExecIndexRow key,
                    int indexNumber)
        throws StandardException
  {
    ConglomerateController    heapCC;
    heapCC = tc.openConglomerate(
                    getHeapConglomerate(),
                    false,
                    0,             // for read only
                    TransactionController.MODE_RECORD,
                    TransactionController.ISOLATION_REPEATABLE_READ);

    try
    {
      RowLocation rl[] = new RowLocation[1];
      ExecRow notUsed = getRowInternal(tc, heapCC, key, indexNumber, rl);
      return rl[0];
    }
    finally
    {
      heapCC.close();
    }
  }
    /**
      * Given a key row, return the first matching heap row.
      * <p>
      * LOCKING: shared row locking.
      *
      * @param  tc          transaction controller
      * @param  heapCC      heap to look in
      * @param  key         key to read by.
      * @param  indexNumber Key is appropriate for this index.
      * @exception StandardException        Thrown on failure
      */
  ExecRow getRow( TransactionController tc,
               ConglomerateController heapCC,
               ExecIndexRow key,
               int indexNumber)
             
     throws StandardException
  {
    RowLocation rl[] = new RowLocation[1];
    return getRowInternal(tc, heapCC, key, indexNumber, rl);
  }

  /**
    * @exception StandardException    Thrown on failure
    */
  private ExecRow getRowInternal( TransactionController tc,
                  ConglomerateController heapCC,
                  ExecIndexRow key,
                  int indexNumber,
                  RowLocation rl[])

     throws StandardException
  {
    ScanController        drivingScan;
    ExecIndexRow         drivingIndexRow;
    RowLocation          baseRowLocation;
    ExecRow            baseRow = crf.makeEmptyRow();

    drivingScan = tc.openScan(
      getIndexConglomerate(indexNumber),
                           // conglomerate to open
      false,               // don't hold open across commit
      0,                   // open for read
            TransactionController.MODE_RECORD,
            TransactionController.ISOLATION_REPEATABLE_READ,
      (FormatableBitSet) null,      // all fields as objects
      key.getRowArray(),   // start position - first row
            ScanController.GE,   // startSearchOperation
      null,                //scanQualifier
      key.getRowArray(),   // stop position - through last row
            ScanController.GT)// stopSearchOperation

    // Get an index row based on the base row
    drivingIndexRow = getIndexRowFromHeapRow(
      getIndexRowGenerator( indexNumber ),
      heapCC.newRowLocationTemplate(),
      crf.makeEmptyRow());

    try  {
      if (drivingScan.fetchNext(drivingIndexRow.getRowArray()))
      {
        rl[0] = baseRowLocation = (RowLocation)
          drivingIndexRow.getColumn(drivingIndexRow.nColumns());
        boolean base_row_exists =
                    heapCC.fetch(
                        baseRowLocation, baseRow.getRowArray(), (FormatableBitSet) null);

                if (SanityManager.DEBUG)
                {
                    // it can not be possible for heap row to disappear while
                    // holding scan cursor on index at ISOLATION_REPEATABLE_READ.
                    SanityManager.ASSERT(base_row_exists, "base row not found");
                }

        return baseRow;
      }
      else
      {
        return null;
      }
    }

    finally {
      drivingScan.close();
    }
  }

  /**
   * Updates a base row in a catalog and updates all the corresponding
   * index rows.
   *
   *  @param  key      key row
   *  @param  newRow    new version of the row
   *  @param  indexNumber  index that key operates
   *  @param  indicesToUpdate  array of booleans, one for each index on the catalog.
   *              if a boolean is true, that means we must update the
   *              corresponding index because changes in the newRow
   *              affect it.
   *  @param  colsToUpdate  array of ints indicating which columns (1 based)
   *              to update.  If null, do all.
   *  @param  tc      transaction controller
   *
   * @exception StandardException    Thrown on failure
   */
  void updateRow( ExecIndexRow        key,
               ExecRow          newRow,
               int            indexNumber,
               boolean[]        indicesToUpdate,
               int[]          colsToUpdate,
               TransactionController  tc)
    throws StandardException
  {
    ExecRow[] newRows = new ExecRow[1];
    newRows[0] = newRow;
    updateRow(key, newRows, indexNumber, indicesToUpdate, colsToUpdate, tc);
  }

  /**
   * Updates a set of base rows in a catalog with the same key on an index
   * and updates all the corresponding index rows.
   *
   *  @param  key      key row
   *  @param  newRows    new version of the array of rows
   *  @param  indexNumber  index that key operates
   *  @param  indicesToUpdate  array of booleans, one for each index on the catalog.
   *              if a boolean is true, that means we must update the
   *              corresponding index because changes in the newRow
   *              affect it.
   *  @param  colsToUpdate  array of ints indicating which columns (1 based)
   *              to update.  If null, do all.
   *  @param  tc      transaction controller
   *
   * @exception StandardException    Thrown on failure
   */
  void updateRow( ExecIndexRow        key,
               ExecRow[]        newRows,
               int            indexNumber,
               boolean[]        indicesToUpdate,
               int[]          colsToUpdate,
               TransactionController  tc )
    throws StandardException
  {
    ConglomerateController    heapCC;
    ScanController        drivingScan;
    ExecIndexRow         drivingIndexRow;
    RowLocation          baseRowLocation;
    ExecRow            baseRow = crf.makeEmptyRow();

    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT( indicesToUpdate.length == crf.getNumIndexes(),
                 "Wrong number of indices." );
    }

    RowChanger           rc  = getRowChanger( tc, colsToUpdate,baseRow );

    // Row level locking
    rc.openForUpdate(indicesToUpdate, TransactionController.MODE_RECORD, true);

    /* Open the heap conglomerate */
    heapCC = tc.openConglomerate(
                    getHeapConglomerate(),
                    false,
                    TransactionController.OPENMODE_FORUPDATE,
                    TransactionController.MODE_RECORD,
                    TransactionController.ISOLATION_REPEATABLE_READ);

    drivingScan = tc.openScan(
      getIndexConglomerate(indexNumber)// conglomerate to open
      false, // don't hold open across commit
      TransactionController.OPENMODE_FORUPDATE,
            TransactionController.MODE_RECORD,
            TransactionController.ISOLATION_REPEATABLE_READ,
      (FormatableBitSet) null,     // all fields as objects
      key.getRowArray(),   // start position - first row
            ScanController.GE,      // startSearchOperation
      null, //scanQualifier
      key.getRowArray(),   // stop position - through last row
            ScanController.GT);     // stopSearchOperation

    // Get an index row based on the base row
    drivingIndexRow = getIndexRowFromHeapRow(
      getIndexRowGenerator( indexNumber ),
      heapCC.newRowLocationTemplate(),
      crf.makeEmptyRow());

    int rowNum = 0;
    while (drivingScan.fetchNext(drivingIndexRow.getRowArray()))
    {
      baseRowLocation = (RowLocation)
            drivingIndexRow.getColumn(drivingIndexRow.nColumns());
      boolean base_row_exists =
                heapCC.fetch(
                    baseRowLocation, baseRow.getRowArray(), (FormatableBitSet) null);

            if (SanityManager.DEBUG)
            {
                // it can not be possible for heap row to disappear while
                // holding scan cursor on index at ISOLATION_REPEATABLE_READ.
                SanityManager.ASSERT(base_row_exists, "base row not found");
            }
     
      rc.updateRow(baseRow, (rowNum == newRows.length - 1) ?
            newRows[rowNum] : newRows[rowNum++], baseRowLocation );
    }
    rc.finish();
    heapCC.close();
    drivingScan.close();
    rc.close();
  }

  /**
   * Get the Properties associated with creating the heap.
   *
   * @return The Properties associated with creating the heap.
   */
  Properties getCreateHeapProperties()
  {
    return crf.getCreateHeapProperties();
  }

  /**
   * Get the Properties associated with creating the specified index.
   *
   * @param indexNumber  The specified index number.
   *
   * @return The Properties associated with creating the specified index.
   */
  Properties getCreateIndexProperties(int indexNumber)
  {
    return crf.getCreateIndexProperties(indexNumber);
  }

  /**
    *  Gets a row changer for this catalog.
    *
    *  @param  tc  transaction controller
    *  @param  changedCols  the columns to change (1 based), may be null
    * @param  baseRow used to detemine column types at creation time
    *         only. The row changer does ***Not*** keep a referance to
    *         this row or change it in any way.
    *
    *  @return  a row changer for this catalog.
    * @exception StandardException    Thrown on failure
    */
  private  RowChanger  getRowChanger( TransactionController tc,
                     int[] changedCols,
                     ExecRow baseRow)
    throws StandardException
  {
    RowChanger           rc;
    int              indexCount = crf.getNumIndexes();
    IndexRowGenerator[]      irgs = new IndexRowGenerator[ indexCount ];
    long[]            cids = new long[ indexCount ];

    if (SanityManager.DEBUG)
    {
      if (changedCols != null)
      {
        for (int i = changedCols.length - 1; i >= 0; i--)
        {
          SanityManager.ASSERT(changedCols[i] != 0,
            "Column id is 0, but should be 1 based");
        }
      }
    }

    for ( int ictr = 0; ictr < indexCount; ictr++ )
    {
      irgs[ictr] = getIndexRowGenerator(ictr);
      cids[ictr] = getIndexConglomerate(ictr);
    }

    rc = crf.getExecutionFactory().getRowChanger(getHeapConglomerate(),
                      (StaticCompiledOpenConglomInfo) null,
                      (DynamicCompiledOpenConglomInfo) null,
                      irgs,
                      cids,
                      (StaticCompiledOpenConglomInfo[]) null,
                      (DynamicCompiledOpenConglomInfo[]) null,
                      crf.getHeapColumnCount(),
                      tc,
                      changedCols,
                      getStreamStorableHeapColIds(baseRow),
                      (Activation) null);
    return  rc;
  }

  private boolean computedStreamStorableHeapColIds = false;
  private int[] streamStorableHeapColIds;
  private int[] getStreamStorableHeapColIds(ExecRow baseRow) throws StandardException
  {
    if (!computedStreamStorableHeapColIds)
    {
      int sshcidLen = 0;
      //
      //Compute the length of streamStorableHeapColIds
      //One entry for each column id.
      DataValueDescriptor[] ra = baseRow.getRowArray();
      for(int ix=0;ix<ra.length;ix++)
        if (ra[ix] instanceof StreamStorable) sshcidLen++;

      //
      //If we have some streamStorableHeapColIds we
      //allocate an array to remember them and fill in
      //the array with the 0 based column ids. If we
      //have none leave streamStorableHeapColIds Null.
      if (sshcidLen > 0)
      {
        streamStorableHeapColIds = new int[sshcidLen];
        int sshcidOffset=0;
        for(int ix=0;ix<ra.length;ix++)
          if (ra[ix] instanceof StreamStorable)
             streamStorableHeapColIds[sshcidOffset++] = ix;
      }
      computedStreamStorableHeapColIds = true;
    }
    return streamStorableHeapColIds;
  }

  /**
   * Get an index row based on a row from the heap.
   *
   * @param irg    IndexRowGenerator to use
   * @param rl    RowLocation for heap
   * @param heapRow  Row from the heap
   *
   * @return ExecIndexRow  Index row.
   *
   * @exception StandardException    Thrown on error
   */
  private ExecIndexRow getIndexRowFromHeapRow(IndexRowGenerator irg,
                   RowLocation rl,
                   ExecRow heapRow)
    throws StandardException
  {
    ExecIndexRow    indexRow;

    indexRow = irg.getIndexRowTemplate();
    // Get an index row based on the base row
    irg.getIndexRow(heapRow, rl, indexRow, (FormatableBitSet) null);

    return indexRow;
  }

  public String toString()
  {
    if (SanityManager.DEBUG)
    {
      return "name: " + this.getTableName() +
        "\n\theapCongolomerate: "+heapConglomerate +
        "\n\tnumIndexes: " + ((indexes != null) ? indexes.length : 0) +
        "\n\tnumIndexesSet: " + numIndexesSet +
        "\n\theapSet: " + heapSet +
        "\n";
    }
    else
    {
      return "";
    }
  }
}
TOP

Related Classes of org.apache.derby.impl.sql.catalog.TabInfoImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.