private boolean hasAggregates(QuerySpecification node) { ImmutableList.Builder<Node> toExtractBuilder = ImmutableList.builder(); toExtractBuilder.addAll(node.getSelect().getSelectItems().stream() .filter(SingleColumn.class::isInstance) .collect(toImmutableList())); toExtractBuilder.addAll(getSortItemsFromOrderBy(node.getOrderBy())); node.getHaving().ifPresent(toExtractBuilder::add); List<FunctionCall> aggregates = extractAggregateFunctions(toExtractBuilder.build(), metadata.getFunctionRegistry()); return !aggregates.isEmpty(); }
@BeforeClass public void setUp() { functionAssertions.getMetadata().addFunctions(ImmutableList.of(APPLY_FUNCTION, INVOKE_FUNCTION)); }
public Set<QualifiedTablePrefix> calculatePrefixesWithTableName( ConnectorSession connectorSession, Set<QualifiedTablePrefix> prefixes, TupleDomain<ColumnHandle> constraint, Optional<Predicate<Map<ColumnHandle, NullableValue>>> predicate) { Session session = ((FullConnectorSession) connectorSession).getSession(); Optional<Set<String>> tables = filterString(constraint, TABLE_NAME_COLUMN_HANDLE); if (tables.isPresent()) { return prefixes.stream() .flatMap(prefix -> tables.get().stream() .filter(this::isLowerCase) .map(table -> table.toLowerCase(ENGLISH)) .map(table -> new QualifiedObjectName(catalogName, prefix.getSchemaName().get(), table))) .filter(objectName -> metadata.getTableHandle(session, objectName).isPresent() || metadata.getView(session, objectName).isPresent()) .map(QualifiedObjectName::asQualifiedTablePrefix) .collect(toImmutableSet()); } return prefixes.stream() .flatMap(prefix -> Stream.concat( metadata.listTables(session, prefix).stream(), metadata.listViews(session, prefix).stream())) .filter(objectName -> !predicate.isPresent() || predicate.get().test(asFixedValues(objectName))) .map(QualifiedObjectName::asQualifiedTablePrefix) .collect(toImmutableSet()); }
public static ExpressionAnalyzer createConstantAnalyzer(Metadata metadata, Session session, List<Expression> parameters, WarningCollector warningCollector, boolean isDescribe) { return createWithoutSubqueries( metadata.getFunctionRegistry(), metadata.getTypeManager(), session, parameters, EXPRESSION_NOT_CONSTANT, "Constant expression cannot contain a subquery", warningCollector, isDescribe); }
protected final List<Type> getColumnTypes(String tableName, String... columnNames) { checkState(session.getCatalog().isPresent(), "catalog not set"); checkState(session.getSchema().isPresent(), "schema not set"); // look up the table Metadata metadata = localQueryRunner.getMetadata(); QualifiedObjectName qualifiedTableName = new QualifiedObjectName(session.getCatalog().get(), session.getSchema().get(), tableName); TableHandle tableHandle = metadata.getTableHandle(session, qualifiedTableName) .orElseThrow(() -> new IllegalArgumentException(format("Table %s does not exist", qualifiedTableName))); Map<String, ColumnHandle> allColumnHandles = metadata.getColumnHandles(session, tableHandle); return Arrays.stream(columnNames) .map(allColumnHandles::get) .map(columnHandle -> metadata.getColumnMetadata(session, tableHandle, columnHandle).getType()) .collect(toImmutableList()); }
@Override public Void visitTableScan(TableScanNode node, Void context) { TableHandle tableHandle = node.getTable(); Set<Column> columns = new HashSet<>(); for (ColumnHandle columnHandle : node.getAssignments().values()) { columns.add(createColumn(metadata.getColumnMetadata(session, tableHandle, columnHandle))); } inputs.add(createInput(metadata.getTableMetadata(session, tableHandle), node.getLayout(), columns)); return null; }
Optional<ViewDefinition> viewDefinition = metadata.getView(session, objectName); if (!viewDefinition.isPresent()) { if (metadata.getTableHandle(session, objectName).isPresent()) { throw new SemanticException(NOT_SUPPORTED, node, "Relation '%s' is a table, not a view", objectName); Query query = parseView(viewDefinition.get().getOriginalSql(), objectName, node); String sql = formatSql(new CreateView(createQualifiedName(objectName), query, false), Optional.of(parameters)).trim(); return singleValueQuery("Create View", sql); Optional<TableHandle> tableHandle = metadata.getTableHandle(session, objectName); if (!tableHandle.isPresent()) { throw new SemanticException(MISSING_TABLE, node, "Table '%s' does not exist", objectName); ConnectorTableMetadata connectorTableMetadata = metadata.getTableMetadata(session, tableHandle.get()).getMetadata(); Map<String, PropertyMetadata<?>> allColumnProperties = metadata.getColumnPropertyManager().getAllProperties().get(tableHandle.get().getConnectorId()); Map<String, PropertyMetadata<?>> allTableProperties = metadata.getTablePropertyManager().getAllProperties().get(tableHandle.get().getConnectorId()); List<Property> propertyNodes = buildProperties(objectName, Optional.empty(), INVALID_TABLE_PROPERTY, properties, allTableProperties); QualifiedName.of(objectName.getCatalogName(), objectName.getSchemaName(), objectName.getObjectName()), columns, false,
private static KdbTree loadKdbTree(String tableName, Session session, Metadata metadata, SplitManager splitManager, PageSourceManager pageSourceManager) QualifiedObjectName name = toQualifiedObjectName(tableName, session.getCatalog().get(), session.getSchema().get()); TableHandle tableHandle = metadata.getTableHandle(session, name) .orElseThrow(() -> new PrestoException(INVALID_SPATIAL_PARTITIONING, format("Table not found: %s", name))); Map<String, ColumnHandle> columnHandles = metadata.getColumnHandles(session, tableHandle); List<ColumnHandle> visibleColumnHandles = columnHandles.values().stream() .filter(handle -> !metadata.getColumnMetadata(session, tableHandle, handle).isHidden()) .collect(toImmutableList()); checkSpatialPartitioningTable(visibleColumnHandles.size() == 1, "Expected single column for table %s, but found %s columns", name, columnHandles.size()); List<TableLayoutResult> layouts = metadata.getLayouts(session, tableHandle, Constraint.alwaysTrue(), Optional.of(ImmutableSet.of(kdbTreeColumn))); checkSpatialPartitioningTable(!layouts.isEmpty(), "Table is empty: %s", name); try (ConnectorPageSource pageSource = pageSourceManager.createPageSource(session, split, ImmutableList.of(kdbTreeColumn))) { do { getFutureValue(pageSource.isBlocked());
if (metadata.getView(session, targetTable).isPresent()) { throw new SemanticException(NOT_SUPPORTED, insert, "Inserting into views is not supported"); Optional<TableHandle> targetTableHandle = metadata.getTableHandle(session, targetTable); if (!targetTableHandle.isPresent()) { throw new SemanticException(MISSING_TABLE, insert, "Table '%s' does not exist", targetTable); accessControl.checkCanInsertIntoTable(session.getRequiredTransactionId(), session.getIdentity(), targetTable); TableMetadata tableMetadata = metadata.getTableMetadata(session, targetTableHandle.get()); List<String> tableColumns = tableMetadata.getColumns().stream() .filter(column -> !column.isHidden()) .map(ColumnMetadata::getName) .collect(toImmutableList()); .map(Identifier::getValue) .map(column -> column.toLowerCase(ENGLISH)) .collect(toImmutableList()); Map<String, ColumnHandle> columnHandles = metadata.getColumnHandles(session, targetTableHandle.get()); analysis.setInsert(new Analysis.Insert( targetTableHandle.get(), insertColumns.stream().map(columnHandles::get).collect(toImmutableList())));
@Override public ListenableFuture<?> execute(Grant statement, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, QueryStateMachine stateMachine, List<Expression> parameters) { Session session = stateMachine.getSession(); QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getTableName()); Optional<TableHandle> tableHandle = metadata.getTableHandle(session, tableName); if (!tableHandle.isPresent()) { throw new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName); } Set<Privilege> privileges; if (statement.getPrivileges().isPresent()) { privileges = statement.getPrivileges().get().stream() .map(privilege -> parsePrivilege(statement, privilege)) .collect(toImmutableSet()); } else { // All privileges privileges = EnumSet.allOf(Privilege.class); } // verify current identity has permissions to grant permissions for (Privilege privilege : privileges) { accessControl.checkCanGrantTablePrivilege(session.getRequiredTransactionId(), session.getIdentity(), privilege, tableName, statement.getGrantee().getValue(), statement.isWithGrantOption()); } metadata.grantTablePrivileges(session, tableName, privileges, statement.getGrantee().getValue(), statement.isWithGrantOption()); return immediateFuture(null); }
@Override public PlanNode visitWindow(WindowNode node, RewriteContext<Context> context) { if (!node.getWindowFunctions().values().stream() .map(function -> function.getFunctionCall().getName()) .allMatch(metadata.getFunctionRegistry()::isAggregationFunction)) { return node; } // Don't need this restriction if we can prove that all order by symbols are deterministically produced if (node.getOrderingScheme().isPresent()) { return node; } // Only RANGE frame type currently supported for aggregation functions because it guarantees the // same value for each peer group. // ROWS frame type requires the ordering to be fully deterministic (e.g. deterministically sorted on all columns) if (node.getFrames().stream().map(WindowNode.Frame::getType).anyMatch(type -> type != WindowFrame.Type.RANGE)) { // TODO: extract frames of type RANGE and allow optimization on them return node; } // Lookup symbols can only be passed through if they are part of the partitioning Set<Symbol> partitionByLookupSymbols = context.get().getLookupSymbols().stream() .filter(node.getPartitionBy()::contains) .collect(toImmutableSet()); if (partitionByLookupSymbols.isEmpty()) { return node; } return context.defaultRewrite(node, new Context(partitionByLookupSymbols, context.get().getSuccess())); }
Optional<TableHandle> tableHandle = metadata.getTableHandle(session, tableName); if (tableHandle.isPresent()) { if (!statement.isNotExists()) { throw new SemanticException(TABLE_ALREADY_EXISTS, statement, "Table '%s' already exists", tableName); ConnectorId connectorId = metadata.getCatalogHandle(session, tableName.getCatalogName()) .orElseThrow(() -> new PrestoException(NOT_FOUND, "Catalog does not exist: " + tableName.getCatalogName())); Type type; try { type = metadata.getType(parseTypeSignature(column.getType())); Map<String, Object> columnProperties = metadata.getColumnPropertyManager().getProperties( connectorId, tableName.getCatalogName(), sqlProperties, session, if (!metadata.getCatalogHandle(session, likeTableName.getCatalogName()).isPresent()) { TableHandle likeTable = metadata.getTableHandle(session, likeTableName) TableMetadata likeTableMetadata = metadata.getTableMetadata(session, likeTable); Map<String, Object> properties = metadata.getTablePropertyManager().getProperties( ConnectorTableMetadata tableMetadata = new ConnectorTableMetadata(tableName.asSchemaTableName(), ImmutableList.copyOf(columns.values()), finalProperties, statement.getComment()); try { metadata.createTable(session, tableName.getCatalogName(), tableMetadata, statement.isNotExists());
List<TableLayoutResult> layouts = metadata.getLayouts( session, node.getTable(), constraint, Optional.of(node.getOutputSymbols().stream() .map(node.getAssignments()::get) .collect(toImmutableSet()))); return ImmutableList.of(new ValuesNode(idAllocator.getNextId(), node.getOutputSymbols(), ImmutableList.of())); .filter(layout -> layout.hasAllOutputs(node)) .collect(toList()); checkState(!layouts.isEmpty(), "No usable layouts for %s", node); if (layouts.stream().anyMatch(layout -> layout.getLayout().getPredicate().isNone())) { return ImmutableList.of(new ValuesNode(idAllocator.getNextId(), node.getOutputSymbols(), ImmutableList.of())); node.getOutputSymbols(), node.getAssignments(), Optional.of(layout.getLayout().getHandle()), layout.getLayout().getPredicate(), computeEnforced(newDomain, layout.getUnenforcedConstraint()));
private RelationPlan createInsertPlan(Analysis analysis, Insert insertStatement) Analysis.Insert insert = analysis.getInsert().get(); TableMetadata tableMetadata = metadata.getTableMetadata(session, insert.getTarget()); .filter(column -> !column.isHidden()) .collect(toImmutableList()); List<String> visibleTableColumnNames = visibleTableColumns.stream() .map(ColumnMetadata::getName) .collect(toImmutableList()); Map<String, ColumnHandle> columns = metadata.getColumnHandles(session, insert.getTarget()); Assignments.Builder assignments = Assignments.builder(); for (ColumnMetadata column : tableMetadata.getColumns()) { Type queryType = symbolAllocator.getTypes().get(input); if (queryType.equals(tableType) || metadata.getTypeManager().isTypeOnlyCoercion(queryType, tableType)) { assignments.put(output, input.toSymbolReference()); .map(column -> Field.newUnqualified(column.getName(), column.getType())) .collect(toImmutableList()); Scope scope = Scope.builder().withRelationType(RelationId.anonymous(), new RelationType(fields)).build(); Optional<NewTableLayout> newTableLayout = metadata.getInsertLayout(session, insert.getTarget()); String catalogName = insert.getTarget().getConnectorId().getCatalogName(); TableStatisticsMetadata statisticsMetadata = metadata.getStatisticsCollectionMetadata(session, catalogName, tableMetadata.getMetadata());
implements Rule<JoinNode> private static final Pattern<JoinNode> PATTERN = join().matching(node -> node.getCriteria().isEmpty() && node.getFilter().isPresent() && node.getType() == LEFT);
.map(columnToSymbolMap::get) .collect(toImmutableList()); ImmutableMap.Builder<Symbol, AggregationNode.Aggregation> aggregations = ImmutableMap.builder(); FunctionRegistry functionRegistry = metadata.getFunctionRegistry(); for (TableStatisticType type : statisticsMetadata.getTableStatistics()) { if (type != ROW_COUNT) { new FunctionCall(count, ImmutableList.of()), functionRegistry.resolveFunction(count, ImmutableList.of()), Optional.empty()); Symbol symbol = symbolAllocator.newSymbol("rowCount", BIGINT); aggregations.put(symbol, aggregation);
protected final OperatorFactory createTableScanOperator(int operatorId, PlanNodeId planNodeId, String tableName, String... columnNames) checkArgument(session.getCatalog().isPresent(), "catalog not set"); checkArgument(session.getSchema().isPresent(), "schema not set"); QualifiedObjectName qualifiedTableName = new QualifiedObjectName(session.getCatalog().get(), session.getSchema().get(), tableName); TableHandle tableHandle = metadata.getTableHandle(session, qualifiedTableName).orElse(null); checkArgument(tableHandle != null, "Table %s does not exist", qualifiedTableName); Map<String, ColumnHandle> allColumnHandles = metadata.getColumnHandles(session, tableHandle); ImmutableList.Builder<ColumnHandle> columnHandlesBuilder = ImmutableList.builder(); for (String columnName : columnNames) { ColumnHandle columnHandle = allColumnHandles.get(columnName); List<TableLayoutResult> layouts = metadata.getLayouts(session, tableHandle, Constraint.alwaysTrue(), Optional.empty()); Split split = getLocalQuerySplit(session, layouts.get(0).getLayout().getHandle());
@Override public PhysicalOperation visitIndexSource(IndexSourceNode node, LocalExecutionPlanContext context) checkState(context.getIndexSourceContext().isPresent(), "Must be in an index source context"); IndexSourceContext indexSourceContext = context.getIndexSourceContext().get(); List<Symbol> lookupSymbolSchema = ImmutableList.copyOf(node.getLookupSymbols()); ImmutableList.Builder<Integer> remappedProbeKeyChannelsBuilder = ImmutableList.builder(); ImmutableList.Builder<Set<Integer>> overlappingFieldSetsBuilder = ImmutableList.builder(); for (Symbol lookupSymbol : lookupSymbolSchema) { Set<Integer> potentialProbeInputs = indexLookupToProbeInput.get(lookupSymbol); checkState(!potentialProbeInputs.isEmpty(), "Must have at least one source from the probe input"); if (potentialProbeInputs.size() > 1) { overlappingFieldSetsBuilder.add(potentialProbeInputs.stream().collect(toImmutableSet())); Function<RecordSet, RecordSet> probeKeyNormalizer = recordSet -> { if (!overlappingFieldSets.isEmpty()) { recordSet = new FieldSetFilteringRecordSet(metadata.getFunctionRegistry(), recordSet, overlappingFieldSets);
private List<FunctionCall> analyzeAggregations( QuerySpecification node, Scope sourceScope, Optional<Scope> orderByScope, List<Expression> groupByExpressions, List<Expression> outputExpressions, List<Expression> orderByExpressions) { checkState(orderByExpressions.isEmpty() || orderByScope.isPresent(), "non-empty orderByExpressions list without orderByScope provided"); List<FunctionCall> aggregates = extractAggregateFunctions(Iterables.concat(outputExpressions, orderByExpressions), metadata.getFunctionRegistry()); analysis.setAggregates(node, aggregates); if (analysis.isAggregation(node)) { // ensure SELECT, ORDER BY and HAVING are constant with respect to group // e.g, these are all valid expressions: // SELECT f(a) GROUP BY a // SELECT f(a + 1) GROUP BY a + 1 // SELECT a + sum(b) GROUP BY a List<Expression> distinctGroupingColumns = groupByExpressions.stream() .distinct() .collect(toImmutableList()); for (Expression expression : outputExpressions) { verifySourceAggregations(distinctGroupingColumns, sourceScope, expression, metadata, analysis); } for (Expression expression : orderByExpressions) { verifyOrderByAggregations(distinctGroupingColumns, sourceScope, orderByScope.get(), expression, metadata, analysis); } } return aggregates; }
private Object getHiveTableProperty(String tableName, Function<HiveTableLayoutHandle, Object> propertyGetter) { Session session = getSession(); Metadata metadata = ((DistributedQueryRunner) getQueryRunner()).getCoordinator().getMetadata(); return transaction(getQueryRunner().getTransactionManager(), getQueryRunner().getAccessControl()) .readOnly() .execute(session, transactionSession -> { Optional<TableHandle> tableHandle = metadata.getTableHandle(transactionSession, new QualifiedObjectName(catalog, TPCH_SCHEMA, tableName)); assertTrue(tableHandle.isPresent()); List<TableLayoutResult> layouts = metadata.getLayouts(transactionSession, tableHandle.get(), Constraint.alwaysTrue(), Optional.empty()); TableLayout layout = getOnlyElement(layouts).getLayout(); return propertyGetter.apply((HiveTableLayoutHandle) layout.getHandle().getConnectorHandle()); }); }