use of io.confluent.ksql.name.ColumnName in project ksql by confluentinc.
the class TableElements method toLogicalSchema.
/**
* @return the logical schema.
*/
public LogicalSchema toLogicalSchema() {
if (elements.isEmpty()) {
throw new KsqlException("No columns supplied.");
}
final Builder builder = LogicalSchema.builder();
for (final TableElement tableElement : this) {
final ColumnName fieldName = tableElement.getName();
final SqlType fieldType = tableElement.getType().getSqlType();
if (tableElement.getConstraints().isKey() || tableElement.getConstraints().isPrimaryKey()) {
builder.keyColumn(fieldName, fieldType);
} else if (tableElement.getConstraints().isHeaders()) {
builder.headerColumn(fieldName, tableElement.getConstraints().getHeaderKey());
} else {
builder.valueColumn(fieldName, fieldType);
}
}
return builder.build();
}
use of io.confluent.ksql.name.ColumnName in project ksql by confluentinc.
the class LogicalPlanner method joinOnNonKeyAttribute.
private static boolean joinOnNonKeyAttribute(final Expression joinExpression, final PlanNode node, final AliasedDataSource aliasedDataSource) {
if (!(joinExpression instanceof ColumnReferenceExp)) {
return true;
}
final ColumnReferenceExp simpleJoinExpression = (ColumnReferenceExp) joinExpression;
final ColumnName joinAttributeName = simpleJoinExpression.getColumnName();
final List<DataSourceNode> dataSourceNodes = node.getSourceNodes().collect(Collectors.toList());
final List<Column> keyColumns;
// n-way join sub-tree (ie, not a leaf)
if (isInnerNode(node)) {
final DataSourceNode qualifiedNode;
if (simpleJoinExpression.maybeQualifier().isPresent()) {
final SourceName qualifierOrAlias = simpleJoinExpression.maybeQualifier().get();
final SourceName qualifier;
if (aliasedDataSource.getAlias().equals(qualifierOrAlias)) {
qualifier = aliasedDataSource.getDataSource().getName();
} else {
qualifier = qualifierOrAlias;
}
final List<DataSourceNode> allNodes = dataSourceNodes.stream().filter(n -> n.getDataSource().getName().equals(qualifier)).collect(Collectors.toList());
if (allNodes.size() != 1) {
throw new KsqlException(String.format("Join qualifier '%s' could not be resolved (either not found or not unique).", qualifier));
}
qualifiedNode = Iterables.getOnlyElement(allNodes);
} else {
final List<DataSourceNode> allNodes = dataSourceNodes.stream().filter(n -> n.getSchema().findColumn(simpleJoinExpression.getColumnName()).isPresent()).collect(Collectors.toList());
if (allNodes.size() != 1) {
throw new KsqlException(String.format("Join identifier '%s' could not be resolved (either not found or not unique).", joinAttributeName));
}
qualifiedNode = Iterables.getOnlyElement(allNodes);
}
keyColumns = qualifiedNode.getSchema().key();
} else {
// leaf node: we know we have single data source
keyColumns = Iterables.getOnlyElement(dataSourceNodes).getSchema().key();
}
// - thus, if the key has more than one column, the join is not on the key
if (keyColumns.size() > 1) {
return true;
}
return !joinAttributeName.equals(Iterables.getOnlyElement(keyColumns).name());
}
use of io.confluent.ksql.name.ColumnName in project ksql by confluentinc.
the class LogicalPlanner method buildJoinKey.
private JoinKey buildJoinKey(final Join join) {
final List<QualifiedColumnReferenceExp> viableKeyColumns = join.viableKeyColumns();
if (viableKeyColumns.isEmpty()) {
return JoinKey.syntheticColumn();
}
final Projection projection = Projection.of(analysis.original().getSelectItems());
final List<QualifiedColumnReferenceExp> availableKeyColumns = viableKeyColumns.stream().filter(projection::containsExpression).collect(Collectors.toList());
final QualifiedColumnReferenceExp keyColumn = availableKeyColumns.isEmpty() ? // Lack of availability is handle later.
viableKeyColumns.get(0) : availableKeyColumns.get(0);
final ColumnName keyColumnName = ColumnNames.generatedJoinColumnAlias(keyColumn.getQualifier(), keyColumn.getColumnName());
return JoinKey.sourceColumn(keyColumnName, viableKeyColumns);
}
use of io.confluent.ksql.name.ColumnName 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.name.ColumnName in project ksql by confluentinc.
the class JoinNode method resolveSelectStar.
@SuppressWarnings("UnstableApiUsage")
@Override
public Stream<ColumnName> resolveSelectStar(final Optional<SourceName> sourceName) {
final Stream<ColumnName> names = Stream.of(left, right).flatMap(JoinNode::getPreJoinProjectDataSources).filter(s -> !sourceName.isPresent() || sourceName.equals(s.getSourceName())).flatMap(s -> s.resolveSelectStar(sourceName));
if (sourceName.isPresent() || !joinKey.isSynthetic() || !finalJoin) {
return names;
}
// if we use a synthetic key, we know there's only a single key element
final Column syntheticKey = getOnlyElement(getSchema().key());
return Streams.concat(Stream.of(syntheticKey.name()), names);
}
Aggregations