Search in sources :

Example 1 with CheckInfo

use of org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo in project derby by apache.

the class InsertResultSet method normalInsertCore.

// Do the work for a "normal" insert
private void normalInsertCore(LanguageConnectionContext lcc, boolean firstExecute) throws StandardException {
    boolean setUserIdentity = constants.hasAutoincrement() && isSingleRowResultSet();
    ExecRow deferredRowBuffer;
    long user_autoinc = 0;
    /* Get or re-use the row changer.
		 */
    if (firstExecute) {
        rowChanger = lcc.getLanguageConnectionFactory().getExecutionFactory().getRowChanger(heapConglom, constants.heapSCOCI, heapDCOCI, constants.irgs, constants.indexCIDS, constants.indexSCOCIs, indexDCOCIs, // number of columns in partial row meaningless for insert
        0, tc, // Changed column ids
        null, constants.getStreamStorableHeapColIds(), activation);
        rowChanger.setIndexNames(constants.indexNames);
    }
    /* decode lock mode for the execution isolation level */
    int lockMode = decodeLockMode(constants.lockMode);
    rowChanger.open(lockMode);
    /* The source does not know whether or not we are doing a
		 * deferred mode insert.  If we are, then we must clear the
		 * index scan info from the activation so that the row changer
		 * does not re-use that information (which won't be valid for
		 * a deferred mode insert).
		 */
    if (constants.deferred) {
        activation.clearIndexScanInfo();
    }
    if (fkInfoArray != null) {
        if (fkChecker == null) {
            fkChecker = new RISetChecker(lcc, tc, fkInfoArray);
        } else {
            fkChecker.reopen();
        }
    }
    if (firstExecute && constants.deferred) {
        Properties properties = new Properties();
        // Get the properties on the old heap
        rowChanger.getHeapConglomerateController().getInternalTablePropertySet(properties);
        /*
			** If deferred we save a copy of the entire row.
			*/
        rowHolder = new TemporaryRowHolderImpl(activation, properties, resultDescription);
        rowChanger.setRowHolder(rowHolder);
    }
    firstExecuteSpecialHandlingAutoGen(firstExecute, rowChanger, constants.targetUUID);
    while (row != null) {
        // auto-generated key columns.
        if (activation.getAutoGeneratedKeysResultsetMode() && autoGeneratedKeysColumnIndexes.length > 0) {
            autoGeneratedKeysRowsHolder.insert(getCompactRow(row, autoGeneratedKeysColumnIndexes));
        }
        // fill in columns that are computed from expressions on other columns
        evaluateGenerationClauses(generationClauses, activation, sourceResultSet, row, false);
        /*
			** If we're doing a deferred insert, insert into the temporary
			** conglomerate.  Otherwise, insert directly into the permanent
			** conglomerates using the rowChanger.
			*/
        if (constants.deferred) {
            rowHolder.insert(row);
        } else {
            // Immediate mode violations will throw, so we only ever
            // see false here with deferred constraint mode for one or more
            // of the constraints being checked.
            boolean allOk = evaluateCheckConstraints();
            if (fkChecker != null) {
                fkChecker.doFKCheck(activation, row);
            }
            // Objectify any streaming columns that are indexed.
            if (constants.irgs.length > 0) {
                DataValueDescriptor[] rowArray = row.getRowArray();
                for (int i = 0; i < rowArray.length; i++) {
                    // System.out.println("checking " + i);
                    if (!constants.indexedCols[i]) {
                        continue;
                    }
                    if (rowArray[i] instanceof StreamStorable)
                        rowArray[i].getObject();
                }
            }
            if (allOk) {
                rowChanger.insertRow(row, false);
            } else {
                RowLocation offendingRow = rowChanger.insertRow(row, true);
                deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, schemaName, tableName, deferredChecks, violatingCheckConstraints, offendingRow, new CheckInfo[1]);
            }
        }
        rowCount++;
        if (setUserIdentity) {
            dd = lcc.getDataDictionary();
            td = dd.getTableDescriptor(constants.targetUUID);
            int maxColumns = td.getMaxColumnID();
            int col;
            for (col = 1; col <= maxColumns; col++) {
                ColumnDescriptor cd = td.getColumnDescriptor(col);
                if (cd.isAutoincrement()) {
                    break;
                }
            }
            if (col <= maxColumns) {
                DataValueDescriptor dvd = row.cloneColumn(col);
                user_autoinc = dvd.getLong();
            }
        }
        // No need to do a next on a single row source
        if (constants.singleRowSource) {
            row = null;
        } else {
            row = getNextRowCore(sourceResultSet);
        }
    }
    /*
		** If it's a deferred insert, scan the temporary conglomerate and
		** insert the rows into the permanent conglomerates using rowChanger.
		*/
    if (constants.deferred) {
        if (triggerInfo != null) {
            Vector<AutoincrementCounter> v = null;
            if (aiCache != null) {
                v = new Vector<AutoincrementCounter>();
                for (int i = 0; i < aiCache.length; i++) {
                    String s, t, c;
                    if (aiCache[i] == null)
                        continue;
                    Long initialValue = lcc.lastAutoincrementValue((s = constants.getSchemaName()), (t = constants.getTableName()), (c = constants.getColumnName(i)));
                    AutoincrementCounter aic = new AutoincrementCounter(initialValue, constants.getAutoincIncrement(i), aiCache[i].getLong(), s, t, c, i + 1);
                    v.addElement(aic);
                }
            }
            if (triggerActivator == null) {
                triggerActivator = new TriggerEventActivator(lcc, constants.targetUUID, triggerInfo, TriggerExecutionContext.INSERT_EVENT, activation, v);
            } else {
                triggerActivator.reopen();
            }
            // fire BEFORE trigger, do this before checking constraints
            triggerActivator.notifyEvent(TriggerEvents.BEFORE_INSERT, (CursorResultSet) null, rowHolder.getResultSet(), (int[]) null);
        }
        CursorResultSet rs = rowHolder.getResultSet();
        try {
            rs.open();
            while ((deferredRowBuffer = rs.getNextRow()) != null) {
                // we have to set the source row so the check constraint
                // sees the correct row.
                sourceResultSet.setCurrentRow(deferredRowBuffer);
                boolean allOk = evaluateCheckConstraints();
                if (allOk) {
                    rowChanger.insertRow(deferredRowBuffer, false);
                } else {
                    RowLocation offendingRow = rowChanger.insertRow(deferredRowBuffer, true);
                    deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, schemaName, tableName, deferredChecks, violatingCheckConstraints, offendingRow, new CheckInfo[1]);
                }
            }
        } finally {
            sourceResultSet.clearCurrentRow();
            rs.close();
        }
        if (fkChecker != null) {
            /*
				** Second scan to make sure all the foreign key
				** constraints are ok.  We have to do this after
				** we have completed the inserts in case of self
				** referencing constraints.
				*/
            rs = rowHolder.getResultSet();
            try {
                rs.open();
                while ((deferredRowBuffer = rs.getNextRow()) != null) {
                    fkChecker.doFKCheck(activation, deferredRowBuffer);
                }
            } finally {
                rs.close();
            }
        }
        // fire AFTER trigger
        if (triggerActivator != null) {
            triggerActivator.notifyEvent(TriggerEvents.AFTER_INSERT, (CursorResultSet) null, rowHolder.getResultSet(), (int[]) null);
        }
    }
    if (rowHolder != null) {
        rowHolder.close();
    // rowHolder kept across opens
    }
    if (fkChecker != null) {
        fkChecker.close();
        fkChecker = null;
    }
    if (setIdentity)
        lcc.setIdentityValue(identityVal);
    else /*
                 * find the value of the identity column from the user inserted value
                 * and do a lcc.setIdentityValue(<user_value>);
                 */
    if (setUserIdentity) {
        lcc.setIdentityValue(user_autoinc);
    }
}
Also used : CursorResultSet(org.apache.derby.iapi.sql.execute.CursorResultSet) ResultColumnDescriptor(org.apache.derby.iapi.sql.ResultColumnDescriptor) ColumnDescriptor(org.apache.derby.iapi.sql.dictionary.ColumnDescriptor) Properties(java.util.Properties) LanguageProperties(org.apache.derby.iapi.sql.LanguageProperties) ExecRow(org.apache.derby.iapi.sql.execute.ExecRow) StreamStorable(org.apache.derby.iapi.services.io.StreamStorable) CheckInfo(org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) RowLocation(org.apache.derby.iapi.types.RowLocation)

Example 2 with CheckInfo

use of org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo in project derby by apache.

the class UpdateResultSet method collectAffectedRows.

public boolean collectAffectedRows() throws StandardException {
    boolean rowsFound = false;
    row = getNextRowCore(sourceResultSet);
    if (row != null)
        rowsFound = true;
    else {
        activation.addWarning(StandardException.newWarning(SQLState.LANG_NO_ROW_FOUND));
    }
    // beetle 3865, update cursor use index.
    TableScanResultSet tableScan = (TableScanResultSet) activation.getForUpdateIndexScan();
    boolean notifyCursor = (tableScan != null);
    boolean checkStream = (deferred && rowsFound && !constants.singleRowSource);
    FormatableBitSet streamCols = (checkStream ? checkStreamCols() : null);
    checkStream = (streamCols != null);
    while (row != null) {
        evaluateGenerationClauses(generationClauses, activation, sourceResultSet, row, true);
        /*
			** If we're doing deferred update, write the new row and row
			** location to the temporary conglomerate.  If we're not doing
			** deferred update, update the permanent conglomerates now
			** using the RowChanger.
			*/
        if (deferred) {
            /*
				** If we have a before trigger, we must evaluate the 
				** check constraint after we have executed the trigger.
				** Note that we have compiled checkGM accordingly (to
				** handle the different row shape if we are evaluating
				** against the input result set or a temporary row holder
				** result set).
				*/
            if (triggerInfo == null) {
                boolean allOk = evaluateCheckConstraints();
                if (!allOk) {
                    DataValueDescriptor[] rw = row.getRowArray();
                    SQLRef r = (SQLRef) rw[rw.length - 1];
                    RowLocation baseRowLocation = (RowLocation) r.getObject();
                    deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, constants.getSchemaName(), constants.getTableName(), deferredChecks, violatingCheckConstraints, baseRowLocation, new CheckInfo[1]);
                }
            }
            /*
				** We are going to only save off the updated
				** columns and the RID.  For a trigger, all columns
				** were marked as needed so we'll copy them all.
				*/
            RowUtil.copyRefColumns(deferredTempRow, row, numberOfBaseColumns, numberOfBaseColumns + 1);
            if (checkStream)
                objectifyStream(deferredTempRow, streamCols);
            insertedRowHolder.insert(deferredTempRow);
            /*
				** Grab a copy of the row to delete.  We are
				** going to use this for deferred RI checks.
				*/
            if (beforeUpdateCopyRequired) {
                RowUtil.copyRefColumns(oldDeletedRow, row, numberOfBaseColumns);
                deletedRowHolder.insert(oldDeletedRow);
            }
            /*
				** If we haven't already, lets get a template to
				** use as a template for our rescan of the base table.
				** Do this now while we have a real row to use
				** as a copy.
				**
				** There is one less column in the base row than
				** there is in source row, because the base row
				** doesn't contain the row location.
				*/
            if (deferredBaseRow == null) {
                deferredBaseRow = RowUtil.getEmptyValueRow(numberOfBaseColumns, lcc);
                RowUtil.copyCloneColumns(deferredBaseRow, row, numberOfBaseColumns);
                /*
					** While we're here, let's also create a sparse row for
					** fetching from the store.
					*/
                deferredSparseRow = makeDeferredSparseRow(deferredBaseRow, baseRowReadList, lcc);
            }
        } else {
            boolean allOk = evaluateCheckConstraints();
            /* Get the RowLocation to update
			 	* NOTE - Column #s in the Row are 1 based.
			 	*/
            RowLocation baseRowLocation = (RowLocation) (row.getColumn(resultWidth)).getObject();
            if (!allOk) {
                deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, constants.getSchemaName(), constants.getTableName(), deferredChecks, violatingCheckConstraints, baseRowLocation, new CheckInfo[1]);
            }
            RowUtil.copyRefColumns(newBaseRow, row, numberOfBaseColumns, numberOfBaseColumns);
            if (riChecker != null) {
                /*
					** Make sure all foreign keys in the new row
					** are maintained.  Note that we don't bother 
					** checking primary/unique keys that are referenced
					** here.  The reason is that if we are updating
					** a referenced key, we'll be updating in deferred
					** mode, so we wont get here.
					*/
                riChecker.doFKCheck(activation, newBaseRow);
            }
            sourceResultSet.updateRow(newBaseRow, rowChanger);
            rowChanger.updateRow(row, newBaseRow, baseRowLocation);
            // beetle 3865, update cursor use index.
            if (notifyCursor)
                notifyForUpdateCursor(row.getRowArray(), newBaseRow.getRowArray(), baseRowLocation, tableScan);
        }
        rowCount++;
        // No need to do a next on a single row source
        if (constants.singleRowSource) {
            row = null;
        } else {
            row = getNextRowCore(sourceResultSet);
        }
    }
    if (rowCount == 1 && constants.hasAutoincrement())
        lcc.setIdentityValue(identityVal);
    return rowsFound;
}
Also used : CheckInfo(org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) RowLocation(org.apache.derby.iapi.types.RowLocation) SQLRef(org.apache.derby.iapi.types.SQLRef)

Example 3 with CheckInfo

use of org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo in project derby by apache.

the class UpdateResultSet method updateDeferredRows.

void updateDeferredRows() throws StandardException {
    if (deferred) {
        // we already have everything locked
        deferredBaseCC = tc.openCompiledConglomerate(false, (TransactionController.OPENMODE_SECONDARY_LOCKED | TransactionController.OPENMODE_FORUPDATE), lockMode, TransactionController.ISOLATION_SERIALIZABLE, constants.heapSCOCI, heapDCOCI);
        CursorResultSet rs = insertedRowHolder.getResultSet();
        try {
            /*
				** We need to do a fetch doing a partial row
				** read.  We need to shift our 1-based bit
				** set to a zero based bit set like the store
				** expects.
				*/
            FormatableBitSet readBitSet = RowUtil.shift(baseRowReadList, 1);
            ExecRow deferredTempRow2;
            rs.open();
            while ((deferredTempRow2 = rs.getNextRow()) != null) {
                /*
					** Check the constraint now if we have triggers.
					** Otherwise we evaluated them as we read the
					** rows in from the source.
					*/
                boolean allOk = true;
                if (triggerInfo != null) {
                    sourceResultSet.setCurrentRow(deferredTempRow);
                    allOk = evaluateCheckConstraints();
                }
                /* 
					** The last column is a Ref, which contains a 
					** RowLocation.
					*/
                DataValueDescriptor rlColumn = deferredTempRow2.getColumn(numberOfBaseColumns + 1);
                RowLocation baseRowLocation = (RowLocation) (rlColumn).getObject();
                if (!allOk) {
                    deferredChecks = DeferredConstraintsMemory.rememberCheckViolations(lcc, constants.targetUUID, constants.getSchemaName(), constants.getTableName(), deferredChecks, violatingCheckConstraints, baseRowLocation, new CheckInfo[1]);
                }
                /* Get the base row at the given RowLocation */
                boolean row_exists = deferredBaseCC.fetch(baseRowLocation, deferredSparseRow.getRowArray(), readBitSet);
                if (SanityManager.DEBUG) {
                    SanityManager.ASSERT(row_exists, "did not find base row in deferred update");
                }
                /*
					** Copy the columns from the temp row to the base row.
					** The base row has fewer columns than the temp row,
					** because it doesn't contain the row location.
					*/
                RowUtil.copyRefColumns(newBaseRow, deferredTempRow2, numberOfBaseColumns);
                rowChanger.updateRow(deferredBaseRow, newBaseRow, baseRowLocation);
            }
        } finally {
            sourceResultSet.clearCurrentRow();
            rs.close();
        }
    }
}
Also used : CursorResultSet(org.apache.derby.iapi.sql.execute.CursorResultSet) ExecRow(org.apache.derby.iapi.sql.execute.ExecRow) CheckInfo(org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo) FormatableBitSet(org.apache.derby.iapi.services.io.FormatableBitSet) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) RowLocation(org.apache.derby.iapi.types.RowLocation)

Example 4 with CheckInfo

use of org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo in project derby by apache.

the class ConstraintConstantAction method validateConstraint.

/**
 * Evaluate a check constraint or not null column constraint.
 * Generate a query of the
 * form SELECT COUNT(*) FROM t where NOT(<check constraint>)
 * and run it by compiling and executing it.   Will
 * work ok if the table is empty and query returns null.
 *
 * @param constraintName	constraint name
 * @param constraintText	constraint text
 * @param constraintId      constraint id
 * @param td				referenced table
 * @param lcc				the language connection context
 * @param isCheckConstraint	the constraint is a check constraint
 * @param isInitiallyDeferred {@code true} if the constraint is
 *                          initially deferred
 *
 * @return true if null constraint passes, false otherwise
 *
 * @exception StandardException if check constraint fails
 */
static boolean validateConstraint(String constraintName, String constraintText, UUID constraintId, TableDescriptor td, LanguageConnectionContext lcc, boolean isCheckConstraint, boolean isInitiallyDeferred) throws StandardException {
    StringBuilder checkStmt = new StringBuilder();
    /* should not use select sum(not(<check-predicate>) ? 1: 0) because
		 * that would generate much more complicated code and may exceed Java
		 * limits if we have a large number of check constraints, beetle 4347
		 */
    checkStmt.append("SELECT COUNT(*) FROM ");
    checkStmt.append(td.getQualifiedName());
    checkStmt.append(" WHERE NOT(");
    checkStmt.append(constraintText);
    checkStmt.append(")");
    ResultSet rs = null;
    try {
        PreparedStatement ps = lcc.prepareInternalStatement(checkStmt.toString());
        // This is a substatement; for now, we do not set any timeout
        // for it. We might change this behaviour later, by linking
        // timeout to its parent statement's timeout settings.
        rs = ps.executeSubStatement(lcc, false, 0L);
        ExecRow row = rs.getNextRow();
        if (SanityManager.DEBUG) {
            if (row == null) {
                SanityManager.THROWASSERT("did not get any rows back from query: " + checkStmt.toString());
            }
        }
        Number value = ((Number) ((NumberDataValue) row.getRowArray()[0]).getObject());
        /*
			** Value may be null if there are no rows in the
			** table.
			*/
        if ((value != null) && (value.longValue() != 0)) {
            // check constraint is violated.
            if (isCheckConstraint) {
                if (isInitiallyDeferred) {
                    // Remember the violation
                    List<UUID> violatingConstraints = new ArrayList<UUID>();
                    violatingConstraints.add(constraintId);
                    // FIXME: We don't know the row locations of the
                    // violating rows, so for now, just pretend we know one,
                    // then invalidate the row location information forcing
                    // full table check at validation time
                    CheckInfo[] newCi = new CheckInfo[1];
                    DeferredConstraintsMemory.rememberCheckViolations(lcc, td.getObjectID(), td.getSchemaName(), td.getName(), null, violatingConstraints, new HeapRowLocation(), /* dummy */
                    newCi);
                    newCi[0].setInvalidatedRowLocations();
                } else {
                    throw StandardException.newException(SQLState.LANG_ADD_CHECK_CONSTRAINT_FAILED, constraintName, td.getQualifiedName(), value.toString());
                }
            }
            /*
				 * for not null constraint violations exception will be thrown in caller
				 * check constraint will not get here since exception is thrown
				 * above
				 */
            return false;
        }
    } finally {
        if (rs != null) {
            rs.close();
        }
    }
    return true;
}
Also used : HeapRowLocation(org.apache.derby.impl.store.access.heap.HeapRowLocation) ResultSet(org.apache.derby.iapi.sql.ResultSet) ExecRow(org.apache.derby.iapi.sql.execute.ExecRow) ArrayList(java.util.ArrayList) CheckInfo(org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo) PreparedStatement(org.apache.derby.iapi.sql.PreparedStatement) UUID(org.apache.derby.catalog.UUID) NumberDataValue(org.apache.derby.iapi.types.NumberDataValue)

Aggregations

CheckInfo (org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo)4 ExecRow (org.apache.derby.iapi.sql.execute.ExecRow)3 DataValueDescriptor (org.apache.derby.iapi.types.DataValueDescriptor)3 RowLocation (org.apache.derby.iapi.types.RowLocation)3 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)2 CursorResultSet (org.apache.derby.iapi.sql.execute.CursorResultSet)2 ArrayList (java.util.ArrayList)1 Properties (java.util.Properties)1 UUID (org.apache.derby.catalog.UUID)1 StreamStorable (org.apache.derby.iapi.services.io.StreamStorable)1 LanguageProperties (org.apache.derby.iapi.sql.LanguageProperties)1 PreparedStatement (org.apache.derby.iapi.sql.PreparedStatement)1 ResultColumnDescriptor (org.apache.derby.iapi.sql.ResultColumnDescriptor)1 ResultSet (org.apache.derby.iapi.sql.ResultSet)1 ColumnDescriptor (org.apache.derby.iapi.sql.dictionary.ColumnDescriptor)1 NumberDataValue (org.apache.derby.iapi.types.NumberDataValue)1 SQLRef (org.apache.derby.iapi.types.SQLRef)1 HeapRowLocation (org.apache.derby.impl.store.access.heap.HeapRowLocation)1