use of io.confluent.ksql.execution.expression.tree.Expression in project ksql by confluentinc.
the class LogicalPlanner method buildJoin.
/**
* @param root the root of the Join Tree
* @param prefix the prefix to uniquely identify the plan node
* @return the PlanNode representing this Join Tree
*/
private JoinNode buildJoin(final Join root, final String prefix, final boolean isWindowed) {
final PlanNode preRepartitionLeft;
if (root.getLeft() instanceof JoinTree.Join) {
preRepartitionLeft = buildJoin((Join) root.getLeft(), prefix + "L_", isWindowed);
} else {
final JoinTree.Leaf leaf = (Leaf) root.getLeft();
preRepartitionLeft = new DataSourceNode(new PlanNodeId("KafkaTopic_" + prefix + "Left"), leaf.getSource().getDataSource(), leaf.getSource().getAlias(), isWindowed, ksqlConfig);
}
final PlanNode preRepartitionRight;
if (root.getRight() instanceof JoinTree.Join) {
preRepartitionRight = buildJoin((Join) root.getRight(), prefix + "R_", isWindowed);
} else {
final JoinTree.Leaf leaf = (Leaf) root.getRight();
preRepartitionRight = new DataSourceNode(new PlanNodeId("KafkaTopic_" + prefix + "Right"), leaf.getSource().getDataSource(), leaf.getSource().getAlias(), isWindowed, ksqlConfig);
}
final Optional<Expression> fkExpression = verifyJoin(root.getInfo(), preRepartitionLeft, preRepartitionRight);
final JoinKey joinKey = fkExpression.map(columnReferenceExp -> buildForeignJoinKey(root, fkExpression.get())).orElseGet(() -> buildJoinKey(root));
final PlanNode left = prepareSourceForJoin(root.getLeft(), preRepartitionLeft, prefix + "Left", root.getInfo().getLeftJoinExpression(), fkExpression.isPresent());
final PlanNode right = prepareSourceForJoin(root.getRight(), preRepartitionRight, prefix + "Right", root.getInfo().getRightJoinExpression(), fkExpression.isPresent());
return new JoinNode(new PlanNodeId(prefix + "Join"), root.getInfo().getType(), joinKey.rewriteWith(refRewriter::process), prefix.isEmpty(), left, right, root.getInfo().getWithinExpression(), ksqlConfig.getString(KsqlConfig.KSQL_DEFAULT_KEY_FORMAT_CONFIG));
}
use of io.confluent.ksql.execution.expression.tree.Expression 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);
}
use of io.confluent.ksql.execution.expression.tree.Expression in project ksql by confluentinc.
the class LogicalPlanner method buildUserRepartitionNode.
private UserRepartitionNode buildUserRepartitionNode(final PlanNode currentNode, final PartitionBy partitionBy) {
final List<Expression> rewrittenPartitionBys = partitionBy.getExpressions().stream().map(exp -> ExpressionTreeRewriter.rewriteWith(refRewriter::process, exp)).collect(Collectors.toList());
final LogicalSchema schema = buildRepartitionedSchema(currentNode, rewrittenPartitionBys);
return new UserRepartitionNode(new PlanNodeId("PartitionBy"), currentNode, schema, partitionBy.getExpressions(), rewrittenPartitionBys, ksqlConfig);
}
use of io.confluent.ksql.execution.expression.tree.Expression in project ksql by confluentinc.
the class LogicalPlanner method verifyJoin.
/**
* @return the foreign key column if this is a foreign key join
*/
private Optional<Expression> verifyJoin(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 (leftNode.getNodeOutputType() == DataSourceType.KSTREAM) {
if (rightNode.getNodeOutputType() == DataSourceType.KTABLE) {
verifyStreamTableJoin(joinInfo, rightNode);
}
// stream-stream join detected: nothing to verify
} else {
if (rightNode.getNodeOutputType() == DataSourceType.KSTREAM) {
throw new KsqlException(String.format("Invalid join order:" + " table-stream joins are not supported; only stream-table joins. Got %s %s %s.", joinInfo.getLeftSource().getDataSource().getName().text(), joinType, joinInfo.getRightSource().getDataSource().getName().text()));
}
if (joinOnNonKeyAttribute(rightExpression, rightNode, joinInfo.getRightSource())) {
throw new KsqlException(String.format("Invalid join condition:" + " table-table joins require to join on the primary key of the right input" + " table. Got %s = %s.", joinInfo.getFlippedLeftJoinExpression(), joinInfo.getFlippedRightJoinExpression()));
}
if (joinOnNonKeyAttribute(leftExpression, leftNode, joinInfo.getLeftSource())) {
return verifyForeignKeyJoin(joinInfo, leftNode, rightNode);
} else {
// primary key join detected
final SqlType leftKeyType = Iterables.getOnlyElement(leftNode.getSchema().key()).type();
final SqlType rightKeyType = Iterables.getOnlyElement(rightNode.getSchema().key()).type();
verifyJoinConditionTypes(leftKeyType, rightKeyType, leftExpression, rightExpression, joinInfo.hasFlippedJoinCondition());
}
}
return Optional.empty();
}
use of io.confluent.ksql.execution.expression.tree.Expression in project ksql by confluentinc.
the class LogicalPlanner method buildQueryLogicalPlan.
public OutputNode buildQueryLogicalPlan(final QueryPlannerOptions queryPlannerOptions, final boolean isScalablePush) {
final boolean isWindowed = analysis.getFrom().getDataSource().getKsqlTopic().getKeyFormat().isWindowed();
PlanNode currentNode = buildSourceNode(isWindowed);
if (analysis.getWhereExpression().isPresent()) {
final Expression whereExpression = analysis.getWhereExpression().get();
final FilterTypeValidator validator = new FilterTypeValidator(currentNode.getSchema(), metaStore, FilterType.WHERE);
validator.validateFilterExpression(whereExpression);
currentNode = new QueryFilterNode(new PlanNodeId("WhereFilter"), currentNode, whereExpression, metaStore, ksqlConfig, isWindowed, queryPlannerOptions);
} else {
if (!queryPlannerOptions.getTableScansEnabled()) {
throw QueryFilterNode.invalidWhereClauseException("Missing WHERE clause", isWindowed);
}
}
if (!isScalablePush && analysis.getLimitClause().isPresent()) {
currentNode = buildLimitNode(currentNode, analysis.getLimitClause().getAsInt());
}
currentNode = new QueryProjectNode(new PlanNodeId("Project"), currentNode, analysis.getSelectItems(), metaStore, ksqlConfig, analysis, isWindowed, queryPlannerOptions, isScalablePush);
return buildOutputNode(currentNode);
}
Aggregations