Search in sources :

Example 36 with ScanController

use of org.apache.derby.iapi.store.access.ScanController in project derby by apache.

the class AlterTableConstantAction method getSemiRowCount.

// class implementation
/**
 * Return the "semi" row count of a table.  We are only interested in
 * whether the table has 0, 1 or > 1 rows.
 *
 * @return Number of rows (0, 1 or > 1) in table.
 *
 * @exception StandardException		Thrown on failure
 */
private int getSemiRowCount(TransactionController tc) throws StandardException {
    int numRows = 0;
    ScanController sc = tc.openScan(td.getHeapConglomerateId(), // hold
    false, // open read only
    0, TransactionController.MODE_TABLE, TransactionController.ISOLATION_SERIALIZABLE, // scanColumnList
    RowUtil.EMPTY_ROW_BITSET, // start position
    null, // startSearchOperation
    ScanController.GE, // scanQualifier
    null, // stop position - through last row
    null, // stopSearchOperation
    ScanController.GT);
    while (sc.next()) {
        numRows++;
        // We're only interested in whether the table has 0, 1 or > 1 rows
        if (numRows == 2) {
            break;
        }
    }
    sc.close();
    return numRows;
}
Also used : ScanController(org.apache.derby.iapi.store.access.ScanController) GroupFetchScanController(org.apache.derby.iapi.store.access.GroupFetchScanController)

Example 37 with ScanController

use of org.apache.derby.iapi.store.access.ScanController in project derby by apache.

the class AlterTableConstantAction method defragmentRows.

/**
 * Defragment rows in the given table.
 * <p>
 * Scans the rows at the end of a table and moves them to free spots
 * towards the beginning of the table.  In the same transaction all
 * associated indexes are updated to reflect the new location of the
 * base table row.
 * <p>
 * After a defragment pass, if was possible, there will be a set of
 * empty pages at the end of the table which can be returned to the
 * operating system by calling truncateEnd().  The allocation bit
 * maps will be set so that new inserts will tend to go to empty and
 * half filled pages starting from the front of the conglomerate.
 *
 * @param tc                transaction controller to use to do updates.
 */
private void defragmentRows(TransactionController tc) throws StandardException {
    GroupFetchScanController base_group_fetch_cc = null;
    int num_indexes = 0;
    int[][] index_col_map = null;
    ScanController[] index_scan = null;
    ConglomerateController[] index_cc = null;
    DataValueDescriptor[][] index_row = null;
    TransactionController nested_tc = null;
    try {
        nested_tc = tc.startNestedUserTransaction(false, true);
        switch(td.getTableType()) {
            /* Skip views and vti tables */
            case TableDescriptor.VIEW_TYPE:
            case TableDescriptor.VTI_TYPE:
                return;
            // DERBY-719,DERBY-720
            default:
                break;
        }
        /* Get a row template for the base table */
        ExecRow br = lcc.getLanguageConnectionFactory().getExecutionFactory().getValueRow(td.getNumberOfColumns());
        /* Fill the row with nulls of the correct type */
        for (ColumnDescriptor cd : td.getColumnDescriptorList()) {
            br.setColumn(cd.getPosition(), cd.getType().getNull());
        }
        DataValueDescriptor[][] row_array = new DataValueDescriptor[100][];
        row_array[0] = br.getRowArray();
        RowLocation[] old_row_location_array = new RowLocation[100];
        RowLocation[] new_row_location_array = new RowLocation[100];
        // Create the following 3 arrays which will be used to update
        // each index as the scan moves rows about the heap as part of
        // the compress:
        // index_col_map - map location of index cols in the base row,
        // ie. index_col_map[0] is column offset of 1st
        // key column in base row.  All offsets are 0
        // based.
        // index_scan - open ScanController used to delete old index row
        // index_cc   - open ConglomerateController used to insert new
        // row
        ConglomerateDescriptor[] conglom_descriptors = td.getConglomerateDescriptors();
        // conglom_descriptors has an entry for the conglomerate and each
        // one of it's indexes.
        num_indexes = conglom_descriptors.length - 1;
        // if indexes exist, set up data structures to update them
        if (num_indexes > 0) {
            // allocate arrays
            index_col_map = new int[num_indexes][];
            index_scan = new ScanController[num_indexes];
            index_cc = new ConglomerateController[num_indexes];
            index_row = new DataValueDescriptor[num_indexes][];
            setup_indexes(nested_tc, td, index_col_map, index_scan, index_cc, index_row);
        }
        /* Open the heap for reading */
        base_group_fetch_cc = nested_tc.defragmentConglomerate(td.getHeapConglomerateId(), false, true, TransactionController.OPENMODE_FORUPDATE, TransactionController.MODE_TABLE, TransactionController.ISOLATION_SERIALIZABLE);
        int num_rows_fetched;
        while ((num_rows_fetched = base_group_fetch_cc.fetchNextGroup(row_array, old_row_location_array, new_row_location_array)) != 0) {
            if (num_indexes > 0) {
                for (int row = 0; row < num_rows_fetched; row++) {
                    for (int index = 0; index < num_indexes; index++) {
                        fixIndex(row_array[row], index_row[index], old_row_location_array[row], new_row_location_array[row], index_cc[index], index_scan[index], index_col_map[index]);
                    }
                }
            }
        }
        // TODO - It would be better if commits happened more frequently
        // in the nested transaction, but to do that there has to be more
        // logic to catch a ddl that might jump in the middle of the
        // above loop and invalidate the various table control structures
        // which are needed to properly update the indexes.  For example
        // the above loop would corrupt an index added midway through
        // the loop if not properly handled.  See DERBY-1188.
        nested_tc.commit();
    } finally {
        /* Clean up before we leave */
        if (base_group_fetch_cc != null) {
            base_group_fetch_cc.close();
            base_group_fetch_cc = null;
        }
        if (num_indexes > 0) {
            for (int i = 0; i < num_indexes; i++) {
                if (index_scan != null && index_scan[i] != null) {
                    index_scan[i].close();
                    index_scan[i] = null;
                }
                if (index_cc != null && index_cc[i] != null) {
                    index_cc[i].close();
                    index_cc[i] = null;
                }
            }
        }
        if (nested_tc != null) {
            nested_tc.destroy();
        }
    }
}
Also used : ScanController(org.apache.derby.iapi.store.access.ScanController) GroupFetchScanController(org.apache.derby.iapi.store.access.GroupFetchScanController) ConglomerateController(org.apache.derby.iapi.store.access.ConglomerateController) ColumnDescriptor(org.apache.derby.iapi.sql.dictionary.ColumnDescriptor) GroupFetchScanController(org.apache.derby.iapi.store.access.GroupFetchScanController) ConglomerateDescriptor(org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor) ExecRow(org.apache.derby.iapi.sql.execute.ExecRow) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) TransactionController(org.apache.derby.iapi.store.access.TransactionController) RowLocation(org.apache.derby.iapi.types.RowLocation)

Example 38 with ScanController

use of org.apache.derby.iapi.store.access.ScanController in project derby by apache.

the class IndexChanger method insertAndCheckDups.

/**
 * Insert the given row into the given conglomerate and check for duplicate
 * key error.
 *
 * @param row	The row to insert
 *
 * @exception StandardException     Thrown on duplicate key error unless
 *                                  we have a deferred constraint. In that
 *                                  index rows are saved for checking
 *                                  on commit.
 */
private void insertAndCheckDups(ExecIndexRow row) throws StandardException {
    openIndexCC();
    int insertStatus;
    final DataValueDescriptor[] rowArray = row.getRowArray();
    if (deferrable) {
        insertStatus = indexCC.insert(row.getRowArray());
        if (SanityManager.DEBUG) {
            // deferrable: we use a non-unique index
            SanityManager.ASSERT(insertStatus != ConglomerateController.ROWISDUPLICATE);
        }
        final DataValueDescriptor[] key = new DataValueDescriptor[rowArray.length - 1];
        System.arraycopy(rowArray, 0, key, 0, key.length);
        // If the constraint mode is deferred, perform the check without
        // waiting for any locks; we will just presume any lock conflicts
        // constitute duplicates (not always the case), and check those keys
        // again at commit time.
        final boolean deferred = lcc.isEffectivelyDeferred(lcc.getCurrentSQLSessionContext(activation), getUniqueConstraintId());
        // TODO add assert getUniqueConstraintId() != null
        ScanController idxScan = tc.openScan(indexCID, false, (deferred ? TransactionController.OPENMODE_LOCK_ROW_NOWAIT : 0), TransactionController.MODE_RECORD, TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK, // retrieve all fields
        (FormatableBitSet) null, key, // startSearchOp
        ScanController.GE, null, key, ScanController.GT);
        boolean duplicate = false;
        try {
            final boolean foundOne = idxScan.next();
            if (SanityManager.DEBUG) {
                SanityManager.ASSERT(foundOne, "IndexChanger: inserted row gone?");
            }
            duplicate = foundOne && idxScan.next();
        } catch (StandardException e) {
            if ((e.getSQLState().equals(SQLState.LOCK_TIMEOUT) || e.getSQLState().equals(SQLState.DEADLOCK)) && deferred) {
                // Assume there is a duplicate, so we'll check again at
                // commit time.
                duplicate = true;
            } else {
                throw e;
            }
        }
        if (duplicate && irg.isUniqueWithDuplicateNulls()) {
            int keyParts = rowArray.length - 1;
            for (int i = 0; i < keyParts; i++) {
                // Keys with null in it are always unique
                if (rowArray[i].isNull()) {
                    duplicate = false;
                    break;
                }
            }
        }
        if (duplicate) {
            if (deferred) {
                // Save duplicate row so we can check at commit time there is
                // no longer any duplicate.
                deferredDuplicates = DeferredConstraintsMemory.rememberDuplicate(lcc, deferredDuplicates, getUniqueConstraintId(), row.getRowArray());
            } else {
                // the constraint is not deferred, so throw
                insertStatus = ConglomerateController.ROWISDUPLICATE;
            }
        }
    } else {
        // not a deferred constraint
        insertStatus = indexCC.insert(row.getRowArray());
    }
    if (insertStatus == ConglomerateController.ROWISDUPLICATE) {
        /*
			** We have a duplicate key error. 
			*/
        String indexOrConstraintName = indexName;
        // now get table name, and constraint name if needed
        LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
        DataDictionary dd = lcc.getDataDictionary();
        // get the descriptors
        ConglomerateDescriptor cd = dd.getConglomerateDescriptor(indexCID);
        UUID tableID = cd.getTableID();
        TableDescriptor td = dd.getTableDescriptor(tableID);
        String tableName = td.getName();
        if (// no index name passed in
        indexOrConstraintName == null) {
            ConstraintDescriptor conDesc = dd.getConstraintDescriptor(td, cd.getUUID());
            indexOrConstraintName = conDesc.getConstraintName();
        }
        StandardException se = StandardException.newException(SQLState.LANG_DUPLICATE_KEY_CONSTRAINT, indexOrConstraintName, tableName);
        throw se;
    } else {
        if (SanityManager.DEBUG) {
            if (insertStatus != 0) {
                SanityManager.THROWASSERT("Unknown insert status " + insertStatus);
            }
        }
    }
}
Also used : ScanController(org.apache.derby.iapi.store.access.ScanController) DataDictionary(org.apache.derby.iapi.sql.dictionary.DataDictionary) ConglomerateDescriptor(org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor) TableDescriptor(org.apache.derby.iapi.sql.dictionary.TableDescriptor) StandardException(org.apache.derby.shared.common.error.StandardException) LanguageConnectionContext(org.apache.derby.iapi.sql.conn.LanguageConnectionContext) ReferencedKeyConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor) ConstraintDescriptor(org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) UUID(org.apache.derby.catalog.UUID)

Example 39 with ScanController

use of org.apache.derby.iapi.store.access.ScanController in project derby by apache.

the class GenericRIChecker method getScanController.

/**
 * Get a scan controller positioned using searchRow as
 * the start/stop position.  The assumption is that searchRow
 * is of the same format as the index being opened.
 * The scan is set up to return no columns.
 * NOTE: We only need an instantaneous lock on the
 * table that we are probing as we are just checking
 * for the existence of a row.  All updaters, whether
 * to the primary or foreign key tables, will hold an
 * X lock on the table that they are updating and will
 * be probing the other table, so instantaneous locks
 * will not change the semantics.
 *
 * RESOLVE:  Due to the current RI implementation
 * we cannot always get instantaneous locks.  We
 * will call a method to find out what kind of
 * locking to do until the implementation changes.
 *
 * @param conglomNumber		the particular conglomerate we
 *							are interested in
 * @param scoci
 * @param dcoci
 * @param searchRow			the row to match
 * @return                  scan controller
 *
 * @exception StandardException on error
 */
protected ScanController getScanController(long conglomNumber, StaticCompiledOpenConglomInfo scoci, DynamicCompiledOpenConglomInfo dcoci, ExecRow searchRow) throws StandardException {
    int isoLevel = getRICheckIsolationLevel();
    ScanController scan;
    Long hashKey = Long.valueOf(conglomNumber);
    /*
		** If we haven't already opened this scan controller,
		** we'll open it now and stick it in the hash table.
		*/
    if ((scan = scanControllers.get(hashKey)) == null) {
        setupQualifierRow(searchRow);
        scan = tc.openCompiledScan(// hold
        false, // read only
        0, // row locking
        TransactionController.MODE_RECORD, isoLevel, // retrieve all fields
        (FormatableBitSet) null, // startKeyValue
        indexQualifierRow.getRowArray(), // startSearchOp
        ScanController.GE, // qualifier
        null, // stopKeyValue
        indexQualifierRow.getRowArray(), // stopSearchOp
        ScanController.GT, scoci, dcoci);
        scanControllers.put(hashKey, scan);
    } else {
        /*
			** If the base row is the same row as the previous	
			** row, this call to setupQualfierRow is redundant,
			** but it is safer this way so we'll take the
			** marginal performance hit (marginal relative
			** to the index scans that we are making).
			*/
        setupQualifierRow(searchRow);
        scan.reopenScan(// startKeyValue
        indexQualifierRow.getRowArray(), // startSearchOp
        ScanController.GE, // qualifier
        null, // stopKeyValue
        indexQualifierRow.getRowArray(), // stopSearchOp
        ScanController.GT);
    }
    return scan;
}
Also used : ScanController(org.apache.derby.iapi.store.access.ScanController) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet)

Example 40 with ScanController

use of org.apache.derby.iapi.store.access.ScanController in project derby by apache.

the class T_QualifierTest method t_scanFetchNextPartial.

/**
 * Test scan which does FetchNext with subset of fields.
 * <p>
 * FetchNext() may be optimized by the underlying scan code to try and
 * not do multiple fetches of the same row for the user, but if the user
 * asks for one column, but the stop position depends on the whole row
 * this optimization is not possible.
 * <p>
 *
 * @return Whether the test succeeded or not.
 *
 * @exception  StandardException  Standard exception policy.
 */
public static boolean t_scanFetchNextPartial(TransactionController tc, long conglomid, DataValueDescriptor[] fetch_template, DataValueDescriptor[] start_key, int start_op, Qualifier[][] qualifier, DataValueDescriptor[] stop_key, int stop_op, int expect_numrows, int input_expect_key, int order) throws StandardException, T_Fail {
    HashSet set = null;
    boolean ordered = (order == ORDER_FORWARD || order == ORDER_DESC);
    /**
     ********************************************************************
     * setup shared by both.
     **********************************************************************
     */
    // In the fetchNext call only ask the minimum set of columns
    // necessary, which is the union of the "key" (col[2]) and other
    // columns referenced in the qualifier list.
    FormatableBitSet fetch_row_validColumns = RowUtil.getQualifierBitSet(qualifier);
    // now add in column 2, as we always need the key field.
    // grow to length of 3
    fetch_row_validColumns.grow(3);
    fetch_row_validColumns.set(2);
    // add in any fields in start and stop positions
    if (start_key != null) {
        for (int i = 0; i < start_key.length; i++) {
            fetch_row_validColumns.set(i);
        }
    }
    if (stop_key != null) {
        for (int i = 0; i < stop_key.length; i++) {
            fetch_row_validColumns.set(i);
        }
    }
    // point key at the right column in the fetch_template
    SQLLongint key_column = (SQLLongint) fetch_template[2];
    if (!ordered) {
        set = create_hash_set(input_expect_key, expect_numrows, order);
    }
    ScanController scan = tc.openScan(conglomid, false, 0, TransactionController.MODE_RECORD, TransactionController.ISOLATION_SERIALIZABLE, (FormatableBitSet) fetch_row_validColumns, start_key, start_op, qualifier, stop_key, stop_op);
    int expect_key = input_expect_key;
    long key = -42;
    long key2 = -42;
    long numrows = 0;
    while (scan.fetchNext(fetch_template)) {
        // see if we are getting the right keys.
        key = key_column.getLong();
        // make sure a subsequent fetch also works.
        key_column.setValue(-42);
        scan.fetch(fetch_template);
        key2 = key_column.getLong();
        if (ordered) {
            if ((key != expect_key) || (key2 != expect_key)) {
                return (fail("(t_scanFetchNext) wrong key, expected (" + expect_key + ")" + "but got (" + key + ")."));
            } else {
                if (order == ORDER_DESC)
                    expect_key--;
                else
                    expect_key++;
            }
        } else {
            if (!set.remove(key)) {
                return (fail("(t_scanFetchNext) wrong key, expected (" + expect_key + ")" + "but got (" + key + ")."));
            }
        }
        numrows++;
    }
    scan.close();
    if (numrows != expect_numrows) {
        return (fail("(t_scanFetchNext) wrong number of rows. Expected " + expect_numrows + " rows, but got " + numrows + "rows."));
    }
    return (true);
}
Also used : ScanController(org.apache.derby.iapi.store.access.ScanController) GroupFetchScanController(org.apache.derby.iapi.store.access.GroupFetchScanController) SQLLongint(org.apache.derby.iapi.types.SQLLongint) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet) SQLLongint(org.apache.derby.iapi.types.SQLLongint) HashSet(java.util.HashSet)

Aggregations

ScanController (org.apache.derby.iapi.store.access.ScanController)61 DataValueDescriptor (org.apache.derby.iapi.types.DataValueDescriptor)35 ConglomerateController (org.apache.derby.iapi.store.access.ConglomerateController)32 RowLocation (org.apache.derby.iapi.types.RowLocation)29 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)24 ExecRow (org.apache.derby.iapi.sql.execute.ExecRow)22 SQLLongint (org.apache.derby.iapi.types.SQLLongint)20 ExecIndexRow (org.apache.derby.iapi.sql.execute.ExecIndexRow)9 StandardException (org.apache.derby.shared.common.error.StandardException)9 TransactionController (org.apache.derby.iapi.store.access.TransactionController)8 Properties (java.util.Properties)7 GroupFetchScanController (org.apache.derby.iapi.store.access.GroupFetchScanController)7 SQLChar (org.apache.derby.iapi.types.SQLChar)6 UUID (org.apache.derby.catalog.UUID)5 ConglomerateDescriptor (org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor)5 SQLVarchar (org.apache.derby.iapi.types.SQLVarchar)5 ConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor)4 HashSet (java.util.HashSet)3 Hashtable (java.util.Hashtable)3 ReferencedKeyConstraintDescriptor (org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor)3