Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed 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 com.facebook.presto.sql.analyzer;
import com.facebook.presto.common.QualifiedObjectName;
import com.facebook.presto.common.Subfield;
import com.facebook.presto.common.transaction.TransactionId;
import com.facebook.presto.common.type.Type;
import com.facebook.presto.spi.ColumnHandle;
import com.facebook.presto.spi.ColumnMetadata;
import com.facebook.presto.spi.TableHandle;
import com.facebook.presto.spi.analyzer.AccessControlInfo;
import com.facebook.presto.spi.analyzer.AccessControlInfoForTable;
import com.facebook.presto.spi.analyzer.AccessControlReferences;
import com.facebook.presto.spi.analyzer.AccessControlRole;
import com.facebook.presto.spi.function.FunctionHandle;
import com.facebook.presto.spi.function.FunctionKind;
import com.facebook.presto.spi.security.AccessControl;
import com.facebook.presto.spi.security.AccessControlContext;
import com.facebook.presto.spi.security.AllowAllAccessControl;
import com.facebook.presto.spi.security.Identity;
import com.facebook.presto.sql.tree.ExistsPredicate;
import com.facebook.presto.sql.tree.Expression;
import com.facebook.presto.sql.tree.FunctionCall;
import com.facebook.presto.sql.tree.GroupingOperation;
import com.facebook.presto.sql.tree.Identifier;
import com.facebook.presto.sql.tree.InPredicate;
import com.facebook.presto.sql.tree.Join;
import com.facebook.presto.sql.tree.LambdaArgumentDeclaration;
import com.facebook.presto.sql.tree.Node;
import com.facebook.presto.sql.tree.NodeRef;
import com.facebook.presto.sql.tree.Offset;
import com.facebook.presto.sql.tree.OrderBy;
import com.facebook.presto.sql.tree.Parameter;
import com.facebook.presto.sql.tree.QuantifiedComparisonExpression;
import com.facebook.presto.sql.tree.Query;
import com.facebook.presto.sql.tree.QuerySpecification;
import com.facebook.presto.sql.tree.Relation;
import com.facebook.presto.sql.tree.SampledRelation;
import com.facebook.presto.sql.tree.Statement;
import com.facebook.presto.sql.tree.SubqueryExpression;
import com.facebook.presto.sql.tree.Table;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static com.facebook.presto.sql.analyzer.Analysis.MaterializedViewAnalysisState.NOT_VISITED;
import static com.facebook.presto.sql.analyzer.Analysis.MaterializedViewAnalysisState.VISITED;
import static com.facebook.presto.sql.analyzer.Analysis.MaterializedViewAnalysisState.VISITING;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Multimaps.forMap;
import static com.google.common.collect.Multimaps.unmodifiableMultimap;
import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableCollection;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableSet;
import static java.util.Objects.requireNonNull;
public class Analysis
{
@Nullable
private final Statement root;
private final Map, Expression> parameters;
private String updateType;
private final Map, NamedQuery> namedQueries = new LinkedHashMap<>();
private final Map, Scope> scopes = new LinkedHashMap<>();
private final Multimap, FieldId> columnReferences = ArrayListMultimap.create();
private final AccessControlReferences accessControlReferences = new AccessControlReferences();
// a map of users to the columns per table that they access
private final Map>> tableColumnReferences = new LinkedHashMap<>();
private final Map>> utilizedTableColumnReferences = new LinkedHashMap<>();
private final Map>> tableColumnAndSubfieldReferences = new LinkedHashMap<>();
private final Map, List> aggregates = new LinkedHashMap<>();
private final Map, List> orderByAggregates = new LinkedHashMap<>();
private final Map, List> groupByExpressions = new LinkedHashMap<>();
private final Map, GroupingSetAnalysis> groupingSets = new LinkedHashMap<>();
private final Map, Expression> where = new LinkedHashMap<>();
private final Map, Expression> having = new LinkedHashMap<>();
private final Map, List> orderByExpressions = new LinkedHashMap<>();
private final Set> redundantOrderBy = new HashSet<>();
private final Map, List> outputExpressions = new LinkedHashMap<>();
private final Map, List> windowFunctions = new LinkedHashMap<>();
private final Map, List> orderByWindowFunctions = new LinkedHashMap<>();
private final Map, Long> offset = new LinkedHashMap<>();
private final Map, Expression> joins = new LinkedHashMap<>();
private final Map, JoinUsingAnalysis> joinUsing = new LinkedHashMap<>();
private final ListMultimap, InPredicate> inPredicatesSubqueries = ArrayListMultimap.create();
private final ListMultimap, SubqueryExpression> scalarSubqueries = ArrayListMultimap.create();
private final ListMultimap, ExistsPredicate> existsSubqueries = ArrayListMultimap.create();
private final ListMultimap, QuantifiedComparisonExpression> quantifiedComparisonSubqueries = ArrayListMultimap.create();
private final MetadataHandle metadataHandle = new MetadataHandle();
private final Map, TableHandle> tables = new LinkedHashMap<>();
private final Map, Type> types = new LinkedHashMap<>();
private final Map, Type> coercions = new LinkedHashMap<>();
// Coercions needed for window function frame of type RANGE.
// These are coercions for the sort key, needed for frame bound calculation, identified by frame range offset expression.
// Frame definition might contain two different offset expressions (for start and end), each requiring different coercion of the sort key.
private final Map, Type> sortKeyCoercionsForFrameBoundCalculation = new LinkedHashMap<>();
// Coercions needed for window function frame of type RANGE.
// These are coercions for the sort key, needed for comparison of the sort key with precomputed frame bound, identified by frame range offset expression.
private final Map, Type> sortKeyCoercionsForFrameBoundComparison = new LinkedHashMap<>();
// Functions for calculating frame bounds for frame of type RANGE, identified by frame range offset expression.
private final Map, FunctionHandle> frameBoundCalculations = new LinkedHashMap<>();
private final Set> typeOnlyCoercions = new LinkedHashSet<>();
private final Map, List> relationCoercions = new LinkedHashMap<>();
private final Map, FunctionHandle> functionHandles = new LinkedHashMap<>();
private final Map, LambdaArgumentDeclaration> lambdaArgumentReferences = new LinkedHashMap<>();
private final Map columns = new LinkedHashMap<>();
private final Map, Double> sampleRatios = new LinkedHashMap<>();
private final Map, List> groupingOperations = new LinkedHashMap<>();
// for create table
private Optional createTableDestination = Optional.empty();
private Map createTableProperties = ImmutableMap.of();
private boolean createTableAsSelectWithData = true;
private boolean createTableAsSelectNoOp;
private Optional> createTableColumnAliases = Optional.empty();
private Optional createTableComment = Optional.empty();
private Optional insert = Optional.empty();
private Optional refreshMaterializedViewAnalysis = Optional.empty();
private Optional analyzeTarget = Optional.empty();
private Optional> updatedColumns = Optional.empty();
// for describe input and describe output
private final boolean isDescribe;
// for recursive view detection
private final Deque
tablesForView = new ArrayDeque<>();
// To prevent recursive analyzing of one materialized view base table
private final ListMultimap, Table> tablesForMaterializedView = ArrayListMultimap.create();
// for materialized view analysis state detection, state is used to identify if materialized view has been expanded or in-process.
private final Map
materializedViewAnalysisStateMap = new HashMap<>();
private final Map materializedViews = new LinkedHashMap<>();
private Optional expandedQuery = Optional.empty();
// Keeps track of the subquery we are visiting, so we have access to base query information when processing materialized view status
private Optional currentQuerySpecification = Optional.empty();
public Analysis(@Nullable Statement root, Map, Expression> parameters, boolean isDescribe)
{
this.root = root;
this.parameters = ImmutableMap.copyOf(requireNonNull(parameters, "parameterMap is null"));
this.isDescribe = isDescribe;
}
public Statement getStatement()
{
return root;
}
public String getUpdateType()
{
return updateType;
}
public void setUpdateType(String updateType)
{
this.updateType = updateType;
}
public boolean isCreateTableAsSelectWithData()
{
return createTableAsSelectWithData;
}
public void setCreateTableAsSelectWithData(boolean createTableAsSelectWithData)
{
this.createTableAsSelectWithData = createTableAsSelectWithData;
}
public boolean isCreateTableAsSelectNoOp()
{
return createTableAsSelectNoOp;
}
public void setCreateTableAsSelectNoOp(boolean createTableAsSelectNoOp)
{
this.createTableAsSelectNoOp = createTableAsSelectNoOp;
}
public void setAggregates(QuerySpecification node, List aggregates)
{
this.aggregates.put(NodeRef.of(node), ImmutableList.copyOf(aggregates));
}
public List getAggregates(QuerySpecification query)
{
return aggregates.get(NodeRef.of(query));
}
public void setOrderByAggregates(OrderBy node, List aggregates)
{
this.orderByAggregates.put(NodeRef.of(node), ImmutableList.copyOf(aggregates));
}
public List getOrderByAggregates(OrderBy node)
{
return orderByAggregates.get(NodeRef.of(node));
}
public Map, Type> getTypes()
{
return unmodifiableMap(types);
}
public Type getType(Expression expression)
{
Type type = types.get(NodeRef.of(expression));
checkArgument(type != null, "Expression not analyzed: %s", expression);
return type;
}
public Type getTypeWithCoercions(Expression expression)
{
NodeRef key = NodeRef.of(expression);
checkArgument(types.containsKey(key), "Expression not analyzed: %s", expression);
if (coercions.containsKey(key)) {
return coercions.get(key);
}
return types.get(key);
}
public Type[] getRelationCoercion(Relation relation)
{
return Optional.ofNullable(relationCoercions.get(NodeRef.of(relation)))
.map(types -> types.stream().toArray(Type[]::new))
.orElse(null);
}
public void addRelationCoercion(Relation relation, Type[] types)
{
relationCoercions.put(NodeRef.of(relation), ImmutableList.copyOf(types));
}
public Map, Type> getCoercions()
{
return unmodifiableMap(coercions);
}
public Set> getTypeOnlyCoercions()
{
return unmodifiableSet(typeOnlyCoercions);
}
public Type getCoercion(Expression expression)
{
return coercions.get(NodeRef.of(expression));
}
public void addLambdaArgumentReferences(Map, LambdaArgumentDeclaration> lambdaArgumentReferences)
{
this.lambdaArgumentReferences.putAll(lambdaArgumentReferences);
}
public LambdaArgumentDeclaration getLambdaArgumentReference(Identifier identifier)
{
return lambdaArgumentReferences.get(NodeRef.of(identifier));
}
public Map, LambdaArgumentDeclaration> getLambdaArgumentReferences()
{
return unmodifiableMap(lambdaArgumentReferences);
}
public void setGroupingSets(QuerySpecification node, GroupingSetAnalysis groupingSets)
{
this.groupingSets.put(NodeRef.of(node), groupingSets);
}
public void setGroupByExpressions(QuerySpecification node, List expressions)
{
groupByExpressions.put(NodeRef.of(node), expressions);
}
public boolean isAggregation(QuerySpecification node)
{
return groupByExpressions.containsKey(NodeRef.of(node));
}
public boolean isTypeOnlyCoercion(Expression expression)
{
return typeOnlyCoercions.contains(NodeRef.of(expression));
}
public GroupingSetAnalysis getGroupingSets(QuerySpecification node)
{
return groupingSets.get(NodeRef.of(node));
}
public List getGroupByExpressions(QuerySpecification node)
{
return groupByExpressions.get(NodeRef.of(node));
}
public void setWhere(Node node, Expression expression)
{
where.put(NodeRef.of(node), expression);
}
public Expression getWhere(QuerySpecification node)
{
return where.get(NodeRef.of(node));
}
public void setOrderByExpressions(Node node, List items)
{
orderByExpressions.put(NodeRef.of(node), ImmutableList.copyOf(items));
}
public List getOrderByExpressions(Node node)
{
return orderByExpressions.get(NodeRef.of(node));
}
public void setOffset(Offset node, long rowCount)
{
offset.put(NodeRef.of(node), rowCount);
}
public long getOffset(Offset node)
{
checkState(offset.containsKey(NodeRef.of(node)), "missing OFFSET value for node %s", node);
return offset.get(NodeRef.of(node));
}
public void setOutputExpressions(Node node, List expressions)
{
outputExpressions.put(NodeRef.of(node), ImmutableList.copyOf(expressions));
}
public List getOutputExpressions(Node node)
{
return outputExpressions.get(NodeRef.of(node));
}
public void setHaving(QuerySpecification node, Expression expression)
{
having.put(NodeRef.of(node), expression);
}
public void setJoinCriteria(Join node, Expression criteria)
{
joins.put(NodeRef.of(node), criteria);
}
public Expression getJoinCriteria(Join join)
{
return joins.get(NodeRef.of(join));
}
public void recordSubqueries(Node node, ExpressionAnalysis expressionAnalysis)
{
NodeRef key = NodeRef.of(node);
this.inPredicatesSubqueries.putAll(key, dereference(expressionAnalysis.getSubqueryInPredicates()));
this.scalarSubqueries.putAll(key, dereference(expressionAnalysis.getScalarSubqueries()));
this.existsSubqueries.putAll(key, dereference(expressionAnalysis.getExistsSubqueries()));
this.quantifiedComparisonSubqueries.putAll(key, dereference(expressionAnalysis.getQuantifiedComparisons()));
}
private List dereference(Collection> nodeRefs)
{
return nodeRefs.stream()
.map(NodeRef::getNode)
.collect(toImmutableList());
}
public List getInPredicateSubqueries(Node node)
{
return ImmutableList.copyOf(inPredicatesSubqueries.get(NodeRef.of(node)));
}
public List getScalarSubqueries(Node node)
{
return ImmutableList.copyOf(scalarSubqueries.get(NodeRef.of(node)));
}
public boolean isScalarSubquery(SubqueryExpression subqueryExpression)
{
return scalarSubqueries.values().contains(subqueryExpression);
}
public List getExistsSubqueries(Node node)
{
return ImmutableList.copyOf(existsSubqueries.get(NodeRef.of(node)));
}
public List getQuantifiedComparisonSubqueries(Node node)
{
return unmodifiableList(quantifiedComparisonSubqueries.get(NodeRef.of(node)));
}
public void setWindowFunctions(QuerySpecification node, List functions)
{
windowFunctions.put(NodeRef.of(node), ImmutableList.copyOf(functions));
}
public List getWindowFunctions(QuerySpecification query)
{
return windowFunctions.get(NodeRef.of(query));
}
public void setOrderByWindowFunctions(OrderBy node, List functions)
{
orderByWindowFunctions.put(NodeRef.of(node), ImmutableList.copyOf(functions));
}
public List getOrderByWindowFunctions(OrderBy query)
{
return orderByWindowFunctions.get(NodeRef.of(query));
}
public void addColumnReferences(Map, FieldId> columnReferences)
{
this.columnReferences.putAll(forMap(columnReferences));
}
public void addColumnReference(NodeRef node, FieldId fieldId)
{
this.columnReferences.put(node, fieldId);
}
public Scope getScope(Node node)
{
return tryGetScope(node).orElseThrow(() -> new IllegalArgumentException(format("Analysis does not contain information for node: %s", node)));
}
public Optional tryGetScope(Node node)
{
NodeRef key = NodeRef.of(node);
if (scopes.containsKey(key)) {
return Optional.of(scopes.get(key));
}
return Optional.empty();
}
public Scope getRootScope()
{
return getScope(root);
}
public void setScope(Node node, Scope scope)
{
scopes.put(NodeRef.of(node), scope);
}
public RelationType getOutputDescriptor()
{
return getOutputDescriptor(root);
}
public RelationType getOutputDescriptor(Node node)
{
return getScope(node).getRelationType();
}
public MetadataHandle getMetadataHandle()
{
return metadataHandle;
}
public TableHandle getTableHandle(Table table)
{
return tables.get(NodeRef.of(table));
}
public Collection getTables()
{
return unmodifiableCollection(tables.values());
}
public List
getTableNodes()
{
return tables.keySet().stream().map(NodeRef::getNode).collect(toImmutableList());
}
public void registerTable(Table table, TableHandle handle)
{
tables.put(NodeRef.of(table), handle);
}
public FunctionHandle getFunctionHandle(FunctionCall function)
{
return functionHandles.get(NodeRef.of(function));
}
public Map, FunctionHandle> getFunctionHandles()
{
return ImmutableMap.copyOf(functionHandles);
}
public void addFunctionHandles(Map, FunctionHandle> infos)
{
functionHandles.putAll(infos);
}
public Set> getColumnReferences()
{
return unmodifiableSet(columnReferences.keySet());
}
public Multimap, FieldId> getColumnReferenceFields()
{
return unmodifiableMultimap(columnReferences);
}
public boolean isColumnReference(Expression expression)
{
requireNonNull(expression, "expression is null");
checkArgument(getType(expression) != null, "expression %s has not been analyzed", expression);
return columnReferences.containsKey(NodeRef.of(expression));
}
public void addTypes(Map, Type> types)
{
this.types.putAll(types);
}
public void addCoercion(Expression expression, Type type, boolean isTypeOnlyCoercion)
{
this.coercions.put(NodeRef.of(expression), type);
if (isTypeOnlyCoercion) {
this.typeOnlyCoercions.add(NodeRef.of(expression));
}
}
public void addCoercions(
Map, Type> coercions,
Set> typeOnlyCoercions,
Map, Type> sortKeyCoercionsForFrameBoundCalculation,
Map, Type> sortKeyCoercionsForFrameBoundComparison)
{
this.coercions.putAll(coercions);
this.typeOnlyCoercions.addAll(typeOnlyCoercions);
this.sortKeyCoercionsForFrameBoundCalculation.putAll(sortKeyCoercionsForFrameBoundCalculation);
this.sortKeyCoercionsForFrameBoundComparison.putAll(sortKeyCoercionsForFrameBoundComparison);
}
public Type getSortKeyCoercionForFrameBoundCalculation(Expression frameOffset)
{
return sortKeyCoercionsForFrameBoundCalculation.get(NodeRef.of(frameOffset));
}
public Type getSortKeyCoercionForFrameBoundComparison(Expression frameOffset)
{
return sortKeyCoercionsForFrameBoundComparison.get(NodeRef.of(frameOffset));
}
public void addFrameBoundCalculations(Map, FunctionHandle> frameBoundCalculations)
{
this.frameBoundCalculations.putAll(frameBoundCalculations);
}
public FunctionHandle getFrameBoundCalculation(Expression frameOffset)
{
return frameBoundCalculations.get(NodeRef.of(frameOffset));
}
public Expression getHaving(QuerySpecification query)
{
return having.get(NodeRef.of(query));
}
public void setColumn(Field field, ColumnHandle handle)
{
columns.put(field, handle);
}
public ColumnHandle getColumn(Field field)
{
return columns.get(field);
}
public void setCreateTableDestination(QualifiedObjectName destination)
{
this.createTableDestination = Optional.of(destination);
}
public Optional getCreateTableDestination()
{
return createTableDestination;
}
public Optional getAnalyzeTarget()
{
return analyzeTarget;
}
public void setAnalyzeTarget(TableHandle analyzeTarget)
{
this.analyzeTarget = Optional.of(analyzeTarget);
}
public void setCreateTableProperties(Map createTableProperties)
{
this.createTableProperties = ImmutableMap.copyOf(createTableProperties);
}
public Map getCreateTableProperties()
{
return createTableProperties;
}
public Optional> getColumnAliases()
{
return createTableColumnAliases;
}
public void setCreateTableColumnAliases(List createTableColumnAliases)
{
this.createTableColumnAliases = Optional.of(createTableColumnAliases);
}
public void setCreateTableComment(Optional createTableComment)
{
this.createTableComment = requireNonNull(createTableComment);
}
public Optional getCreateTableComment()
{
return createTableComment;
}
public void setInsert(Insert insert)
{
this.insert = Optional.of(insert);
}
public Optional getInsert()
{
return insert;
}
public void setUpdatedColumns(List updatedColumns)
{
this.updatedColumns = Optional.of(updatedColumns);
}
public Optional> getUpdatedColumns()
{
return updatedColumns;
}
public void setRefreshMaterializedViewAnalysis(RefreshMaterializedViewAnalysis refreshMaterializedViewAnalysis)
{
this.refreshMaterializedViewAnalysis = Optional.of(refreshMaterializedViewAnalysis);
}
public Optional getRefreshMaterializedViewAnalysis()
{
return refreshMaterializedViewAnalysis;
}
public NamedQuery getNamedQuery(Table table)
{
return namedQueries.get(NodeRef.of(table));
}
public void registerNamedQuery(Table tableReference, Query query, boolean isFromView)
{
requireNonNull(tableReference, "tableReference is null");
requireNonNull(query, "query is null");
namedQueries.put(NodeRef.of(tableReference), new NamedQuery(query, isFromView));
}
public void registerTableForView(Table tableReference)
{
tablesForView.push(requireNonNull(tableReference, "table is null"));
}
public void unregisterTableForView()
{
tablesForView.pop();
}
public void registerMaterializedViewForAnalysis(QualifiedObjectName materializedViewName, Table materializedView, String materializedViewSql)
{
requireNonNull(materializedView, "materializedView is null");
if (materializedViewAnalysisStateMap.containsKey(materializedView)) {
materializedViewAnalysisStateMap.put(materializedView, VISITED);
}
else {
materializedViewAnalysisStateMap.put(materializedView, VISITING);
}
materializedViews.put(materializedViewName, materializedViewSql);
}
public void unregisterMaterializedViewForAnalysis(Table materializedView)
{
requireNonNull(materializedView, "materializedView is null");
checkState(
materializedViewAnalysisStateMap.containsKey(materializedView),
format("materializedViewAnalysisStateMap does not contain materialized view : %s", materializedView.getName()));
materializedViewAnalysisStateMap.remove(materializedView);
}
public MaterializedViewAnalysisState getMaterializedViewAnalysisState(Table materializedView)
{
requireNonNull(materializedView, "materializedView is null");
return materializedViewAnalysisStateMap.getOrDefault(materializedView, NOT_VISITED);
}
public boolean hasTableInView(Table tableReference)
{
return tablesForView.contains(tableReference);
}
public void registerTableForMaterializedView(Table view, Table table)
{
requireNonNull(view, "view is null");
requireNonNull(table, "table is null");
tablesForMaterializedView.put(NodeRef.of(view), table);
}
public void unregisterTableForMaterializedView(Table view, Table table)
{
requireNonNull(view, "view is null");
requireNonNull(table, "table is null");
tablesForMaterializedView.remove(NodeRef.of(view), table);
}
public boolean hasTableRegisteredForMaterializedView(Table view, Table table)
{
requireNonNull(view, "view is null");
requireNonNull(table, "table is null");
return tablesForMaterializedView.containsEntry(NodeRef.of(view), table);
}
public void setSampleRatio(SampledRelation relation, double ratio)
{
sampleRatios.put(NodeRef.of(relation), ratio);
}
public double getSampleRatio(SampledRelation relation)
{
NodeRef key = NodeRef.of(relation);
checkState(sampleRatios.containsKey(key), "Sample ratio missing for %s. Broken analysis?", relation);
return sampleRatios.get(key);
}
public void setGroupingOperations(QuerySpecification querySpecification, List groupingOperations)
{
this.groupingOperations.put(NodeRef.of(querySpecification), ImmutableList.copyOf(groupingOperations));
}
public List getGroupingOperations(QuerySpecification querySpecification)
{
return Optional.ofNullable(groupingOperations.get(NodeRef.of(querySpecification)))
.orElse(emptyList());
}
public Map, Expression> getParameters()
{
return parameters;
}
public boolean isDescribe()
{
return isDescribe;
}
public void setJoinUsing(Join node, JoinUsingAnalysis analysis)
{
joinUsing.put(NodeRef.of(node), analysis);
}
public JoinUsingAnalysis getJoinUsing(Join node)
{
return joinUsing.get(NodeRef.of(node));
}
public AccessControlReferences getAccessControlReferences()
{
return accessControlReferences;
}
public void addAccessControlCheckForTable(AccessControlRole accessControlRole, AccessControlInfoForTable accessControlInfoForTable)
{
accessControlReferences.addTableReference(accessControlRole, accessControlInfoForTable);
}
public void addTableColumnAndSubfieldReferences(
AccessControl accessControl,
Identity identity,
Optional transactionId,
AccessControlContext accessControlContext,
Multimap tableColumnMap,
Multimap tableColumnMapForAccessControl)
{
AccessControlInfo accessControlInfo = new AccessControlInfo(accessControl, identity, transactionId, accessControlContext);
Map> columnReferences = tableColumnReferences.computeIfAbsent(accessControlInfo, k -> new LinkedHashMap<>());
tableColumnMap.asMap()
.forEach((key, value) -> columnReferences.computeIfAbsent(key, k -> new HashSet<>()).addAll(value.stream().map(Subfield::getRootName).collect(toImmutableSet())));
Map> columnAndSubfieldReferences = tableColumnAndSubfieldReferences.computeIfAbsent(accessControlInfo, k -> new LinkedHashMap<>());
tableColumnMapForAccessControl.asMap()
.forEach((key, value) -> columnAndSubfieldReferences.computeIfAbsent(key, k -> new HashSet<>()).addAll(value));
}
public void addEmptyColumnReferencesForTable(AccessControl accessControl, Identity identity, Optional transactionId, AccessControlContext accessControlContext, QualifiedObjectName table)
{
AccessControlInfo accessControlInfo = new AccessControlInfo(accessControl, identity, transactionId, accessControlContext);
tableColumnReferences.computeIfAbsent(accessControlInfo, k -> new LinkedHashMap<>()).computeIfAbsent(table, k -> new HashSet<>());
tableColumnAndSubfieldReferences.computeIfAbsent(accessControlInfo, k -> new LinkedHashMap<>()).computeIfAbsent(table, k -> new HashSet<>());
}
public Map>> getTableColumnReferences()
{
return tableColumnReferences;
}
public void addUtilizedTableColumnReferences(AccessControlInfo accessControlInfo, Map> utilizedTableColumns)
{
utilizedTableColumnReferences.put(accessControlInfo, utilizedTableColumns);
}
public Map>> getUtilizedTableColumnReferences()
{
return ImmutableMap.copyOf(utilizedTableColumnReferences);
}
public void populateTableColumnAndSubfieldReferencesForAccessControl(boolean checkAccessControlOnUtilizedColumnsOnly, boolean checkAccessControlWithSubfields)
{
accessControlReferences.addTableColumnAndSubfieldReferencesForAccessControl(getTableColumnAndSubfieldReferencesForAccessControl(checkAccessControlOnUtilizedColumnsOnly, checkAccessControlWithSubfields));
}
private Map>> getTableColumnAndSubfieldReferencesForAccessControl(boolean checkAccessControlOnUtilizedColumnsOnly, boolean checkAccessControlWithSubfields)
{
Map>> references;
if (!checkAccessControlWithSubfields) {
references = (checkAccessControlOnUtilizedColumnsOnly ? utilizedTableColumnReferences : tableColumnReferences).entrySet().stream()
.collect(toImmutableMap(
Map.Entry::getKey,
accessControlEntry -> accessControlEntry.getValue().entrySet().stream().collect(toImmutableMap(
Map.Entry::getKey,
tableEntry -> tableEntry.getValue().stream().map(column -> new Subfield(column, ImmutableList.of())).collect(toImmutableSet())))));
}
else if (!checkAccessControlOnUtilizedColumnsOnly) {
references = tableColumnAndSubfieldReferences;
}
else {
// TODO: Properly support utilized column check. Currently, we prune whole columns, if they are not utilized.
// We need to generalize it and exclude unutilized subfield references independently.
references = tableColumnAndSubfieldReferences.entrySet().stream()
.collect(toImmutableMap(
Map.Entry::getKey, accessControlEntry ->
accessControlEntry.getValue().entrySet().stream().collect(toImmutableMap(
Map.Entry::getKey, tableEntry -> tableEntry.getValue().stream().filter(
column -> {
Map> utilizedTableReferences = utilizedTableColumnReferences.get(accessControlEntry.getKey());
if (utilizedTableReferences == null) {
return false;
}
Set utilizedColumns = utilizedTableReferences.get(tableEntry.getKey());
return utilizedColumns != null && utilizedColumns.contains(column.getRootName());
})
.collect(toImmutableSet())))));
}
return buildMaterializedViewAccessControl(references);
}
/**
* For a query on materialized view, only check the actual required access controls for its base tables. For the materialized view,
* will not check access control by replacing with AllowAllAccessControl.
**/
private Map>> buildMaterializedViewAccessControl(Map>> tableColumnReferences)
{
if (!(getStatement() instanceof Query) || materializedViews.isEmpty()) {
return tableColumnReferences;
}
Map>> newTableColumnReferences = new LinkedHashMap<>();
tableColumnReferences.forEach((accessControlInfo, references) -> {
AccessControlInfo allowAllAccessControlInfo = new AccessControlInfo(new AllowAllAccessControl(), accessControlInfo.getIdentity(), accessControlInfo.getTransactionId(), accessControlInfo.getAccessControlContext());
Map> newAllowAllReferences = newTableColumnReferences.getOrDefault(allowAllAccessControlInfo, new LinkedHashMap<>());
Map> newOtherReferences = new LinkedHashMap<>();
references.forEach((table, columns) -> {
if (materializedViews.containsKey(table)) {
newAllowAllReferences.computeIfAbsent(table, key -> new HashSet<>()).addAll(columns);
}
else {
newOtherReferences.put(table, columns);
}
});
if (!newAllowAllReferences.isEmpty()) {
newTableColumnReferences.put(allowAllAccessControlInfo, newAllowAllReferences);
}
if (!newOtherReferences.isEmpty()) {
newTableColumnReferences.put(accessControlInfo, newOtherReferences);
}
});
return newTableColumnReferences;
}
public void markRedundantOrderBy(OrderBy orderBy)
{
redundantOrderBy.add(NodeRef.of(orderBy));
}
public boolean isOrderByRedundant(OrderBy orderBy)
{
return redundantOrderBy.contains(NodeRef.of(orderBy));
}
public void setExpandedQuery(String expandedQuery)
{
this.expandedQuery = Optional.of(expandedQuery);
}
public Optional getExpandedQuery()
{
return expandedQuery;
}
public void setCurrentSubquery(QuerySpecification currentSubQuery)
{
this.currentQuerySpecification = Optional.of(currentSubQuery);
}
public Optional getCurrentQuerySpecification()
{
return currentQuerySpecification;
}
public Map> getInvokedFunctions()
{
Map> functionMap = new HashMap<>();
for (FunctionHandle functionHandle : functionHandles.values()) {
functionMap.putIfAbsent(functionHandle.getKind(), new HashSet<>());
functionMap.get(functionHandle.getKind()).add(functionHandle.getName());
}
return functionMap.entrySet().stream().collect(toImmutableMap(Map.Entry::getKey, entry -> ImmutableSet.copyOf(entry.getValue())));
}
@Immutable
public static final class Insert
{
private final TableHandle target;
private final List columns;
public Insert(TableHandle target, List columns)
{
this.target = requireNonNull(target, "target is null");
this.columns = requireNonNull(columns, "columns is null");
checkArgument(columns.size() > 0, "No columns given to insert");
}
public List getColumns()
{
return columns;
}
public TableHandle getTarget()
{
return target;
}
}
@Immutable
public static final class RefreshMaterializedViewAnalysis
{
private final TableHandle target;
private final List columns;
private final Query query;
public RefreshMaterializedViewAnalysis(TableHandle target, List columns, Query query)
{
this.target = requireNonNull(target, "target is null");
this.columns = requireNonNull(columns, "columns is null");
this.query = requireNonNull(query, "query is null");
checkArgument(columns.size() > 0, "No columns given to insert");
}
public List getColumns()
{
return columns;
}
public TableHandle getTarget()
{
return target;
}
public Query getQuery()
{
return query;
}
}
public static final class JoinUsingAnalysis
{
private final List leftJoinFields;
private final List rightJoinFields;
private final List otherLeftFields;
private final List otherRightFields;
JoinUsingAnalysis(List leftJoinFields, List rightJoinFields, List otherLeftFields, List otherRightFields)
{
this.leftJoinFields = ImmutableList.copyOf(leftJoinFields);
this.rightJoinFields = ImmutableList.copyOf(rightJoinFields);
this.otherLeftFields = ImmutableList.copyOf(otherLeftFields);
this.otherRightFields = ImmutableList.copyOf(otherRightFields);
checkArgument(leftJoinFields.size() == rightJoinFields.size(), "Expected join fields for left and right to have the same size");
}
public List getLeftJoinFields()
{
return leftJoinFields;
}
public List getRightJoinFields()
{
return rightJoinFields;
}
public List getOtherLeftFields()
{
return otherLeftFields;
}
public List getOtherRightFields()
{
return otherRightFields;
}
}
public static class GroupingSetAnalysis
{
private final List> cubes;
private final List> rollups;
private final List>> ordinarySets;
private final List complexExpressions;
public GroupingSetAnalysis(
List> cubes,
List> rollups,
List>> ordinarySets,
List complexExpressions)
{
this.cubes = ImmutableList.copyOf(cubes);
this.rollups = ImmutableList.copyOf(rollups);
this.ordinarySets = ImmutableList.copyOf(ordinarySets);
this.complexExpressions = ImmutableList.copyOf(complexExpressions);
}
public List> getCubes()
{
return cubes;
}
public List> getRollups()
{
return rollups;
}
public List>> getOrdinarySets()
{
return ordinarySets;
}
public List getComplexExpressions()
{
return complexExpressions;
}
}
public enum MaterializedViewAnalysisState
{
NOT_VISITED(0),
VISITING(1),
VISITED(2);
private final int value;
MaterializedViewAnalysisState(int value)
{
this.value = value;
}
public boolean isNotVisited()
{
return this.value == NOT_VISITED.value;
}
public boolean isVisited()
{
return this.value == VISITED.value;
}
public boolean isVisiting()
{
return this.value == VISITING.value;
}
}
public class NamedQuery
{
private final Query query;
private final boolean isFromView;
public NamedQuery(Query query, boolean isFromView)
{
this.query = query;
this.isFromView = isFromView;
}
public Query getQuery()
{
return query;
}
public boolean isFromView()
{
return isFromView;
}
}
}