use of io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp in project ksql by confluentinc.
the class AggregateExpressionRewriter method visitFunctionCall.
@Override
public Optional<Expression> visitFunctionCall(final FunctionCall node, final ExpressionTreeRewriter.Context<Void> context) {
final FunctionName functionName = node.getName();
if (functionRegistry.isAggregate(functionName)) {
final ColumnName aggVarName = ColumnNames.aggregateColumn(aggVariableIndex);
aggVariableIndex++;
return Optional.of(new UnqualifiedColumnReferenceExp(node.getLocation(), aggVarName));
} else {
final List<Expression> arguments = new ArrayList<>();
for (final Expression argExpression : node.getArguments()) {
arguments.add(context.process(argExpression));
}
return Optional.of(new FunctionCall(node.getLocation(), node.getName(), arguments));
}
}
use of io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp 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);
}
use of io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp in project ksql by confluentinc.
the class LogicalPlanner method verifyForeignKeyJoin.
private Optional<Expression> verifyForeignKeyJoin(final JoinInfo joinInfo, final PlanNode leftNode, final PlanNode rightNode) {
final JoinType joinType = joinInfo.getType();
final Expression leftExpression = joinInfo.getLeftJoinExpression();
final Expression rightExpression = joinInfo.getRightJoinExpression();
if (joinInfo.getType().equals(JoinType.OUTER)) {
throw new KsqlException(String.format("Invalid join type:" + " full-outer join not supported for foreign-key table-table join." + " Got %s %s %s.", joinInfo.getLeftSource().getDataSource().getName().text(), joinType, joinInfo.getRightSource().getDataSource().getName().text()));
}
// because a FK-join output table has the same PK as its left input table
if (!(leftNode instanceof DataSourceNode) || !(rightNode instanceof DataSourceNode)) {
throw new KsqlException(String.format("Invalid join condition:" + " foreign-key table-table joins are not supported as part of n-way joins." + " Got %s = %s.", joinInfo.getFlippedLeftJoinExpression(), joinInfo.getFlippedRightJoinExpression()));
}
final CodeGenRunner codeGenRunner = new CodeGenRunner(leftNode.getSchema(), ksqlConfig, metaStore);
final VisitParentExpressionVisitor<Optional<Expression>, Context<Void>> unqualifiedRewritter = new VisitParentExpressionVisitor<Optional<Expression>, Context<Void>>(Optional.empty()) {
@Override
public Optional<Expression> visitQualifiedColumnReference(final QualifiedColumnReferenceExp node, final Context<Void> ctx) {
return Optional.of(new UnqualifiedColumnReferenceExp(node.getColumnName()));
}
};
final Expression leftExpressionUnqualified = ExpressionTreeRewriter.rewriteWith(unqualifiedRewritter::process, leftExpression);
final ExpressionEvaluator expressionEvaluator = codeGenRunner.buildCodeGenFromParseTree(leftExpressionUnqualified, "Left Join Expression");
final SqlType fkType = expressionEvaluator.getExpressionType();
final SqlType rightKeyType = Iterables.getOnlyElement(rightNode.getSchema().key()).type();
verifyJoinConditionTypes(fkType, rightKeyType, leftExpression, rightExpression, joinInfo.hasFlippedJoinCondition());
if (((DataSourceNode) rightNode).isWindowed()) {
throw new KsqlException("Foreign-key table-table joins are not supported on windowed tables.");
}
return Optional.of(leftExpression);
}
use of io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp in project ksql by confluentinc.
the class LogicalPlanner method prepareSourceForJoin.
private PlanNode prepareSourceForJoin(final DataSourceNode sourceNode, final String side, final Expression joinExpression, final boolean isForeignKeyJoin) {
final PlanNode preProjectNode;
if (isForeignKeyJoin) {
// we do not need to repartition for foreign key joins, as FK joins do not
// have co-partitioning requirements
preProjectNode = sourceNode;
} else {
// it is always safe to build the repartition node - this operation will be
// a no-op if a repartition is not required. if the source is a table, and
// a repartition is needed, then an exception will be thrown
final VisitParentExpressionVisitor<Optional<Expression>, Context<Void>> rewriter = new VisitParentExpressionVisitor<Optional<Expression>, Context<Void>>(Optional.empty()) {
@Override
public Optional<Expression> visitQualifiedColumnReference(final QualifiedColumnReferenceExp node, final Context<Void> ctx) {
return Optional.of(new UnqualifiedColumnReferenceExp(node.getColumnName()));
}
};
preProjectNode = buildInternalRepartitionNode(sourceNode, side, joinExpression, rewriter::process);
}
return buildInternalProjectNode(preProjectNode, "PrependAlias" + side, sourceNode.getAlias());
}
use of io.confluent.ksql.execution.expression.tree.UnqualifiedColumnReferenceExp in project ksql by confluentinc.
the class LogicalPlanner method buildForeignJoinKey.
private JoinKey buildForeignJoinKey(final Join join, final Expression foreignKeyExpression) {
final AliasedDataSource leftSource = join.getInfo().getLeftSource();
final SourceName alias = leftSource.getAlias();
final List<QualifiedColumnReferenceExp> leftSourceKeys = leftSource.getDataSource().getSchema().key().stream().map(c -> new QualifiedColumnReferenceExp(alias, c.name())).collect(Collectors.toList());
final VisitParentExpressionVisitor<Optional<Expression>, Context<Void>> aliasRewritter = new VisitParentExpressionVisitor<Optional<Expression>, Context<Void>>(Optional.empty()) {
@Override
public Optional<Expression> visitQualifiedColumnReference(final QualifiedColumnReferenceExp node, final Context<Void> ctx) {
return Optional.of(new UnqualifiedColumnReferenceExp(ColumnNames.generatedJoinColumnAlias(node.getQualifier(), node.getColumnName())));
}
};
final Expression aliasedForeignKeyExpression = ExpressionTreeRewriter.rewriteWith(aliasRewritter::process, foreignKeyExpression);
return JoinKey.foreignKey(aliasedForeignKeyExpression, leftSourceKeys);
}
Aggregations