use of io.confluent.ksql.execution.plan.SelectExpression 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;
}
use of io.confluent.ksql.execution.plan.SelectExpression in project ksql by confluentinc.
the class SchemaKStreamTest method shouldBuildSchemaForSelect.
@Test
public void shouldBuildSchemaForSelect() {
// Given:
final PlanNode logicalPlan = givenInitialKStreamOf("SELECT col0 AS K, col2, col3 FROM test1 WHERE col0 > 100 EMIT CHANGES;");
final ProjectNode projectNode = (ProjectNode) logicalPlan.getSources().get(0);
final List<SelectExpression> selectExpressions = projectNode.getSelectExpressions();
// When:
final SchemaKStream<?> projectedSchemaKStream = initialSchemaKStream.select(ImmutableList.of(ColumnName.of("K")), selectExpressions, childContextStacker, buildContext, internalFormats);
// Then:
assertThat(projectedSchemaKStream.getSchema(), is(schemaResolver.resolve(projectedSchemaKStream.getSourceStep(), initialSchemaKStream.schema)));
}
use of io.confluent.ksql.execution.plan.SelectExpression in project ksql by confluentinc.
the class QueryProjectNode method selectOutputSchema.
private LogicalSchema selectOutputSchema(final MetaStore metaStore, final List<SelectExpression> selectExpressions, final boolean isWindowed) {
final Builder schemaBuilder = LogicalSchema.builder();
final LogicalSchema parentSchema = getSource().getSchema();
// Copy meta & key columns into the value schema as SelectValueMapper expects it:
final LogicalSchema schema = parentSchema.withPseudoAndKeyColsInValue(isWindowed, ksqlConfig);
final ExpressionTypeManager expressionTypeManager = new ExpressionTypeManager(schema, metaStore);
for (final SelectExpression select : selectExpressions) {
final SqlType type = expressionTypeManager.getExpressionSqlType(select.getExpression());
if (parentSchema.isKeyColumn(select.getAlias()) || select.getAlias().equals(SystemColumns.WINDOWSTART_NAME) || select.getAlias().equals(SystemColumns.WINDOWEND_NAME)) {
schemaBuilder.keyColumn(select.getAlias(), type);
} else {
schemaBuilder.valueColumn(select.getAlias(), type);
}
}
return schemaBuilder.build();
}
use of io.confluent.ksql.execution.plan.SelectExpression in project ksql by confluentinc.
the class LogicalPlanner method buildAggregateSchema.
private LogicalSchema buildAggregateSchema(final PlanNode sourcePlanNode, final GroupBy groupBy, final List<SelectExpression> projectionExpressions) {
final LogicalSchema sourceSchema = sourcePlanNode.getSchema();
final LogicalSchema projectionSchema = SelectionUtil.buildProjectionSchema(sourceSchema.withPseudoAndKeyColsInValue(analysis.getWindowExpression().isPresent(), ksqlConfig), projectionExpressions, metaStore);
final List<Expression> groupByExps = groupBy.getGroupingExpressions();
final Function<Expression, Optional<ColumnName>> selectResolver = expression -> {
final List<ColumnName> foundInProjection = projectionExpressions.stream().filter(e -> e.getExpression().equals(expression)).map(SelectExpression::getAlias).collect(Collectors.toList());
switch(foundInProjection.size()) {
case 0:
return Optional.empty();
case 1:
return Optional.of(foundInProjection.get(0));
default:
final String keys = GrammaticalJoiner.and().join(foundInProjection);
throw new KsqlException("The projection contains a key column more than once: " + 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 List<Column> valueColumns;
if (analysis.getInto().isPresent()) {
// Persistent query:
final Set<ColumnName> keyColumnNames = groupBy.getGroupingExpressions().stream().map(selectResolver).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet());
valueColumns = projectionSchema.value().stream().filter(col -> !keyColumnNames.contains(col.name())).collect(Collectors.toList());
if (valueColumns.isEmpty()) {
throw new KsqlException("The projection contains no value columns.");
}
} else {
// Transient query:
// Transient queries only return value columns, so must have key columns in the value:
valueColumns = projectionSchema.columns();
}
final Builder builder = LogicalSchema.builder();
final ExpressionTypeManager typeManager = new ExpressionTypeManager(sourceSchema, metaStore);
for (final Expression expression : groupByExps) {
final SqlType keyType = typeManager.getExpressionSqlType(expression);
final ColumnName keyName = selectResolver.apply(expression).orElseGet(() -> expression instanceof ColumnReferenceExp ? ((ColumnReferenceExp) expression).getColumnName() : ColumnNames.uniqueAliasFor(expression, sourceSchema));
builder.keyColumn(keyName, keyType);
}
return builder.valueColumns(valueColumns).build();
}
use of io.confluent.ksql.execution.plan.SelectExpression in project ksql by confluentinc.
the class LogicalPlanner method buildAggregateNode.
private AggregateNode buildAggregateNode(final PlanNode sourcePlanNode) {
final GroupBy groupBy = analysis.getGroupBy().orElseThrow(IllegalStateException::new);
final List<SelectExpression> projectionExpressions = SelectionUtil.buildSelectExpressions(sourcePlanNode, analysis.getSelectItems(), getTargetSchema());
final RewrittenAggregateAnalysis aggregateAnalysis = new RewrittenAggregateAnalysis(aggregateAnalyzer.analyze(analysis, projectionExpressions), refRewriter::process);
final LogicalSchema schema = buildAggregateSchema(sourcePlanNode, groupBy, projectionExpressions);
if (analysis.getHavingExpression().isPresent()) {
final FilterTypeValidator validator = new FilterTypeValidator(sourcePlanNode.getSchema(), metaStore, FilterType.HAVING);
validator.validateFilterExpression(analysis.getHavingExpression().get());
}
return new AggregateNode(new PlanNodeId("Aggregate"), sourcePlanNode, schema, groupBy, metaStore, analysis, aggregateAnalysis, projectionExpressions, analysis.getInto().isPresent(), ksqlConfig);
}
Aggregations