blob: 6e4b0e8d84ff5e41a903c437f08620d0e4ec7dad [file] [log] [blame]
/*
Derby - Class org.apache.derby.iapi.sql.dictionary.ViewDescriptor
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.iapi.sql.dictionary;
import org.apache.derby.catalog.UUID;
import org.apache.derby.iapi.sql.depend.Dependent;
import org.apache.derby.iapi.sql.depend.Provider;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
import org.apache.derby.iapi.store.access.TransactionController;
import org.apache.derby.iapi.sql.depend.DependencyManager;
import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.shared.common.sanity.SanityManager;
import org.apache.derby.catalog.DependableFinder;
import org.apache.derby.catalog.Dependable;
import org.apache.derby.iapi.services.io.StoredFormatIds;
/**
* This is the implementation of ViewDescriptor. Users of View descriptors
* should only use the following methods:
* <ol>
* <li> getUUID
* <li> setUUID
* <li> getViewText
* <li> setViewName
* <li> getCheckOptionType
* <li> getCompSchemaId
* </ol>
*
* @version 0.1
*/
public final class ViewDescriptor extends UniqueTupleDescriptor
implements Dependent, Provider
{
private final int checkOption;
private String viewName;
private final String viewText;
private UUID uuid;
private final UUID compSchemaId;
public static final int NO_CHECK_OPTION = 0;
/**
* Constructor for a ViewDescriptor.
*
* @param dataDictionary The data dictionary that this descriptor lives in
* @param viewID The UUID for the view
* @param viewName The name of the view
* @param viewText The text of the query expression from the view definition.
* @param checkOption int check option type
* @param compSchemaId the schemaid to compile in
*/
public ViewDescriptor(DataDictionary dataDictionary, UUID viewID, String viewName, String viewText,
int checkOption, UUID compSchemaId)
{
super( dataDictionary );
uuid = viewID;
this.viewText = viewText;
this.viewName = viewName;
/* RESOLVE - No check options for now */
if (SanityManager.DEBUG)
{
if (checkOption != ViewDescriptor.NO_CHECK_OPTION)
{
SanityManager.THROWASSERT("checkOption (" + checkOption +
") expected to be " + ViewDescriptor.NO_CHECK_OPTION);
}
}
this.checkOption = checkOption;
this.compSchemaId = compSchemaId;
}
//
// ViewDescriptor interface
//
/**
* Gets the UUID of the view.
*
* @return The UUID of the view.
*/
public UUID getUUID()
{
return uuid;
}
/**
* Sets the UUID of the view.
*
* @param uuid The UUID of the view.
*/
public void setUUID(UUID uuid)
{
this.uuid = uuid;
}
/**
* Gets the text of the view definition.
*
* @return A String containing the text of the CREATE VIEW
* statement that created the view
*/
public String getViewText()
{
return viewText;
}
/**
* Sets the name of the view.
*
* @param name The name of the view.
*/
public void setViewName(String name)
{
viewName = name;
}
/**
* Gets an identifier telling what type of check option
* is on this view.
*
* @return An identifier telling what type of check option
* is on the view.
*/
public int getCheckOptionType()
{
return checkOption;
}
/**
* Get the compilation type schema id when this view
* was first bound.
*
* @return the schema UUID
*/
public UUID getCompSchemaId()
{
return compSchemaId;
}
//
// Provider interface
//
/**
@return the stored form of this provider
@see Dependable#getDependableFinder
*/
public DependableFinder getDependableFinder()
{
return getDependableFinder(StoredFormatIds.VIEW_DESCRIPTOR_FINDER_V01_ID);
}
/**
* Return the name of this Provider. (Useful for errors.)
*
* @return String The name of this provider.
*/
public String getObjectName()
{
return viewName;
}
/**
* Get the provider's UUID
*
* @return String The provider's UUID
*/
public UUID getObjectID()
{
return uuid;
}
/**
* Get the provider's type.
*
* @return String The provider's type.
*/
public String getClassType()
{
return Dependable.VIEW;
}
//
// Dependent Inteface
//
/**
Check that all of the dependent's dependencies are valid.
@return true if the dependent is currently valid
*/
public boolean isValid()
{
return true;
}
/**
Prepare to mark the dependent as invalid (due to at least one of
its dependencies being invalid).
@param action The action causing the invalidation
@param p the provider
@exception StandardException thrown if unable to make it invalid
*/
public void prepareToInvalidate(Provider p, int action,
LanguageConnectionContext lcc)
throws StandardException
{
switch ( action )
{
/*
* We don't care about creating or dropping indexes or
* alter table on an underlying table.
*/
case DependencyManager.CREATE_INDEX:
case DependencyManager.DROP_INDEX:
case DependencyManager.DROP_COLUMN:
case DependencyManager.CREATE_CONSTRAINT:
case DependencyManager.ALTER_TABLE:
case DependencyManager.CREATE_TRIGGER:
case DependencyManager.DROP_TRIGGER:
case DependencyManager.BULK_INSERT:
case DependencyManager.COMPRESS_TABLE:
case DependencyManager.RENAME_INDEX:
case DependencyManager.UPDATE_STATISTICS:
case DependencyManager.DROP_STATISTICS:
case DependencyManager.TRUNCATE_TABLE:
/*
** Set constriants is a bit odd in that it
** will send a SET_CONSTRAINTS on the table
** when it enables a constraint, rather than
** on the constraint. So since we depend on
** the table, we have to deal with this action.
*/
case DependencyManager.SET_CONSTRAINTS_ENABLE:
case DependencyManager.SET_TRIGGERS_ENABLE:
//When REVOKE_PRIVILEGE gets sent (this happens for privilege
//types SELECT, UPDATE, DELETE, INSERT, REFERENCES, TRIGGER), we
//don't do anything here. Later in makeInvalid method, we make
//the ViewDescriptor drop itself.
case DependencyManager.REVOKE_PRIVILEGE:
// When a role grant is revoked, any a view dependent on priviliges
// obtained through that role grant will dropped. We don't do
// anything here. Later in makeInvalid method, we make the
// ViewDescriptor drop itself.
case DependencyManager.REVOKE_ROLE:
// Only used by Activations
case DependencyManager.RECHECK_PRIVILEGES:
break;
// When REVOKE_PRIVILEGE gets sent to a
// TablePermsDescriptor we must also send
// INTERNAL_RECOMPILE_REQUEST to its Dependents which
// may be GPSs needing re-compilation. But Dependents
// could also be ViewDescriptors, which then also need
// to handle this event.
case DependencyManager.INTERNAL_RECOMPILE_REQUEST:
break;
//Notice that REVOKE_PRIVILEGE_RESTRICT is not caught earlier.
//It gets handled in this default: action where an exception
//will be thrown. This is because, if such an invalidation
//action type is ever received by a dependent, the dependent
//show throw an exception.
//In Derby, at this point, REVOKE_PRIVILEGE_RESTRICT gets sent
//when execute privilege on a routine is getting revoked.
// DROP_COLUMN_RESTRICT is similar. Any case which arrives
// at this default: statement causes the exception to be
// thrown, indicating that the DDL modification should be
// rejected because a view is dependent on the underlying
// object (table, column, privilege, etc.)
default:
DependencyManager dm;
dm = getDataDictionary().getDependencyManager();
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_VIEW,
dm.getActionString(action),
p.getObjectName(), viewName);
} // end switch
}
/**
Mark the dependent as invalid (due to at least one of
its dependencies being invalid).
@param action The action causing the invalidation
@exception StandardException thrown if unable to make it invalid
*/
public void makeInvalid(int action, LanguageConnectionContext lcc)
throws StandardException
{
switch ( action )
{
/* We don't care about creating or dropping indexes or
* alter table on an underlying table.
*/
case DependencyManager.CREATE_INDEX:
case DependencyManager.DROP_INDEX:
case DependencyManager.ALTER_TABLE:
case DependencyManager.CREATE_CONSTRAINT:
case DependencyManager.BULK_INSERT:
case DependencyManager.COMPRESS_TABLE:
case DependencyManager.SET_CONSTRAINTS_ENABLE:
case DependencyManager.SET_TRIGGERS_ENABLE:
case DependencyManager.CREATE_TRIGGER:
case DependencyManager.DROP_TRIGGER:
case DependencyManager.RENAME_INDEX:
case DependencyManager.UPDATE_STATISTICS:
case DependencyManager.DROP_STATISTICS:
case DependencyManager.TRUNCATE_TABLE:
// Only used by Activations
case DependencyManager.RECHECK_PRIVILEGES:
// When REVOKE_PRIVILEGE gets sent to a
// TablePermsDescriptor we must also send
// INTERNAL_RECOMPILE_REQUEST to its Dependents which
// may be GPSs needing re-compilation. But Dependents
// could also be ViewDescriptors, which then also need
// to handle this event.
case DependencyManager.INTERNAL_RECOMPILE_REQUEST:
break;
// When REVOKE_PRIVILEGE gets sent (this happens for privilege
// types SELECT, UPDATE, DELETE, INSERT, REFERENCES, TRIGGER),
// we make the ViewDescriptor drop itself. REVOKE_ROLE also
// drops the dependent view.
case DependencyManager.DROP_COLUMN:
case DependencyManager.REVOKE_PRIVILEGE:
case DependencyManager.REVOKE_ROLE:
TableDescriptor td =
getDataDictionary().getTableDescriptor(uuid);
if (td == null) {
// DERBY-5567 already dropped via another dependency
break;
}
// DERBY-5567 keep original action
drop(lcc, td.getSchemaDescriptor(), td, action);
lcc.getLastActivation().addWarning(
StandardException.newWarning(
SQLState.LANG_VIEW_DROPPED,
this.getObjectName() ));
break;
default:
/* We should never get here, since we can't have dangling references */
if (SanityManager.DEBUG)
{
SanityManager.THROWASSERT("did not expect to get called");
}
break;
} // end switch
}
//
// class interface
//
/**
* Prints the contents of the ViewDescriptor
*
* @return The contents as a String
*/
public String toString()
{
if (SanityManager.DEBUG)
{
return "uuid: " + uuid + " viewName: " + viewName + "\n" +
"viewText: " + viewText + "\n" +
"checkOption: " + checkOption + "\n" +
"compSchemaId: " + compSchemaId + "\n";
}
else
{
return "";
}
}
/**
* Drop this descriptor, if not already done.
*
* @param lcc current language connection context
* @param sd schema descriptor
* @param td table descriptor for this view
* @throws StandardException standard error policy
*/
public void drop(
LanguageConnectionContext lcc,
SchemaDescriptor sd,
TableDescriptor td) throws StandardException
{
drop(lcc, sd, td, DependencyManager.DROP_VIEW);
}
/**
* Drop this descriptor, if not already done, due to action.
* If action is not {@code DependencyManager.DROP_VIEW}, the descriptor is
* dropped due to dropping some other object, e.g. a table column.
*
* @param lcc current language connection context
* @param sd schema descriptor
* @param td table descriptor for this view
* @param action action
* @throws StandardException standard error policy
*/
private void drop(
LanguageConnectionContext lcc,
SchemaDescriptor sd,
TableDescriptor td,
int action) throws StandardException
{
DataDictionary dd = getDataDictionary();
DependencyManager dm = dd.getDependencyManager();
TransactionController tc = lcc.getTransactionExecute();
/* Drop the columns */
dd.dropAllColumnDescriptors(td.getUUID(), tc);
/* Prepare all dependents to invalidate. (This is there chance
* to say that they can't be invalidated. For example, an open
* cursor referencing a table/view that the user is attempting to
* drop.) If no one objects, then invalidate any dependent objects.
*/
dm.invalidateFor(td, action, lcc);
/* Clear the dependencies for the view */
dm.clearDependencies(lcc, this);
/* Drop the view */
dd.dropViewDescriptor(this, tc);
/* Drop all table and column permission descriptors */
dd.dropAllTableAndColPermDescriptors(td.getUUID(), tc);
/* Drop the table */
dd.dropTableDescriptor(td, sd, tc);
}
public String getName() {
return viewName;
}
}