use of io.confluent.ksql.execution.transform.ExpressionEvaluator 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.transform.ExpressionEvaluator in project ksql by confluentinc.
the class ExpressionEvaluatorParityTest method runEvaluator.
private void runEvaluator(final GenericRow row, Callable<ExpressionEvaluator> compile, final Object expectedResult, final Optional<EvaluatorError> error) throws Exception {
ExpressionEvaluator expressionEvaluator = null;
try {
expressionEvaluator = compile.call();
} catch (Exception e) {
if (error.isPresent() && error.get().getErrorTime() == ErrorTime.COMPILE_TIME) {
assertThat(e.getMessage(), containsString(error.get().getMessage()));
return;
} else {
throw e;
}
}
Object result = null;
try {
result = expressionEvaluator.evaluate(row, null, processingLogger, () -> "ERROR!!!");
} catch (Exception e) {
if (error.isPresent() && error.get().getErrorTime() == ErrorTime.EVALUATION_TIME) {
assertThat(e.getMessage(), containsString(error.get().getMessage()));
return;
} else {
throw e;
}
}
if (error.isPresent() && error.get().getErrorTime() == ErrorTime.EVALUATION_LOGGER) {
verify(processingLogger, times(1)).error(errorMessageCaptor.capture());
RecordProcessingError processingError = ((RecordProcessingError) errorMessageCaptor.getValue());
if (error.get().getMessage() == null) {
assertThat(processingError.getException().get().getMessage(), nullValue());
} else {
assertThat(processingError.getException().get().getMessage(), containsString(error.get().getMessage()));
}
} else {
verify(processingLogger, never()).error(any());
}
reset(processingLogger);
assertThat(result, is(expectedResult));
}
use of io.confluent.ksql.execution.transform.ExpressionEvaluator in project ksql by confluentinc.
the class ForeignKeyTableTableJoinBuilder method build.
public static <KLeftT, KRightT> KTableHolder<KLeftT> build(final KTableHolder<KLeftT> left, final KTableHolder<KRightT> right, final ForeignKeyTableTableJoin<KLeftT, KRightT> join, final RuntimeBuildContext buildContext) {
final LogicalSchema leftSchema = left.getSchema();
final LogicalSchema rightSchema = right.getSchema();
final ProcessingLogger logger = buildContext.getProcessingLogger(join.getProperties().getQueryContext());
final ExpressionEvaluator expressionEvaluator;
final CodeGenRunner codeGenRunner = new CodeGenRunner(leftSchema, buildContext.getKsqlConfig(), buildContext.getFunctionRegistry());
final Optional<ColumnName> leftColumnName = join.getLeftJoinColumnName();
final Optional<Expression> leftJoinExpression = join.getLeftJoinExpression();
if (leftColumnName.isPresent()) {
expressionEvaluator = codeGenRunner.buildCodeGenFromParseTree(new UnqualifiedColumnReferenceExp(leftColumnName.get()), "Left Join Expression");
} else if (leftJoinExpression.isPresent()) {
expressionEvaluator = codeGenRunner.buildCodeGenFromParseTree(leftJoinExpression.get(), "Left Join Expression");
} else {
throw new IllegalStateException("Both leftColumnName and leftJoinExpression are empty.");
}
final ForeignKeyJoinParams<KRightT> joinParams = ForeignKeyJoinParamsFactory.create(expressionEvaluator, leftSchema, rightSchema, logger);
final Formats formats = join.getFormats();
final PhysicalSchema physicalSchema = PhysicalSchema.from(joinParams.getSchema(), formats.getKeyFeatures(), formats.getValueFeatures());
final Serde<KLeftT> keySerde = left.getExecutionKeyFactory().buildKeySerde(formats.getKeyFormat(), physicalSchema, join.getProperties().getQueryContext());
final Serde<GenericRow> valSerde = buildContext.buildValueSerde(formats.getValueFormat(), physicalSchema, join.getProperties().getQueryContext());
final KTable<KLeftT, GenericRow> result;
switch(join.getJoinType()) {
case INNER:
result = left.getTable().join(right.getTable(), joinParams.getKeyExtractor(), joinParams.getJoiner(), Materialized.with(keySerde, valSerde));
break;
case LEFT:
result = left.getTable().leftJoin(right.getTable(), joinParams.getKeyExtractor(), joinParams.getJoiner(), Materialized.with(keySerde, valSerde));
break;
default:
throw new IllegalStateException("invalid join type: " + join.getJoinType());
}
return KTableHolder.unmaterialized(result, joinParams.getSchema(), left.getExecutionKeyFactory());
}
Aggregations