use of io.trino.sql.analyzer.RelationType in project trino by trinodb.
the class LogicalPlanner method getInsertPlan.
private RelationPlan getInsertPlan(Analysis analysis, Table table, Query query, TableHandle tableHandle, List<ColumnHandle> insertColumns, Optional<TableLayout> newTableLayout, Optional<WriterTarget> materializedViewRefreshWriterTarget) {
TableMetadata tableMetadata = metadata.getTableMetadata(session, tableHandle);
Map<NodeRef<LambdaArgumentDeclaration>, Symbol> lambdaDeclarationToSymbolMap = buildLambdaDeclarationToSymbolMap(analysis, symbolAllocator);
RelationPlanner planner = new RelationPlanner(analysis, symbolAllocator, idAllocator, lambdaDeclarationToSymbolMap, plannerContext, Optional.empty(), session, ImmutableMap.of());
RelationPlan plan = planner.process(query, null);
ImmutableList.Builder<Symbol> builder = ImmutableList.builder();
for (int i = 0; i < plan.getFieldMappings().size(); i++) {
if (!plan.getDescriptor().getFieldByIndex(i).isHidden()) {
builder.add(plan.getFieldMappings().get(i));
}
}
List<Symbol> visibleFieldMappings = builder.build();
Map<String, ColumnHandle> columns = metadata.getColumnHandles(session, tableHandle);
Assignments.Builder assignments = Assignments.builder();
boolean supportsMissingColumnsOnInsert = metadata.supportsMissingColumnsOnInsert(session, tableHandle);
ImmutableList.Builder<ColumnMetadata> insertedColumnsBuilder = ImmutableList.builder();
for (ColumnMetadata column : tableMetadata.getColumns()) {
if (column.isHidden()) {
continue;
}
Symbol output = symbolAllocator.newSymbol(column.getName(), column.getType());
int index = insertColumns.indexOf(columns.get(column.getName()));
if (index < 0) {
if (supportsMissingColumnsOnInsert) {
continue;
}
Expression cast = new Cast(new NullLiteral(), toSqlType(column.getType()));
assignments.put(output, cast);
insertedColumnsBuilder.add(column);
} else {
Symbol input = visibleFieldMappings.get(index);
Type tableType = column.getType();
Type queryType = symbolAllocator.getTypes().get(input);
if (queryType.equals(tableType) || typeCoercion.isTypeOnlyCoercion(queryType, tableType)) {
assignments.put(output, input.toSymbolReference());
} else {
Expression cast = noTruncationCast(input.toSymbolReference(), queryType, tableType);
assignments.put(output, cast);
}
insertedColumnsBuilder.add(column);
}
}
ProjectNode projectNode = new ProjectNode(idAllocator.getNextId(), plan.getRoot(), assignments.build());
List<ColumnMetadata> insertedColumns = insertedColumnsBuilder.build();
List<Field> fields = insertedColumns.stream().map(column -> Field.newUnqualified(column.getName(), column.getType())).collect(toImmutableList());
Scope scope = Scope.builder().withRelationType(RelationId.anonymous(), new RelationType(fields)).build();
plan = new RelationPlan(projectNode, scope, projectNode.getOutputSymbols(), Optional.empty());
plan = planner.addRowFilters(table, plan, failIfPredicateIsNotMeet(metadata, session, PERMISSION_DENIED, AccessDeniedException.PREFIX + "Cannot insert row that does not match to a row filter"), node -> {
Scope accessControlScope = analysis.getAccessControlScope(table);
// hidden fields are not accessible in insert
return Scope.builder().like(accessControlScope).withRelationType(accessControlScope.getRelationId(), accessControlScope.getRelationType().withOnlyVisibleFields()).build();
});
List<String> insertedTableColumnNames = insertedColumns.stream().map(ColumnMetadata::getName).collect(toImmutableList());
String catalogName = tableHandle.getCatalogName().getCatalogName();
TableStatisticsMetadata statisticsMetadata = metadata.getStatisticsCollectionMetadataForWrite(session, catalogName, tableMetadata.getMetadata());
if (materializedViewRefreshWriterTarget.isPresent()) {
return createTableWriterPlan(analysis, plan.getRoot(), plan.getFieldMappings(), materializedViewRefreshWriterTarget.get(), insertedTableColumnNames, insertedColumns, newTableLayout, statisticsMetadata);
}
InsertReference insertTarget = new InsertReference(tableHandle, insertedTableColumnNames.stream().map(columns::get).collect(toImmutableList()));
return createTableWriterPlan(analysis, plan.getRoot(), plan.getFieldMappings(), insertTarget, insertedTableColumnNames, insertedColumns, newTableLayout, statisticsMetadata);
}
use of io.trino.sql.analyzer.RelationType in project trino by trinodb.
the class RelationPlanner method process.
private SetOperationPlan process(SetOperation node) {
RelationType outputFields = analysis.getOutputDescriptor(node);
List<Symbol> outputs = outputFields.getAllFields().stream().map(symbolAllocator::newSymbol).collect(toImmutableList());
ImmutableListMultimap.Builder<Symbol, Symbol> symbolMapping = ImmutableListMultimap.builder();
ImmutableList.Builder<PlanNode> sources = ImmutableList.builder();
for (Relation child : node.getRelations()) {
RelationPlan plan = process(child, null);
NodeAndMappings planAndMappings;
List<Type> types = analysis.getRelationCoercion(child);
if (types == null) {
// no coercion required, only prune invisible fields from child outputs
planAndMappings = pruneInvisibleFields(plan, idAllocator);
} else {
// apply required coercion and prune invisible fields from child outputs
planAndMappings = coerce(plan, types, symbolAllocator, idAllocator);
}
for (int i = 0; i < outputFields.getAllFields().size(); i++) {
symbolMapping.put(outputs.get(i), planAndMappings.getFields().get(i));
}
sources.add(planAndMappings.getNode());
}
return new SetOperationPlan(sources.build(), symbolMapping.build());
}
use of io.trino.sql.analyzer.RelationType in project trino by trinodb.
the class SubqueryPlanner method planScalarSubquery.
private PlanBuilder planScalarSubquery(PlanBuilder subPlan, Cluster<SubqueryExpression> cluster) {
// Plan one of the predicates from the cluster
SubqueryExpression scalarSubquery = cluster.getRepresentative();
RelationPlan relationPlan = planSubquery(scalarSubquery, subPlan.getTranslations());
PlanBuilder subqueryPlan = newPlanBuilder(relationPlan, analysis, lambdaDeclarationToSymbolMap);
PlanNode root = new EnforceSingleRowNode(idAllocator.getNextId(), subqueryPlan.getRoot());
Type type = analysis.getType(scalarSubquery);
RelationType descriptor = relationPlan.getDescriptor();
List<Symbol> fieldMappings = relationPlan.getFieldMappings();
Symbol column;
if (descriptor.getVisibleFieldCount() > 1) {
column = symbolAllocator.newSymbol("row", type);
ImmutableList.Builder<Expression> fields = ImmutableList.builder();
for (int i = 0; i < descriptor.getAllFieldCount(); i++) {
Field field = descriptor.getFieldByIndex(i);
if (!field.isHidden()) {
fields.add(fieldMappings.get(i).toSymbolReference());
}
}
Expression expression = new Cast(new Row(fields.build()), TypeSignatureTranslator.toSqlType(type));
root = new ProjectNode(idAllocator.getNextId(), root, Assignments.of(column, expression));
} else {
column = getOnlyElement(fieldMappings);
}
return appendCorrelatedJoin(subPlan, root, scalarSubquery.getQuery(), CorrelatedJoinNode.Type.INNER, TRUE_LITERAL, mapAll(cluster, subPlan.getScope(), column));
}
use of io.trino.sql.analyzer.RelationType in project trino by trinodb.
the class SubqueryPlanner method planSubquery.
private PlanAndMappings planSubquery(Expression subquery, Optional<Type> coercion, TranslationMap outerContext) {
Type type = analysis.getType(subquery);
Symbol column = symbolAllocator.newSymbol("row", type);
RelationPlan relationPlan = planSubquery(subquery, outerContext);
PlanBuilder subqueryPlan = newPlanBuilder(relationPlan, analysis, lambdaDeclarationToSymbolMap, ImmutableMap.of(scopeAwareKey(subquery, analysis, relationPlan.getScope()), column));
RelationType descriptor = relationPlan.getDescriptor();
ImmutableList.Builder<Expression> fields = ImmutableList.builder();
for (int i = 0; i < descriptor.getAllFieldCount(); i++) {
Field field = descriptor.getFieldByIndex(i);
if (!field.isHidden()) {
fields.add(relationPlan.getFieldMappings().get(i).toSymbolReference());
}
}
subqueryPlan = subqueryPlan.withNewRoot(new ProjectNode(idAllocator.getNextId(), relationPlan.getRoot(), Assignments.of(column, new Cast(new Row(fields.build()), toSqlType(type)))));
return coerceIfNecessary(subqueryPlan, column, subquery, analysis.getType(subquery), coercion);
}
use of io.trino.sql.analyzer.RelationType in project trino by trinodb.
the class RelationPlanner method planJoin.
private RelationPlan planJoin(Expression criteria, Join.Type type, Scope scope, RelationPlan leftPlan, RelationPlan rightPlan, Analysis.SubqueryAnalysis subqueries) {
// NOTE: symbols must be in the same order as the outputDescriptor
List<Symbol> outputSymbols = ImmutableList.<Symbol>builder().addAll(leftPlan.getFieldMappings()).addAll(rightPlan.getFieldMappings()).build();
PlanBuilder leftPlanBuilder = newPlanBuilder(leftPlan, analysis, lambdaDeclarationToSymbolMap).withScope(scope, outputSymbols);
PlanBuilder rightPlanBuilder = newPlanBuilder(rightPlan, analysis, lambdaDeclarationToSymbolMap).withScope(scope, outputSymbols);
ImmutableList.Builder<JoinNode.EquiJoinClause> equiClauses = ImmutableList.builder();
List<Expression> complexJoinExpressions = new ArrayList<>();
List<Expression> postInnerJoinConditions = new ArrayList<>();
RelationType left = leftPlan.getDescriptor();
RelationType right = rightPlan.getDescriptor();
if (type != CROSS && type != IMPLICIT) {
List<Expression> leftComparisonExpressions = new ArrayList<>();
List<Expression> rightComparisonExpressions = new ArrayList<>();
List<ComparisonExpression.Operator> joinConditionComparisonOperators = new ArrayList<>();
for (Expression conjunct : ExpressionUtils.extractConjuncts(criteria)) {
if (!isEqualComparisonExpression(conjunct) && type != INNER) {
complexJoinExpressions.add(conjunct);
continue;
}
Set<QualifiedName> dependencies = SymbolsExtractor.extractNames(conjunct, analysis.getColumnReferences());
if (dependencies.stream().allMatch(left::canResolve) || dependencies.stream().allMatch(right::canResolve)) {
// If the conjunct can be evaluated entirely with the inputs on either side of the join, add
// it to the list complex expressions and let the optimizers figure out how to push it down later.
complexJoinExpressions.add(conjunct);
} else if (conjunct instanceof ComparisonExpression) {
Expression firstExpression = ((ComparisonExpression) conjunct).getLeft();
Expression secondExpression = ((ComparisonExpression) conjunct).getRight();
ComparisonExpression.Operator comparisonOperator = ((ComparisonExpression) conjunct).getOperator();
Set<QualifiedName> firstDependencies = SymbolsExtractor.extractNames(firstExpression, analysis.getColumnReferences());
Set<QualifiedName> secondDependencies = SymbolsExtractor.extractNames(secondExpression, analysis.getColumnReferences());
if (firstDependencies.stream().allMatch(left::canResolve) && secondDependencies.stream().allMatch(right::canResolve)) {
leftComparisonExpressions.add(firstExpression);
rightComparisonExpressions.add(secondExpression);
joinConditionComparisonOperators.add(comparisonOperator);
} else if (firstDependencies.stream().allMatch(right::canResolve) && secondDependencies.stream().allMatch(left::canResolve)) {
leftComparisonExpressions.add(secondExpression);
rightComparisonExpressions.add(firstExpression);
joinConditionComparisonOperators.add(comparisonOperator.flip());
} else {
// the case when we mix symbols from both left and right join side on either side of condition.
complexJoinExpressions.add(conjunct);
}
} else {
complexJoinExpressions.add(conjunct);
}
}
leftPlanBuilder = subqueryPlanner.handleSubqueries(leftPlanBuilder, leftComparisonExpressions, subqueries);
rightPlanBuilder = subqueryPlanner.handleSubqueries(rightPlanBuilder, rightComparisonExpressions, subqueries);
// Add projections for join criteria
leftPlanBuilder = leftPlanBuilder.appendProjections(leftComparisonExpressions, symbolAllocator, idAllocator);
rightPlanBuilder = rightPlanBuilder.appendProjections(rightComparisonExpressions, symbolAllocator, idAllocator);
QueryPlanner.PlanAndMappings leftCoercions = coerce(leftPlanBuilder, leftComparisonExpressions, analysis, idAllocator, symbolAllocator, typeCoercion);
leftPlanBuilder = leftCoercions.getSubPlan();
QueryPlanner.PlanAndMappings rightCoercions = coerce(rightPlanBuilder, rightComparisonExpressions, analysis, idAllocator, symbolAllocator, typeCoercion);
rightPlanBuilder = rightCoercions.getSubPlan();
for (int i = 0; i < leftComparisonExpressions.size(); i++) {
if (joinConditionComparisonOperators.get(i) == ComparisonExpression.Operator.EQUAL) {
Symbol leftSymbol = leftCoercions.get(leftComparisonExpressions.get(i));
Symbol rightSymbol = rightCoercions.get(rightComparisonExpressions.get(i));
equiClauses.add(new JoinNode.EquiJoinClause(leftSymbol, rightSymbol));
} else {
postInnerJoinConditions.add(new ComparisonExpression(joinConditionComparisonOperators.get(i), leftCoercions.get(leftComparisonExpressions.get(i)).toSymbolReference(), rightCoercions.get(rightComparisonExpressions.get(i)).toSymbolReference()));
}
}
}
PlanNode root = new JoinNode(idAllocator.getNextId(), JoinNode.Type.typeConvert(type), leftPlanBuilder.getRoot(), rightPlanBuilder.getRoot(), equiClauses.build(), leftPlanBuilder.getRoot().getOutputSymbols(), rightPlanBuilder.getRoot().getOutputSymbols(), false, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of(), Optional.empty());
if (type != INNER) {
for (Expression complexExpression : complexJoinExpressions) {
Set<QualifiedName> dependencies = SymbolsExtractor.extractNamesNoSubqueries(complexExpression, analysis.getColumnReferences());
// t JOIN u ON t.x + u.x = (...) get's planned on an arbitrary side
if (dependencies.stream().allMatch(left::canResolve)) {
leftPlanBuilder = subqueryPlanner.handleSubqueries(leftPlanBuilder, complexExpression, subqueries);
} else {
rightPlanBuilder = subqueryPlanner.handleSubqueries(rightPlanBuilder, complexExpression, subqueries);
}
}
}
TranslationMap translationMap = new TranslationMap(outerContext, scope, analysis, lambdaDeclarationToSymbolMap, outputSymbols).withAdditionalMappings(leftPlanBuilder.getTranslations().getMappings()).withAdditionalMappings(rightPlanBuilder.getTranslations().getMappings());
if (type != INNER && !complexJoinExpressions.isEmpty()) {
Expression joinedFilterCondition = ExpressionUtils.and(complexJoinExpressions);
Expression rewrittenFilterCondition = translationMap.rewrite(joinedFilterCondition);
root = new JoinNode(idAllocator.getNextId(), JoinNode.Type.typeConvert(type), leftPlanBuilder.getRoot(), rightPlanBuilder.getRoot(), equiClauses.build(), leftPlanBuilder.getRoot().getOutputSymbols(), rightPlanBuilder.getRoot().getOutputSymbols(), false, Optional.of(rewrittenFilterCondition), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of(), Optional.empty());
}
if (type == INNER) {
// rewrite all the other conditions using output symbols from left + right plan node.
PlanBuilder rootPlanBuilder = new PlanBuilder(translationMap, root);
rootPlanBuilder = subqueryPlanner.handleSubqueries(rootPlanBuilder, complexJoinExpressions, subqueries);
for (Expression expression : complexJoinExpressions) {
postInnerJoinConditions.add(rootPlanBuilder.rewrite(expression));
}
root = rootPlanBuilder.getRoot();
Expression postInnerJoinCriteria;
if (!postInnerJoinConditions.isEmpty()) {
postInnerJoinCriteria = ExpressionUtils.and(postInnerJoinConditions);
root = new FilterNode(idAllocator.getNextId(), root, postInnerJoinCriteria);
}
}
return new RelationPlan(root, scope, outputSymbols, outerContext);
}
Aggregations