Search in sources :

Example 1 with Projection

use of io.confluent.ksql.planner.Projection in project ksql by confluentinc.

the class FinalProjectNode method validateProjection.

/**
 * Called to validate that columns referenced in the projection are valid.
 *
 * <p>This is necessary as some joins can create synthetic key columns that do not come
 * from any data source.  This means the normal column validation done during analysis can not
 * fail on unknown column with generated column names.
 *
 * <p>Once the logical model has been built the synthetic key names are known and generated
 * column names can be validated.
 */
private void validateProjection() {
    // Validate any column in the projection that might be a synthetic
    // Only really need to include any that might be, but we include all:
    final RequiredColumns requiredColumns = RequiredColumns.builder().addAll(projection.singleExpressions()).build();
    final Set<ColumnReferenceExp> unknown = getSource().validateColumns(requiredColumns);
    if (!unknown.isEmpty()) {
        final String errors = unknown.stream().map(columnRef -> NodeLocation.asPrefix(columnRef.getLocation()) + "Column '" + columnRef + "' cannot be resolved.").collect(Collectors.joining(System.lineSeparator()));
        throw new KsqlException(errors);
    }
}
Also used : DataSource(io.confluent.ksql.metastore.model.DataSource) ColumnName(io.confluent.ksql.name.ColumnName) SourceName(io.confluent.ksql.name.SourceName) GrammaticalJoiner(io.confluent.ksql.util.GrammaticalJoiner) UnqualifiedColumnReferenceExp(io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp) Name(io.confluent.ksql.name.Name) HashMap(java.util.HashMap) SelectItem(io.confluent.ksql.parser.tree.SelectItem) HashSet(java.util.HashSet) AsValue(io.confluent.ksql.function.udf.AsValue) Pair(io.confluent.ksql.util.Pair) ImmutableList(com.google.common.collect.ImmutableList) Analysis(io.confluent.ksql.analyzer.Analysis) Map(java.util.Map) MetaStore(io.confluent.ksql.metastore.MetaStore) Projection(io.confluent.ksql.planner.Projection) ColumnReferenceExp(io.confluent.ksql.execution.expression.tree.ColumnReferenceExp) RequiredColumns(io.confluent.ksql.planner.RequiredColumns) SystemColumns(io.confluent.ksql.schema.ksql.SystemColumns) Set(java.util.Set) KsqlConfig(io.confluent.ksql.util.KsqlConfig) LogicalSchema(io.confluent.ksql.schema.ksql.LogicalSchema) Collectors(java.util.stream.Collectors) SelectExpression(io.confluent.ksql.execution.plan.SelectExpression) Builder(io.confluent.ksql.schema.ksql.LogicalSchema.Builder) NodeLocation(io.confluent.ksql.parser.NodeLocation) List(java.util.List) Entry(java.util.Map.Entry) KsqlException(io.confluent.ksql.util.KsqlException) Optional(java.util.Optional) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings) UnqualifiedColumnReferenceExp(io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp) ColumnReferenceExp(io.confluent.ksql.execution.expression.tree.ColumnReferenceExp) RequiredColumns(io.confluent.ksql.planner.RequiredColumns) KsqlException(io.confluent.ksql.util.KsqlException)

Example 2 with Projection

use of io.confluent.ksql.planner.Projection in project ksql by confluentinc.

the class FinalProjectNode method build.

private Pair<LogicalSchema, List<SelectExpression>> build(final MetaStore metaStore, final KsqlConfig ksqlConfig) {
    final LogicalSchema parentSchema = getSource().getSchema();
    final Optional<LogicalSchema> targetSchema = getTargetSchema(metaStore);
    final List<SelectExpression> selectExpressions = SelectionUtil.buildSelectExpressions(getSource(), projection.selectItems(), targetSchema);
    final LogicalSchema schema = SelectionUtil.buildProjectionSchema(parentSchema, selectExpressions, metaStore);
    if (into.isPresent()) {
        // Persistent queries have key columns as value columns - final projection can exclude them:
        final Map<ColumnName, Set<ColumnName>> seenKeyColumns = new HashMap<>();
        selectExpressions.removeIf(se -> {
            if (se.getExpression() instanceof UnqualifiedColumnReferenceExp) {
                final ColumnName columnName = ((UnqualifiedColumnReferenceExp) se.getExpression()).getColumnName();
                // Window bounds columns are currently removed if not aliased:
                if (SystemColumns.isWindowBound(columnName) && se.getAlias().equals(columnName)) {
                    return true;
                }
                if (parentSchema.isKeyColumn(columnName)) {
                    seenKeyColumns.computeIfAbsent(columnName, k -> new HashSet<>()).add(se.getAlias());
                    return true;
                }
            }
            return false;
        });
        for (final Entry<ColumnName, Set<ColumnName>> seenKey : seenKeyColumns.entrySet()) {
            if (seenKey.getValue().size() > 1) {
                final String keys = GrammaticalJoiner.and().join(seenKey.getValue().stream().map(Name::text).sorted());
                throw new KsqlException("The projection contains a key column (" + seenKey.getKey() + ") more than once, aliased as: " + keys + "." + System.lineSeparator() + "Each key column must only be in the projection once. " + "If you intended to copy the key into the value, then consider using the " + AsValue.NAME + " function to indicate which key reference should be copied.");
            }
        }
    }
    final LogicalSchema nodeSchema;
    if (into.isPresent()) {
        nodeSchema = schema.withoutPseudoAndKeyColsInValue(ksqlConfig);
    } else {
        // Transient queries return key columns in the value, so the projection includes them, and
        // the schema needs to include them too:
        final Builder builder = LogicalSchema.builder();
        builder.keyColumns(parentSchema.key());
        schema.columns().forEach(builder::valueColumn);
        nodeSchema = builder.build();
    }
    return Pair.of(nodeSchema, selectExpressions);
}
Also used : DataSource(io.confluent.ksql.metastore.model.DataSource) ColumnName(io.confluent.ksql.name.ColumnName) SourceName(io.confluent.ksql.name.SourceName) GrammaticalJoiner(io.confluent.ksql.util.GrammaticalJoiner) UnqualifiedColumnReferenceExp(io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp) Name(io.confluent.ksql.name.Name) HashMap(java.util.HashMap) SelectItem(io.confluent.ksql.parser.tree.SelectItem) HashSet(java.util.HashSet) AsValue(io.confluent.ksql.function.udf.AsValue) Pair(io.confluent.ksql.util.Pair) ImmutableList(com.google.common.collect.ImmutableList) Analysis(io.confluent.ksql.analyzer.Analysis) Map(java.util.Map) MetaStore(io.confluent.ksql.metastore.MetaStore) Projection(io.confluent.ksql.planner.Projection) ColumnReferenceExp(io.confluent.ksql.execution.expression.tree.ColumnReferenceExp) RequiredColumns(io.confluent.ksql.planner.RequiredColumns) SystemColumns(io.confluent.ksql.schema.ksql.SystemColumns) Set(java.util.Set) KsqlConfig(io.confluent.ksql.util.KsqlConfig) LogicalSchema(io.confluent.ksql.schema.ksql.LogicalSchema) Collectors(java.util.stream.Collectors) SelectExpression(io.confluent.ksql.execution.plan.SelectExpression) Builder(io.confluent.ksql.schema.ksql.LogicalSchema.Builder) NodeLocation(io.confluent.ksql.parser.NodeLocation) List(java.util.List) Entry(java.util.Map.Entry) KsqlException(io.confluent.ksql.util.KsqlException) Optional(java.util.Optional) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings) HashSet(java.util.HashSet) Set(java.util.Set) HashMap(java.util.HashMap) Builder(io.confluent.ksql.schema.ksql.LogicalSchema.Builder) LogicalSchema(io.confluent.ksql.schema.ksql.LogicalSchema) SelectExpression(io.confluent.ksql.execution.plan.SelectExpression) KsqlException(io.confluent.ksql.util.KsqlException) UnqualifiedColumnReferenceExp(io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp) ColumnName(io.confluent.ksql.name.ColumnName) SourceName(io.confluent.ksql.name.SourceName) Name(io.confluent.ksql.name.Name) ColumnName(io.confluent.ksql.name.ColumnName) HashSet(java.util.HashSet)

Example 3 with Projection

use of io.confluent.ksql.planner.Projection in project ksql by confluentinc.

the class JoinNode method validateKeyPresent.

@Override
void validateKeyPresent(final SourceName sinkName, final Projection projection) {
    if (joinKey.isForeignKey()) {
        final DataSourceNode leftInputTable = getLeftmostSourceNode();
        final SourceName leftInputTableName = leftInputTable.getAlias();
        final List<Column> leftInputTableKeys = leftInputTable.getDataSource().getSchema().key();
        final List<Column> missingKeys = leftInputTableKeys.stream().filter(k -> !projection.containsExpression(new QualifiedColumnReferenceExp(leftInputTableName, k.name())) && !projection.containsExpression(new UnqualifiedColumnReferenceExp(ColumnNames.generatedJoinColumnAlias(leftInputTableName, k.name())))).collect(Collectors.toList());
        if (!missingKeys.isEmpty()) {
            throwMissingKeyColumnForFkJoinException(missingKeys, leftInputTableName);
        }
    } else {
        final boolean atLeastOneKey = joinKey.getAllViableKeys(schema).stream().anyMatch(projection::containsExpression);
        if (!atLeastOneKey) {
            final boolean synthetic = joinKey.isSynthetic();
            final List<? extends Expression> viable = joinKey.getOriginalViableKeys(schema);
            throwKeysNotIncludedError(sinkName, "join expression", viable, false, synthetic);
        }
    }
}
Also used : DataSource(io.confluent.ksql.metastore.model.DataSource) Arrays(java.util.Arrays) ColumnName(io.confluent.ksql.name.ColumnName) SourceName(io.confluent.ksql.name.SourceName) WithinExpression(io.confluent.ksql.parser.tree.WithinExpression) BiFunction(java.util.function.BiFunction) Pair(io.confluent.ksql.util.Pair) Immutable(com.google.errorprone.annotations.Immutable) Map(java.util.Map) ColumnReferenceExp(io.confluent.ksql.execution.expression.tree.ColumnReferenceExp) ColumnNames(io.confluent.ksql.schema.ksql.ColumnNames) ImmutableMap(com.google.common.collect.ImmutableMap) Expression(io.confluent.ksql.execution.expression.tree.Expression) Collection(java.util.Collection) Set(java.util.Set) ConsumerConfig(org.apache.kafka.clients.consumer.ConsumerConfig) Streams(com.google.common.collect.Streams) LogicalSchema(io.confluent.ksql.schema.ksql.LogicalSchema) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) List(java.util.List) Stream(java.util.stream.Stream) KsqlException(io.confluent.ksql.util.KsqlException) Optional(java.util.Optional) Column(io.confluent.ksql.schema.ksql.Column) FormatInfo(io.confluent.ksql.serde.FormatInfo) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings) SchemaKStream(io.confluent.ksql.structured.SchemaKStream) SchemaKTable(io.confluent.ksql.structured.SchemaKTable) KeyFormat(io.confluent.ksql.serde.KeyFormat) QueryContext(io.confluent.ksql.execution.context.QueryContext) UnqualifiedColumnReferenceExp(io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp) DataSourceType(io.confluent.ksql.metastore.model.DataSource.DataSourceType) KafkaTopicClient(io.confluent.ksql.services.KafkaTopicClient) Supplier(java.util.function.Supplier) NoneFormat(io.confluent.ksql.serde.none.NoneFormat) ImmutableList(com.google.common.collect.ImmutableList) ForeignKeyJoinParamsFactory(io.confluent.ksql.execution.streams.ForeignKeyJoinParamsFactory) Objects.requireNonNull(java.util.Objects.requireNonNull) QualifiedColumnReferenceExp(io.confluent.ksql.execution.expression.tree.QualifiedColumnReferenceExp) Projection(io.confluent.ksql.planner.Projection) SerdeFeatures(io.confluent.ksql.serde.SerdeFeatures) RequiredColumns(io.confluent.ksql.planner.RequiredColumns) JoinParamsFactory(io.confluent.ksql.execution.streams.JoinParamsFactory) Iterables.getOnlyElement(com.google.common.collect.Iterables.getOnlyElement) KsqlTopic(io.confluent.ksql.execution.ddl.commands.KsqlTopic) Context(io.confluent.ksql.engine.rewrite.ExpressionTreeRewriter.Context) ExpressionTreeRewriter(io.confluent.ksql.engine.rewrite.ExpressionTreeRewriter) Collections(java.util.Collections) Column(io.confluent.ksql.schema.ksql.Column) QualifiedColumnReferenceExp(io.confluent.ksql.execution.expression.tree.QualifiedColumnReferenceExp) SourceName(io.confluent.ksql.name.SourceName) UnqualifiedColumnReferenceExp(io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp)

Example 4 with Projection

use of io.confluent.ksql.planner.Projection in project ksql by confluentinc.

the class QueryProjectNode method buildOutputSchema.

/**
 * Builds the output schema of the project node.
 * The output schema comprises of exactly the columns that appear in the SELECT clause of the
 * query.
 * @param metaStore the metastore
 * @return the project node's output schema
 */
private LogicalSchema buildOutputSchema(final MetaStore metaStore) {
    final LogicalSchema outputSchema;
    final LogicalSchema parentSchema = getSource().getSchema();
    final boolean isWindowed = analysis.getFrom().getDataSource().getKsqlTopic().getKeyFormat().isWindowed();
    if (isSelectStar()) {
        outputSchema = buildPullQuerySelectStarSchema(parentSchema.withoutPseudoAndKeyColsInValue(ksqlConfig), isWindowed);
    } else {
        final List<SelectExpression> projects = projection.selectItems().stream().map(SingleColumn.class::cast).map(si -> SelectExpression.of(si.getAlias().orElseThrow(IllegalStateException::new), si.getExpression())).collect(Collectors.toList());
        outputSchema = selectOutputSchema(metaStore, projects, isWindowed);
    }
    if (isScalablePush) {
        // Transient queries return key columns in the value, so the projection includes them, and
        // the schema needs to include them too:
        final Builder builder = LogicalSchema.builder();
        outputSchema.columns().forEach(builder::valueColumn);
        return builder.build();
    }
    return outputSchema;
}
Also used : CodeGenRunner(io.confluent.ksql.execution.codegen.CodeGenRunner) SelectItem(io.confluent.ksql.parser.tree.SelectItem) RewrittenAnalysis(io.confluent.ksql.analyzer.RewrittenAnalysis) SingleColumn(io.confluent.ksql.parser.tree.SingleColumn) ImmutableList(com.google.common.collect.ImmutableList) ExpressionTypeManager(io.confluent.ksql.execution.util.ExpressionTypeManager) MetaStore(io.confluent.ksql.metastore.MetaStore) Projection(io.confluent.ksql.planner.Projection) AllColumns(io.confluent.ksql.parser.tree.AllColumns) SqlType(io.confluent.ksql.schema.ksql.types.SqlType) InterpretedExpressionFactory(io.confluent.ksql.execution.interpreter.InterpretedExpressionFactory) SystemColumns(io.confluent.ksql.schema.ksql.SystemColumns) ExpressionEvaluator(io.confluent.ksql.execution.transform.ExpressionEvaluator) Expression(io.confluent.ksql.execution.expression.tree.Expression) KsqlConfig(io.confluent.ksql.util.KsqlConfig) LogicalSchema(io.confluent.ksql.schema.ksql.LogicalSchema) Collectors(java.util.stream.Collectors) SelectExpression(io.confluent.ksql.execution.plan.SelectExpression) Builder(io.confluent.ksql.schema.ksql.LogicalSchema.Builder) Objects(java.util.Objects) List(java.util.List) QueryPlannerOptions(io.confluent.ksql.planner.QueryPlannerOptions) KsqlException(io.confluent.ksql.util.KsqlException) Optional(java.util.Optional) SqlTypes(io.confluent.ksql.schema.ksql.types.SqlTypes) SuppressFBWarnings(edu.umd.cs.findbugs.annotations.SuppressFBWarnings) Builder(io.confluent.ksql.schema.ksql.LogicalSchema.Builder) LogicalSchema(io.confluent.ksql.schema.ksql.LogicalSchema) SelectExpression(io.confluent.ksql.execution.plan.SelectExpression) SingleColumn(io.confluent.ksql.parser.tree.SingleColumn)

Aggregations

ImmutableList (com.google.common.collect.ImmutableList)4 SuppressFBWarnings (edu.umd.cs.findbugs.annotations.SuppressFBWarnings)4 Projection (io.confluent.ksql.planner.Projection)4 LogicalSchema (io.confluent.ksql.schema.ksql.LogicalSchema)4 KsqlException (io.confluent.ksql.util.KsqlException)4 List (java.util.List)4 Optional (java.util.Optional)4 Collectors (java.util.stream.Collectors)4 ColumnReferenceExp (io.confluent.ksql.execution.expression.tree.ColumnReferenceExp)3 UnqualifiedColumnReferenceExp (io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp)3 SelectExpression (io.confluent.ksql.execution.plan.SelectExpression)3 MetaStore (io.confluent.ksql.metastore.MetaStore)3 DataSource (io.confluent.ksql.metastore.model.DataSource)3 ColumnName (io.confluent.ksql.name.ColumnName)3 SourceName (io.confluent.ksql.name.SourceName)3 SelectItem (io.confluent.ksql.parser.tree.SelectItem)3 RequiredColumns (io.confluent.ksql.planner.RequiredColumns)3 Builder (io.confluent.ksql.schema.ksql.LogicalSchema.Builder)3 SystemColumns (io.confluent.ksql.schema.ksql.SystemColumns)3 KsqlConfig (io.confluent.ksql.util.KsqlConfig)3