use of io.trino.sql.analyzer.Scope 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.Scope in project trino by trinodb.
the class RelationPlanner method visitValues.
@Override
protected RelationPlan visitValues(Values node, Void context) {
Scope scope = analysis.getScope(node);
ImmutableList.Builder<Symbol> outputSymbolsBuilder = ImmutableList.builder();
for (Field field : scope.getRelationType().getVisibleFields()) {
Symbol symbol = symbolAllocator.newSymbol(field);
outputSymbolsBuilder.add(symbol);
}
List<Symbol> outputSymbols = outputSymbolsBuilder.build();
TranslationMap translationMap = new TranslationMap(outerContext, analysis.getScope(node), analysis, lambdaDeclarationToSymbolMap, outputSymbols);
ImmutableList.Builder<Expression> rows = ImmutableList.builder();
for (Expression row : node.getRows()) {
if (row instanceof Row) {
rows.add(new Row(((Row) row).getItems().stream().map(item -> coerceIfNecessary(analysis, item, translationMap.rewrite(item))).collect(toImmutableList())));
} else if (analysis.getType(row) instanceof RowType) {
rows.add(coerceIfNecessary(analysis, row, translationMap.rewrite(row)));
} else {
rows.add(new Row(ImmutableList.of(coerceIfNecessary(analysis, row, translationMap.rewrite(row)))));
}
}
ValuesNode valuesNode = new ValuesNode(idAllocator.getNextId(), outputSymbols, rows.build());
return new RelationPlan(valuesNode, scope, outputSymbols, outerContext);
}
use of io.trino.sql.analyzer.Scope in project trino by trinodb.
the class ScopeAware method scopeAwareHash.
private OptionalInt scopeAwareHash(Node node) {
if (node instanceof Expression) {
Expression expression = (Expression) node;
if (analysis.isColumnReference(expression)) {
ResolvedField field = analysis.getResolvedField(expression);
Scope resolvedScope = field.getScope();
if (resolvedScope.hasOuterParent(queryScope)) {
return OptionalInt.of(treeHash(expression, CanonicalizationAware::canonicalizationAwareHash));
}
return OptionalInt.of(field.getFieldId().hashCode());
} else if (expression instanceof Identifier) {
return OptionalInt.of(treeHash(expression, CanonicalizationAware::canonicalizationAwareHash));
} else if (node.getChildren().isEmpty()) {
// Calculate shallow hash since node doesn't have any children
return OptionalInt.of(expression.hashCode());
}
}
return OptionalInt.empty();
}
use of io.trino.sql.analyzer.Scope in project trino by trinodb.
the class RelationPlanner method planSingleEmptyRow.
private PlanBuilder planSingleEmptyRow(Optional<Scope> parent) {
Scope.Builder scope = Scope.builder();
parent.ifPresent(scope::withOuterQueryParent);
PlanNode values = new ValuesNode(idAllocator.getNextId(), 1);
TranslationMap translations = new TranslationMap(outerContext, scope.build(), analysis, lambdaDeclarationToSymbolMap, ImmutableList.of());
return new PlanBuilder(translations, values);
}
use of io.trino.sql.analyzer.Scope in project trino by trinodb.
the class RelationPlanner method visitTable.
@Override
protected RelationPlan visitTable(Table node, Void context) {
// is this a recursive reference in expandable named query? If so, there's base relation already planned.
RelationPlan expansion = recursiveSubqueries.get(NodeRef.of(node));
if (expansion != null) {
// put the pre-planned recursive subquery in the actual outer context to enable resolving correlation
return new RelationPlan(expansion.getRoot(), expansion.getScope(), expansion.getFieldMappings(), outerContext);
}
Query namedQuery = analysis.getNamedQuery(node);
Scope scope = analysis.getScope(node);
RelationPlan plan;
if (namedQuery != null) {
RelationPlan subPlan;
if (analysis.isExpandableQuery(namedQuery)) {
subPlan = new QueryPlanner(analysis, symbolAllocator, idAllocator, lambdaDeclarationToSymbolMap, plannerContext, outerContext, session, recursiveSubqueries).planExpand(namedQuery);
} else {
subPlan = process(namedQuery, null);
}
// Add implicit coercions if view query produces types that don't match the declared output types
// of the view (e.g., if the underlying tables referenced by the view changed)
List<Type> types = analysis.getOutputDescriptor(node).getAllFields().stream().map(Field::getType).collect(toImmutableList());
NodeAndMappings coerced = coerce(subPlan, types, symbolAllocator, idAllocator);
plan = new RelationPlan(coerced.getNode(), scope, coerced.getFields(), outerContext);
} else {
TableHandle handle = analysis.getTableHandle(node);
ImmutableList.Builder<Symbol> outputSymbolsBuilder = ImmutableList.builder();
ImmutableMap.Builder<Symbol, ColumnHandle> columns = ImmutableMap.builder();
for (Field field : scope.getRelationType().getAllFields()) {
Symbol symbol = symbolAllocator.newSymbol(field);
outputSymbolsBuilder.add(symbol);
columns.put(symbol, analysis.getColumn(field));
}
List<Symbol> outputSymbols = outputSymbolsBuilder.build();
boolean updateTarget = analysis.isUpdateTarget(node);
PlanNode root = TableScanNode.newInstance(idAllocator.getNextId(), handle, outputSymbols, columns.buildOrThrow(), updateTarget, Optional.empty());
plan = new RelationPlan(root, scope, outputSymbols, outerContext);
List<Type> types = analysis.getRelationCoercion(node);
if (types != null) {
// apply required coercion and prune invisible fields from child outputs
NodeAndMappings coerced = coerce(plan, types, symbolAllocator, idAllocator);
plan = new RelationPlan(coerced.getNode(), scope, coerced.getFields(), outerContext);
}
}
plan = addRowFilters(node, plan);
plan = addColumnMasks(node, plan);
return plan;
}
Aggregations