Search in sources :

Example 1 with ScopeFilter

use of org.apache.derby.iapi.sql.compile.ScopeFilter in project derby by apache.

the class DeleteNode method bindStatement.

/**
 * Bind this DeleteNode.  This means looking up tables and columns and
 * getting their types, and figuring out the result types of all
 * expressions, as well as doing view resolution, permissions checking,
 * etc.
 * <p>
 * If any indexes need to be updated, we add all the columns in the
 * base table to the result column list, so that we can use the column
 * values as look-up keys for the index rows to be deleted.  Binding a
 * delete will also massage the tree so that the ResultSetNode has
 * column containing the RowLocation of the base row.
 *
 * @exception StandardException		Thrown on error
 */
@Override
public void bindStatement() throws StandardException {
    // We just need select privilege on the where clause tables
    getCompilerContext().pushCurrentPrivType(Authorizer.SELECT_PRIV);
    try {
        FromList fromList = new FromList(getOptimizerFactory().doJoinOrderOptimization(), getContextManager());
        ResultColumn rowLocationColumn = null;
        CurrentRowLocationNode rowLocationNode;
        TableName cursorTargetTableName = null;
        CurrentOfNode currentOfNode = null;
        // 
        // Don't add privilege requirements for the UDT types of columns.
        // The compiler will attempt to add these when generating the full column list during
        // binding of the tables.
        // 
        IgnoreFilter ignorePermissions = new IgnoreFilter();
        getCompilerContext().addPrivilegeFilter(ignorePermissions);
        DataDictionary dataDictionary = getDataDictionary();
        // for DELETE clause of a MERGE statement, the tables have already been bound
        if (!inMatchingClause()) {
            super.bindTables(dataDictionary);
        }
        // for positioned delete, get the cursor's target table.
        if (SanityManager.DEBUG)
            SanityManager.ASSERT(resultSet != null && resultSet instanceof SelectNode, "Delete must have a select result set");
        SelectNode sel = (SelectNode) resultSet;
        targetTable = (FromTable) sel.fromList.elementAt(0);
        if (targetTable instanceof CurrentOfNode) {
            currentOfNode = (CurrentOfNode) targetTable;
            cursorTargetTableName = inMatchingClause() ? targetTableName : currentOfNode.getBaseCursorTargetTableName();
            // instead of an assert, we might say the cursor is not updatable.
            if (SanityManager.DEBUG)
                SanityManager.ASSERT(cursorTargetTableName != null);
        }
        if (targetTable instanceof FromVTI) {
            targetVTI = (FromVTI) targetTable;
            targetVTI.setTarget();
        } else {
            // we get it from the cursor supplying the position.
            if (targetTableName == null) {
                // verify we have current of
                if (SanityManager.DEBUG)
                    SanityManager.ASSERT(cursorTargetTableName != null);
                targetTableName = cursorTargetTableName;
            } else // the named table is the same as the cursor's target (base table name).
            if (cursorTargetTableName != null) {
                // be the same as a base name in the cursor.
                if (!targetTableName.equals(cursorTargetTableName)) {
                    throw StandardException.newException(SQLState.LANG_CURSOR_DELETE_MISMATCH, targetTableName, currentOfNode.getCursorName());
                }
            }
        }
        // descriptor must exist, tables already bound.
        verifyTargetTable();
        /* Generate a select list for the ResultSetNode - CurrentRowLocation(). */
        if (SanityManager.DEBUG) {
            SanityManager.ASSERT((resultSet.getResultColumns() == null), "resultColumns is expected to be null until bind time");
        }
        if (targetTable instanceof FromVTI) {
            getResultColumnList();
            resultColumnList = targetTable.getResultColumnsForList(null, resultColumnList, null);
            /* Set the new result column list in the result set */
            resultSet.setResultColumns(resultColumnList);
        } else {
            /*
				** Start off assuming no columns from the base table
				** are needed in the rcl.
				*/
            resultColumnList = new ResultColumnList(getContextManager());
            FromBaseTable fbt = getResultColumnList(resultColumnList);
            readColsBitSet = getReadMap(dataDictionary, targetTableDescriptor);
            resultColumnList = fbt.addColsToList(resultColumnList, readColsBitSet);
            /*
				** If all bits are set, then behave as if we chose all
				** in the first place
				*/
            int i = 1;
            int size = targetTableDescriptor.getMaxColumnID();
            for (; i <= size; i++) {
                if (!readColsBitSet.get(i)) {
                    break;
                }
            }
            if (i > size) {
                readColsBitSet = null;
            }
            /* Generate the RowLocation column */
            rowLocationNode = new CurrentRowLocationNode(getContextManager());
            rowLocationColumn = new ResultColumn(COLUMNNAME, rowLocationNode, getContextManager());
            rowLocationColumn.markGenerated();
            /* Append to the ResultColumnList */
            resultColumnList.addResultColumn(rowLocationColumn);
            /* Force the added columns to take on the table's correlation name, if any */
            correlateAddedColumns(resultColumnList, targetTable);
            /* Add the new result columns to the driving result set */
            ResultColumnList originalRCL = resultSet.getResultColumns();
            if (originalRCL != null) {
                originalRCL.appendResultColumns(resultColumnList, false);
                resultColumnList = originalRCL;
            }
            resultSet.setResultColumns(resultColumnList);
        }
        // done excluding column types from privilege checking
        getCompilerContext().removePrivilegeFilter(ignorePermissions);
        /* Bind the expressions before the ResultColumns are bound */
        // only add privileges when we're inside the WHERE clause
        ScopeFilter scopeFilter = new ScopeFilter(getCompilerContext(), CompilerContext.WHERE_SCOPE, 1);
        getCompilerContext().addPrivilegeFilter(scopeFilter);
        super.bindExpressions();
        getCompilerContext().removePrivilegeFilter(scopeFilter);
        /* Bind untyped nulls directly under the result columns */
        resultSet.getResultColumns().bindUntypedNullsToResultColumns(resultColumnList);
        if (!(targetTable instanceof FromVTI)) {
            /* Bind the new ResultColumn */
            rowLocationColumn.bindResultColumnToExpression();
            bindConstraints(dataDictionary, getOptimizerFactory(), targetTableDescriptor, null, resultColumnList, (int[]) null, readColsBitSet, // we alway include triggers in core language
            true, // dummy
            new boolean[1]);
            /* If the target table is also a source table, then
			 	* the delete will have to be in deferred mode
			 	* For deletes, this means that the target table appears in a
			 	* subquery.  Also, self-referencing foreign key deletes
		 	 	* are deferred.  And triggers cause the delete to be deferred.
			 	*/
            if (resultSet.subqueryReferencesTarget(targetTableDescriptor.getName(), true) || requiresDeferredProcessing()) {
                deferred = true;
            }
        } else {
            deferred = VTIDeferModPolicy.deferIt(DeferModification.DELETE_STATEMENT, targetVTI, null, sel.getWhereClause());
        }
        /* Verify that all underlying ResultSets reclaimed their FromList */
        if (SanityManager.DEBUG) {
            SanityManager.ASSERT(fromList.size() == 0, "fromList.size() is expected to be 0, not " + fromList.size() + " on return from RS.bindExpressions()");
        }
        // the ref action  dependent tables and bind them.
        if (fkTableNames != null) {
            String currentTargetTableName = targetTableDescriptor.getSchemaName() + "." + targetTableDescriptor.getName();
            if (!isDependentTable) {
                // graph node
                dependentTables = new HashSet<String>();
            }
            /*Check whether the current target has already been explored.
			 	*If we are seeing the same table name which we binded earlier
			 	*means we have cyclic references.
			 	*/
            if (dependentTables.add(currentTargetTableName)) {
                cascadeDelete = true;
                int noDependents = fkTableNames.length;
                dependentNodes = new StatementNode[noDependents];
                for (int i = 0; i < noDependents; i++) {
                    dependentNodes[i] = getDependentTableNode(fkSchemaNames[i], fkTableNames[i], fkRefActions[i], fkColDescriptors[i]);
                    dependentNodes[i].bindStatement();
                }
            }
        } else {
            // case where current dependent table does not have dependent tables
            if (isDependentTable) {
                String currentTargetTableName = targetTableDescriptor.getSchemaName() + "." + targetTableDescriptor.getName();
                dependentTables.add(currentTargetTableName);
            }
        }
        // add need for DELETE privilege on the target table
        getCompilerContext().pushCurrentPrivType(getPrivType());
        getCompilerContext().addRequiredTablePriv(targetTableDescriptor);
        getCompilerContext().popCurrentPrivType();
    } finally {
        getCompilerContext().popCurrentPrivType();
    }
}
Also used : IgnoreFilter(org.apache.derby.iapi.sql.compile.IgnoreFilter) DataDictionary(org.apache.derby.iapi.sql.dictionary.DataDictionary) ScopeFilter(org.apache.derby.iapi.sql.compile.ScopeFilter)

Aggregations

IgnoreFilter (org.apache.derby.iapi.sql.compile.IgnoreFilter)1 ScopeFilter (org.apache.derby.iapi.sql.compile.ScopeFilter)1 DataDictionary (org.apache.derby.iapi.sql.dictionary.DataDictionary)1