blob: 82cd6e1daa82fe8be3f413b5db30cf6adc968f84 [file] [log] [blame]
/*
Derby - Class org.apache.derby.impl.sql.compile.PrivilegeNode
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.compile;
import java.util.HashMap;
import java.util.List;
import org.apache.derby.catalog.AliasInfo;
import org.apache.derby.catalog.TypeDescriptor;
import org.apache.derby.catalog.types.RoutineAliasInfo;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.services.context.ContextManager;
import org.apache.derby.iapi.sql.compile.Visitor;
import org.apache.derby.shared.common.sanity.SanityManager;
import org.apache.derby.iapi.sql.depend.Provider;
import org.apache.derby.iapi.sql.dictionary.AliasDescriptor;
import org.apache.derby.iapi.sql.dictionary.PrivilegedSQLObject;
import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
import org.apache.derby.impl.sql.execute.GenericPrivilegeInfo;
import org.apache.derby.impl.sql.execute.PrivilegeInfo;
/**
* This node represents a set of privileges that are granted or revoked on one object.
*/
class PrivilegeNode extends QueryTreeNode
{
// Privilege object type
public static final int TABLE_PRIVILEGES = 0;
public static final int ROUTINE_PRIVILEGES = 1;
public static final int SEQUENCE_PRIVILEGES = 2;
public static final int UDT_PRIVILEGES = 3;
public static final int AGGREGATE_PRIVILEGES = 4;
//
// State initialized when the node is instantiated
//
private int objectType;
private TableName objectName;
private TablePrivilegesNode specificPrivileges; // Null for routine and usage privs
private RoutineDesignator routineDesignator; // null for table and usage privs
private String privilege; // E.g., PermDescriptor.USAGE_PRIV
private boolean restrict;
//
// State which is filled in by the bind() logic.
//
private Provider dependencyProvider;
/**
* Initialize a PrivilegeNode for use against SYS.SYSTABLEPERMS and SYS.SYSROUTINEPERMS.
*
* @param objectType
* @param objectOfPrivilege (a TableName or RoutineDesignator)
* @param specificPrivileges null for routines and usage
* @param cm the context manager
*/
PrivilegeNode(int objectType,
Object objectOfPrivilege,
TablePrivilegesNode specificPrivileges,
ContextManager cm) throws StandardException {
super(cm);
this.objectType = objectType;
if ( SanityManager.DEBUG)
{
SanityManager.ASSERT( objectOfPrivilege != null,
"null privilge object");
}
switch( this.objectType)
{
case TABLE_PRIVILEGES:
if( SanityManager.DEBUG)
{
SanityManager.ASSERT( specificPrivileges != null,
"null specific privileges used with table privilege");
}
objectName = (TableName) objectOfPrivilege;
this.specificPrivileges = specificPrivileges;
break;
case ROUTINE_PRIVILEGES:
if( SanityManager.DEBUG)
{
SanityManager.ASSERT( specificPrivileges == null,
"non-null specific privileges used with execute privilege");
}
routineDesignator = (RoutineDesignator) objectOfPrivilege;
objectName = routineDesignator.name;
break;
default:
throw unimplementedFeature();
}
}
/**
* Constructor a PrivilegeNode for use against SYS.SYSPERMS.
*
* @param objectType E.g., SEQUENCE
* @param objectName A possibles schema-qualified name
* @param privilege A PermDescriptor privilege, e.g.
* {@code PermDescriptor.USAGE_PRIV}
* @param restrict True if this is a REVOKE...RESTRICT action
* @param cm The context manager
*/
PrivilegeNode(int objectType,
TableName objectName,
String privilege,
boolean restrict,
ContextManager cm)
{
super(cm);
this.objectType = objectType;
this.objectName = objectName;
this.privilege = privilege;
this.restrict = restrict;
}
/**
* Bind this GrantNode. Resolve all table, column, and routine references. Register
* a dependency on the object of the privilege if it has not already been done
*
* @param dependencies The list of privilege objects that this statement has already seen.
* If the object of this privilege is not in the list then this statement is registered
* as dependent on the object.
* @param grantees The list of grantees
* @param isGrant grant if true; revoke if false
* @return the bound node
*
* @exception StandardException Standard error policy.
*/
public QueryTreeNode bind(
HashMap<Provider,Provider> dependencies,
List<String> grantees,
boolean isGrant ) throws StandardException
{
// The below code handles the case where objectName.getSchemaName()
// returns null, in which case we'll fetch the schema descriptor for
// the current compilation schema (see getSchemaDescriptor).
SchemaDescriptor sd = getSchemaDescriptor( objectName.getSchemaName(), true);
objectName.setSchemaName( sd.getSchemaName() );
// Can not grant/revoke permissions from self
if (grantees.contains(sd.getAuthorizationId()))
{
throw StandardException.newException
(SQLState.AUTH_GRANT_REVOKE_NOT_ALLOWED, objectName.getFullTableName());
}
switch( objectType)
{
case TABLE_PRIVILEGES:
// can't grant/revoke privileges on system tables
if (sd.isSystemSchema())
{
throw StandardException.newException(SQLState.AUTH_GRANT_REVOKE_NOT_ALLOWED, objectName.getFullTableName());
}
TableDescriptor td = getTableDescriptor( objectName.getTableName(), sd);
if( td == null)
{
throw StandardException.newException( SQLState.LANG_TABLE_NOT_FOUND, objectName);
}
// Don't allow authorization on SESSION schema tables. Causes confusion if
// a temporary table is created later with same name.
if (isSessionSchema(sd.getSchemaName()))
{
throw StandardException.newException(SQLState.LANG_OPERATION_NOT_ALLOWED_ON_SESSION_SCHEMA_TABLES);
}
if (td.getTableType() != TableDescriptor.BASE_TABLE_TYPE &&
td.getTableType() != TableDescriptor.VIEW_TYPE)
{
throw StandardException.newException(SQLState.AUTH_GRANT_REVOKE_NOT_ALLOWED, objectName.getFullTableName());
}
specificPrivileges.bind( td, isGrant);
dependencyProvider = td;
break;
case ROUTINE_PRIVILEGES:
if (!sd.isSchemaWithGrantableRoutines())
{
throw StandardException.newException(SQLState.AUTH_GRANT_REVOKE_NOT_ALLOWED, objectName.getFullTableName());
}
AliasDescriptor proc = null;
List<AliasDescriptor> list = getDataDictionary().getRoutineList(
sd.getUUID().toString(),
objectName.getTableName(),
routineDesignator.isFunction ?
AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR :
AliasInfo.ALIAS_NAME_SPACE_PROCEDURE_AS_CHAR);
if( routineDesignator.paramTypeList == null)
{
// No signature was specified. Make sure that there is exactly one routine with that name.
if( list.size() > 1)
{
throw StandardException.newException( ( routineDesignator.isFunction ? SQLState.LANG_AMBIGUOUS_FUNCTION_NAME
: SQLState.LANG_AMBIGUOUS_PROCEDURE_NAME),
objectName.getFullTableName());
}
if( list.size() != 1) {
if (routineDesignator.isFunction) {
throw StandardException.newException(SQLState.LANG_NO_SUCH_FUNCTION,
objectName.getFullTableName());
} else {
throw StandardException.newException(SQLState.LANG_NO_SUCH_PROCEDURE,
objectName.getFullTableName());
}
}
proc = list.get(0);
}
else
{
// The full signature was specified
boolean found = false;
for (int i = list.size() - 1; (!found) && i >= 0; i--)
{
proc = list.get(i);
RoutineAliasInfo
routineInfo = (RoutineAliasInfo) proc.getAliasInfo();
int parameterCount = routineInfo.getParameterCount();
if (parameterCount != routineDesignator.paramTypeList.size())
continue;
TypeDescriptor[] parameterTypes = routineInfo.getParameterTypes();
found = true;
for( int parmIdx = 0; parmIdx < parameterCount; parmIdx++)
{
if( ! parameterTypes[parmIdx].equals( routineDesignator.paramTypeList.get( parmIdx)))
{
found = false;
break;
}
}
}
if( ! found)
{
// reconstruct the signature for the error message
StringBuilder sb =
new StringBuilder(objectName.getFullTableName());
sb.append( "(");
for( int i = 0; i < routineDesignator.paramTypeList.size(); i++)
{
if( i > 0)
sb.append(",");
sb.append( routineDesignator.paramTypeList.get(i).toString());
}
throw StandardException.newException(SQLState.LANG_NO_SUCH_METHOD_ALIAS, sb.toString());
}
}
routineDesignator.setAliasDescriptor( proc);
dependencyProvider = proc;
break;
case AGGREGATE_PRIVILEGES:
dependencyProvider = getDataDictionary().getAliasDescriptor
( sd.getUUID().toString(), objectName.getTableName(), AliasInfo.ALIAS_NAME_SPACE_AGGREGATE_AS_CHAR );
if ( dependencyProvider == null )
{
throw StandardException.newException
(SQLState.LANG_OBJECT_NOT_FOUND, "DERBY AGGREGATE", objectName.getFullTableName());
}
break;
case SEQUENCE_PRIVILEGES:
dependencyProvider = getDataDictionary().getSequenceDescriptor( sd, objectName.getTableName() );
if ( dependencyProvider == null )
{
throw StandardException.newException(SQLState.LANG_OBJECT_NOT_FOUND, "SEQUENCE", objectName.getFullTableName());
}
break;
case UDT_PRIVILEGES:
dependencyProvider = getDataDictionary().getAliasDescriptor
( sd.getUUID().toString(), objectName.getTableName(), AliasInfo.ALIAS_NAME_SPACE_UDT_AS_CHAR );
if ( dependencyProvider == null )
{
throw StandardException.newException(SQLState.LANG_OBJECT_NOT_FOUND, "TYPE", objectName.getFullTableName());
}
break;
default:
throw unimplementedFeature();
}
if( dependencyProvider != null)
{
if( dependencies.get( dependencyProvider) == null)
{
getCompilerContext().createDependency( dependencyProvider);
dependencies.put( dependencyProvider, dependencyProvider);
}
}
return this;
} // end of bind
/**
* @return PrivilegeInfo for this node
*/
PrivilegeInfo makePrivilegeInfo() throws StandardException
{
switch( objectType)
{
case TABLE_PRIVILEGES:
return specificPrivileges.makePrivilegeInfo();
case ROUTINE_PRIVILEGES:
return routineDesignator.makePrivilegeInfo();
case AGGREGATE_PRIVILEGES:
case SEQUENCE_PRIVILEGES:
case UDT_PRIVILEGES:
return new GenericPrivilegeInfo( (PrivilegedSQLObject) dependencyProvider, privilege, restrict );
default:
throw unimplementedFeature();
}
}
/** Report an unimplemented feature */
private StandardException unimplementedFeature()
{
return StandardException.newException( SQLState.BTREE_UNIMPLEMENTED_FEATURE );
}
@Override
void acceptChildren(Visitor v) throws StandardException {
super.acceptChildren(v);
if (objectName != null) {
objectName = (TableName) objectName.accept(v);
}
}
}