julianhyde commented on code in PR #2606:
URL: https://github.com/apache/calcite/pull/2606#discussion_r904270107
##########
core/src/main/codegen/templates/Parser.jj:
##########
@@ -1558,6 +1562,101 @@ SqlNode NamedRoutineCall(
}
}
+/**
+ * Table argument of a table function.
+ * The input table with set semantics may be partitioned/ordered on one or
more columns.
+ */
+SqlNode TableArg() :
+{
+ final Span s;
+ SqlNode tableRef;
+ SqlNodeList partitionList = SqlNodeList.EMPTY;
+ SqlNodeList orderList = SqlNodeList.EMPTY;
+}
+{
+ { s = span(); }
+ tableRef = ExplicitTable(getPos())
+ [
+ <PARTITION> <BY>
+ partitionList = SimpleIdentifierOrList()
+ ]
+ [
+ orderList = OrderByInTableParam()
+ ]
+ {
+ if (partitionList.isEmpty() && orderList.isEmpty()) {
+ return tableRef;
+ } else {
+ return SqlStdOperatorTable.SET_SEMANTICS_TABLE.createCall(
+ s.pos(), tableRef, partitionList, orderList);
+ }
+ }
+}
+
+SqlNode PartitionedQueryOrOrderedQueryOrExpr(ExprContext exprContext) :
+{
+ final Span s;
+ SqlNode subQuery;
+ SqlNodeList partitionList = SqlNodeList.EMPTY;
+ SqlNodeList orderList = SqlNodeList.EMPTY;
+}
+{
+ { s = span(); }
+ subQuery = OrderedQueryOrExpr(exprContext)
+ [
+ <PARTITION> <BY>
+ partitionList = SimpleIdentifierOrList()
+ ]
+ [
+ orderList = OrderByInTableParam()
+ ]
+ {
+ if (partitionList.isEmpty() && orderList.isEmpty()) {
+ return subQuery;
+ } else {
+ return SqlStdOperatorTable.SET_SEMANTICS_TABLE.createCall(
+ s.pos(), subQuery, partitionList, orderList);
+ }
+ }
+}
+
+SqlNodeList OrderByInTableParam() :
+{
+ List<SqlNode> list;
+ SqlNode e;
+ final Span s;
+}
+{
+ <ORDER> { s = span(); }
+ <BY>
+ (
+ LOOKAHEAD(2)
+ <LPAREN> e = OrderItem()
+ {
+ list = startList(e);
+ }
+ (
+ // NOTE jvs 6-Feb-2004: See comments at top of file for why
Review Comment:
it this comment relevant?
##########
core/src/main/java/org/apache/calcite/runtime/CalciteResource.java:
##########
@@ -971,4 +971,12 @@ ExInstWithCause<CalciteException> failedToAccessField(
@BaseMessage("No operator for ''{0}'' with kind: ''{1}'', syntax: ''{2}''
during JSON deserialization")
ExInst<CalciteException> noOperator(String name, String kind, String syntax);
+ @BaseMessage("Only tables with set semantics may be partitioned. Invalid
PARTITION BY clause in the {0,number,#}-th operand of table function ''{1}''")
Review Comment:
don't add stuff to the end of files. it causes merge conflicts. add it at
the right place.
##########
core/src/main/java/org/apache/calcite/sql/SqlSetSemanticsTableOperator.java:
##########
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql;
+
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.validate.SqlValidator;
+import org.apache.calcite.sql.validate.SqlValidatorScope;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.util.List;
+
+/**
+ * SetSemanticsTable appears as an argument in a Table Function.
+ * It represents as an input table with set semantics.
+ */
+public class SqlSetSemanticsTableOperator extends SqlSpecialOperator {
Review Comment:
i don't believe that people can reference this operator by name. therefore
it should possibly subclass SqlInternalOperator.
##########
core/src/main/java/org/apache/calcite/sql/SqlKind.java:
##########
@@ -130,6 +130,9 @@ public enum SqlKind {
*/
OTHER_FUNCTION,
+ /** Clause of input table with set semantics of Table Function. */
+ SET_SEMANTICS_TABLE,
Review Comment:
need to expand. 'the set semantics of a table function' is jargon. 'input
table' is jargon.
##########
core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java:
##########
@@ -2548,6 +2549,9 @@ public class SqlStdOperatorTable extends
ReflectiveSqlOperatorTable {
}
};
+ /** SetSemanticsTable represents as an input table with set semantics. */
+ public static final SqlSpecialOperator SET_SEMANTICS_TABLE = new
SqlSetSemanticsTableOperator();
Review Comment:
should probably be in `SqlnternalOperators`, since users can't reference it
from SQL.
##########
core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java:
##########
@@ -1362,13 +1364,98 @@ private void substituteSubQuery(Blackboard bb, SubQuery
subQuery) {
//
bb.cursors.add(converted.r);
return;
-
+ case SET_SEMANTICS_TABLE:
+ if (!config.isExpand()) {
+ return;
+ }
+ call = (SqlBasicCall) subQuery.node;
+ query = call.operand(0);
+ final SqlValidatorScope innerTableScope =
+ (query instanceof SqlSelect)
+ ? validator().getSelectScope((SqlSelect) query)
+ : null;
+ final Blackboard setSemanticsTableBb = createBlackboard(innerTableScope,
null, false);
+ final RelNode inputOfSetSemanticsTable = convertQueryRecursive(query,
false, null).project();
+ requireNonNull(inputOfSetSemanticsTable, () -> "input RelNode is null
for query " + query);
+ SqlNodeList partitionList = call.operand(1);
+ final ImmutableBitSet partitionKeys =
buildPartitionKeys(setSemanticsTableBb, partitionList);
+ // For set semantics table, distribution is singleton if does not
specify partition keys
+ RelDistribution distribution = partitionKeys.isEmpty()
+ ? RelDistributions.SINGLETON
+ : RelDistributions.hash(partitionKeys.asList());
+ // ORDER BY
+ final SqlNodeList orderList = call.operand(2);
+ final RelCollation orders = buildCollation(setSemanticsTableBb,
orderList);
+ relBuilder.push(inputOfSetSemanticsTable);
+ if (orderList.isEmpty()) {
+ relBuilder.exchange(distribution);
+ } else {
+ relBuilder.sortExchange(distribution, orders);
+ }
+ RelNode tableRel = relBuilder.build();
+ subQuery.expr = bb.register(tableRel, JoinRelType.LEFT);
+ // This is used when converting window table functions:
+ //
+ // select * from table(tumble(table emps, descriptor(deptno), interval
'3' DAY))
+ //
+ bb.cursors.add(tableRel);
+ return;
default:
throw new AssertionError("unexpected kind of sub-query: "
+ subQuery.node);
}
}
+ private ImmutableBitSet buildPartitionKeys(Blackboard bb, SqlNodeList
partitionList) {
+ final ImmutableBitSet.Builder partitionKeys = ImmutableBitSet.builder();
+ for (SqlNode partition : partitionList) {
+ validator().deriveType(bb.scope(), partition);
+ RexNode e = bb.convertExpression(partition);
+ partitionKeys.set(parseFieldIdx(e));
+ }
+ return partitionKeys.build();
+ }
+
+ private RelCollation buildCollation(Blackboard bb, SqlNodeList orderList) {
+ final List<RelFieldCollation> orderKeys = new ArrayList<>();
Review Comment:
can you combine this method with `convertOrderItem`?
##########
core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java:
##########
@@ -958,7 +961,16 @@ private static List<Integer> elseArgs(int count) {
private static List<RexNode> convertOperands(SqlRexContext cx,
SqlCall call, SqlOperandTypeChecker.Consistency consistency) {
- return convertOperands(cx, call, call.getOperandList(), consistency);
+ List<SqlNode> operandList;
+ if (call.getOperator() instanceof SqlTableFunction) {
+ // skip set semantic table node of table function
+ operandList =
+ call.getOperandList().stream().filter(
+ operand -> operand.getKind() !=
SET_SEMANTICS_TABLE).collect(Collectors.toList());
Review Comment:
suggest move '.collect' to next line. makes it easier to read.
##########
site/_docs/reference.md:
##########
@@ -1953,12 +1953,32 @@ Not implemented:
Table functions occur in the `FROM` clause.
+Table functions may have generic table parameters (i.e., no row type declared
when the table function is created), and the row type of the result might
depend on the row type(s) of the input tables.
+Besides, input tables are classified by three characteristics.
+The first characteristic is semantics. Input tables have either row semantics
or set semantics, as follows:
+* Row semantics means that the result of the table function depends on a
row-by-row basis.
+* Set semantics means that the outcome of the function depends on how the data
is partitioned.
+
+The second characteristic, which applies only to input tables with set
semantics, is whether the table function can generate a result row even if the
input table is empty.
+* If the table function can generate a result row on empty input, the table is
said to be "keep when empty".
+* The alternative is called "prune when empty", meaning that the result would
be pruned out if the input table is empty.
+
+The third characteristic is whether the input table supports pass-through
columns or not. Pass-through columns is a mechanism enabling the table function
to copy every column of an input row into columns of an output row.
+
+The input tables with set semantics may be partitioned on one or more columns.
+The input tables with set semantics may be ordered on one or more columns.
+
+Note:
+* The input tables with row semantics may not be partitioned or ordered.
+* A polymorphic table function may have multiple input tables. However, at
most one input table could have row semantics.
+
#### TUMBLE
In streaming queries, TUMBLE assigns a window for each row of a relation based
on a timestamp column. An assigned window is specified by its beginning and
ending. All assigned windows have the same length, and that's why tumbling
sometimes is named as "fixed windowing".
+The first parameter of TUMBLE table function is a generic table parameter. The
input table has row semantics and supports pass-through columns.
Review Comment:
add line break between paragraphs. fold paragraphs to 80 chars.
##########
core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties:
##########
@@ -317,4 +317,7 @@ InvalidInputForExtractXml=Invalid input for EXTRACT xpath:
''{0}'', namespace: '
InvalidInputForExistsNode=Invalid input for EXISTSNODE xpath: ''{0}'',
namespace: ''{1}''
DifferentLengthForBitwiseOperands=Different length for bitwise operands: the
first: {0,number,#}, the second: {1,number,#}
NoOperator=No operator for ''{0}'' with kind: ''{1}'', syntax: ''{2}'' during
JSON deserialization
+InvalidPartitionKeys=Only tables with set semantics may be partitioned.
Invalid PARTITION BY clause in the {0,number,#}-th operand of table function
''{1}''
Review Comment:
stuff at the end of files causes merge conflicts. put it in the right place.
##########
testkit/src/main/java/org/apache/calcite/test/MockSqlOperatorTable.java:
##########
@@ -168,6 +182,211 @@ public DedupFunction() {
}
}
+ /** "Score" user-defined table function. First parameter is input table with
row semantics. */
+ public static class ScoreTableFunction extends SqlFunction
+ implements SqlTableFunction {
+
+ private static final Map<Integer, TableCharacteristic> TABLE_PARAMS = new
HashMap<>();
Review Comment:
use `ImmutableMap`. no need to a `static` block.
##########
testkit/src/main/java/org/apache/calcite/test/MockSqlOperatorTable.java:
##########
@@ -168,6 +182,211 @@ public DedupFunction() {
}
}
+ /** "Score" user-defined table function. First parameter is input table with
row semantics. */
+ public static class ScoreTableFunction extends SqlFunction
+ implements SqlTableFunction {
+
+ private static final Map<Integer, TableCharacteristic> TABLE_PARAMS = new
HashMap<>();
+ static {
+ TABLE_PARAMS.put(0, TableCharacteristic.withRowSemantic(true));
+ }
+
+ public ScoreTableFunction() {
+ super("SCORE",
+ SqlKind.OTHER_FUNCTION,
+ ReturnTypes.CURSOR,
+ null,
+ new OperandMetadataImpl(),
+ SqlFunctionCategory.USER_DEFINED_TABLE_FUNCTION);
+ }
+
+ private static RelDataType inferRowType(SqlOperatorBinding opBinding) {
+ final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
+ final RelDataType inputRowType = opBinding.getOperandType(0);
+ final RelDataType bigintType =
+ typeFactory.createSqlType(SqlTypeName.BIGINT);
+ return typeFactory.builder()
+ .kind(inputRowType.getStructKind())
+ .addAll(inputRowType.getFieldList())
+ .add("SCORE_VALUE", bigintType).nullable(true)
+ .build();
+ }
+
+ @Override public SqlReturnTypeInference getRowTypeInference() {
+ return ScoreTableFunction::inferRowType;
+ }
+
+ @Override public TableCharacteristic tableCharacteristic(int ordinal) {
+ return TABLE_PARAMS.get(ordinal);
+ }
+
+ @Override public boolean argumentMustBeScalar(int ordinal) {
+ return !TABLE_PARAMS.containsKey(ordinal);
+ }
+
+ /** Operand type checker for {@link ScoreTableFunction}. */
+ private static class OperandMetadataImpl implements SqlOperandMetadata {
+
+ @Override public List<RelDataType> paramTypes(RelDataTypeFactory
typeFactory) {
+ return ImmutableList.of(typeFactory.createSqlType(SqlTypeName.ANY));
+ }
+
+ @Override public List<String> paramNames() {
+ return ImmutableList.of("DATA");
+ }
+
+ @Override public boolean checkOperandTypes(
+ SqlCallBinding callBinding, boolean throwOnFailure) {
+ return true;
+ }
+
+ @Override public SqlOperandCountRange getOperandCountRange() {
+ return SqlOperandCountRanges.of(1);
+ }
+
+ @Override public String getAllowedSignatures(SqlOperator op, String
opName) {
+ return "Score(TABLE table_name)";
+ };
+
+ @Override public Consistency getConsistency() {
+ return Consistency.NONE;
+ }
+
+ @Override public boolean isOptional(int i) {
+ return false;
+ }
+ }
+ }
+
+ /** "TopN" user-defined table function. First parameter is input table with
set semantics. */
+ public static class TopNTableFunction extends SqlFunction
+ implements SqlTableFunction {
+
+ private static final Map<Integer, TableCharacteristic> TABLE_PARAMS = new
HashMap<>();
+ static {
+ TABLE_PARAMS.put(
+ 0,
+ TableCharacteristic.withSetSemantic(true, true));
+ }
+
+ public TopNTableFunction() {
+ super("TOPN",
+ SqlKind.OTHER_FUNCTION,
+ ReturnTypes.CURSOR,
+ null,
+ new OperandMetadataImpl(),
+ SqlFunctionCategory.USER_DEFINED_TABLE_FUNCTION);
+ }
+
+ private static RelDataType inferRowType(SqlOperatorBinding opBinding) {
+ final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
+ final RelDataType inputRowType = opBinding.getOperandType(0);
+ final RelDataType bigintType =
+ typeFactory.createSqlType(SqlTypeName.BIGINT);
+ return typeFactory.builder()
+ .kind(inputRowType.getStructKind())
+ .addAll(inputRowType.getFieldList())
+ .add("RANK_NUMBER", bigintType).nullable(true)
+ .build();
+ }
+
+ @Override public SqlReturnTypeInference getRowTypeInference() {
+ return TopNTableFunction::inferRowType;
+ }
+
+ @Override public TableCharacteristic tableCharacteristic(int ordinal) {
+ return TABLE_PARAMS.get(ordinal);
+ }
+
+ @Override public boolean argumentMustBeScalar(int ordinal) {
+ return !TABLE_PARAMS.containsKey(ordinal);
+ }
+
+ /** Operand type checker for {@link TopNTableFunction}. */
+ private static class OperandMetadataImpl implements SqlOperandMetadata {
+
+ @Override public List<RelDataType> paramTypes(RelDataTypeFactory
typeFactory) {
+ return ImmutableList.of(
+ typeFactory.createSqlType(SqlTypeName.ANY),
+ typeFactory.createSqlType(SqlTypeName.INTEGER));
+ }
+
+ @Override public List<String> paramNames() {
+ return ImmutableList.of("DATA", "COL");
+ }
+
+ @Override public boolean checkOperandTypes(
+ SqlCallBinding callBinding, boolean throwOnFailure) {
+ final SqlNode operand1 = callBinding.operand(1);
+ final SqlValidator validator = callBinding.getValidator();
+ final RelDataType type = validator.getValidatedNodeType(operand1);
+ if (!SqlTypeUtil.isIntType(type)) {
+ if (throwOnFailure) {
+ throw callBinding.newValidationSignatureError();
+ } else {
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ @Override public SqlOperandCountRange getOperandCountRange() {
+ return SqlOperandCountRanges.of(2);
+ }
+
+ @Override public String getAllowedSignatures(SqlOperator op, String
opName) {
+ return "TopN(TABLE table_name, BIGINT rows)";
+ }
+
+ @Override public Consistency getConsistency() {
+ return Consistency.NONE;
+ }
+
+ @Override public boolean isOptional(int i) {
+ return false;
+ }
+ }
+ }
+
+ /** Invalid user-defined table function with multiple input tables with row
semantics. */
+ public static class InvalidTableFunction extends SqlFunction
+ implements SqlTableFunction {
+
+ private static final Map<Integer, TableCharacteristic> TABLE_PARAMS = new
HashMap<>();
Review Comment:
use `ImmutableMap`
##########
testkit/src/main/java/org/apache/calcite/test/MockSqlOperatorTable.java:
##########
@@ -168,6 +182,211 @@ public DedupFunction() {
}
}
+ /** "Score" user-defined table function. First parameter is input table with
row semantics. */
+ public static class ScoreTableFunction extends SqlFunction
+ implements SqlTableFunction {
+
+ private static final Map<Integer, TableCharacteristic> TABLE_PARAMS = new
HashMap<>();
Review Comment:
or perhaps an `ImmutableList` would be better.
##########
core/src/main/java/org/apache/calcite/sql/TableCharacteristic.java:
##########
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.sql;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.util.Objects;
+
+/**
+ * An input table of table function is classified by three characteristics.
Review Comment:
Is it pedantic to say 'table-valued input parameter of a table function'
rather than 'input table of table function'? After all, these are not
characteristics of tables, these are characteristics of parameters.
Could we have a few SQL examples here that use table functions with set
semantics, prune, etc.? Choose a good example and the concept will be clear.
##########
core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java:
##########
@@ -1362,13 +1364,98 @@ private void substituteSubQuery(Blackboard bb, SubQuery
subQuery) {
//
bb.cursors.add(converted.r);
return;
-
+ case SET_SEMANTICS_TABLE:
+ if (!config.isExpand()) {
+ return;
+ }
+ call = (SqlBasicCall) subQuery.node;
+ query = call.operand(0);
+ final SqlValidatorScope innerTableScope =
+ (query instanceof SqlSelect)
+ ? validator().getSelectScope((SqlSelect) query)
+ : null;
+ final Blackboard setSemanticsTableBb = createBlackboard(innerTableScope,
null, false);
+ final RelNode inputOfSetSemanticsTable = convertQueryRecursive(query,
false, null).project();
+ requireNonNull(inputOfSetSemanticsTable, () -> "input RelNode is null
for query " + query);
+ SqlNodeList partitionList = call.operand(1);
+ final ImmutableBitSet partitionKeys =
buildPartitionKeys(setSemanticsTableBb, partitionList);
+ // For set semantics table, distribution is singleton if does not
specify partition keys
+ RelDistribution distribution = partitionKeys.isEmpty()
+ ? RelDistributions.SINGLETON
+ : RelDistributions.hash(partitionKeys.asList());
+ // ORDER BY
+ final SqlNodeList orderList = call.operand(2);
+ final RelCollation orders = buildCollation(setSemanticsTableBb,
orderList);
+ relBuilder.push(inputOfSetSemanticsTable);
+ if (orderList.isEmpty()) {
+ relBuilder.exchange(distribution);
+ } else {
+ relBuilder.sortExchange(distribution, orders);
+ }
+ RelNode tableRel = relBuilder.build();
+ subQuery.expr = bb.register(tableRel, JoinRelType.LEFT);
+ // This is used when converting window table functions:
+ //
+ // select * from table(tumble(table emps, descriptor(deptno), interval
'3' DAY))
+ //
+ bb.cursors.add(tableRel);
+ return;
default:
throw new AssertionError("unexpected kind of sub-query: "
+ subQuery.node);
}
}
+ private ImmutableBitSet buildPartitionKeys(Blackboard bb, SqlNodeList
partitionList) {
+ final ImmutableBitSet.Builder partitionKeys = ImmutableBitSet.builder();
+ for (SqlNode partition : partitionList) {
+ validator().deriveType(bb.scope(), partition);
+ RexNode e = bb.convertExpression(partition);
+ partitionKeys.set(parseFieldIdx(e));
+ }
+ return partitionKeys.build();
+ }
+
+ private RelCollation buildCollation(Blackboard bb, SqlNodeList orderList) {
+ final List<RelFieldCollation> orderKeys = new ArrayList<>();
+ for (SqlNode order : orderList) {
+ final RelFieldCollation.Direction direction;
+ switch (order.getKind()) {
+ case DESCENDING:
+ direction = RelFieldCollation.Direction.DESCENDING;
+ order = ((SqlCall) order).operand(0);
+ break;
+ case NULLS_FIRST:
+ case NULLS_LAST:
+ throw new AssertionError();
Review Comment:
why?
##########
core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java:
##########
@@ -1362,13 +1364,98 @@ private void substituteSubQuery(Blackboard bb, SubQuery
subQuery) {
//
bb.cursors.add(converted.r);
return;
-
+ case SET_SEMANTICS_TABLE:
+ if (!config.isExpand()) {
Review Comment:
case is too long. move code into a separate method
##########
core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java:
##########
@@ -90,7 +91,9 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
+import static org.apache.calcite.sql.SqlKind.SET_SEMANTICS_TABLE;
Review Comment:
remove this static import. lots of other SqlKind fields in this file are
qualified.
##########
testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java:
##########
@@ -3988,6 +3988,77 @@ void checkPeriodPredicate(Checker checker) {
sql(sql).ok(expected);
}
+ @Test void testTableFunction() {
+ final String sql = "select * from table(score(table orders))";
+ final String expected = "SELECT *\n"
+ + "FROM TABLE(`SCORE`((TABLE `ORDERS`)))";
Review Comment:
TABLE seems to end up with an extra set of parentheses. something is wrong
with how TABLE is unparsed.
##########
site/_docs/reference.md:
##########
@@ -1953,12 +1953,32 @@ Not implemented:
Table functions occur in the `FROM` clause.
+Table functions may have generic table parameters (i.e., no row type declared
when the table function is created), and the row type of the result might
depend on the row type(s) of the input tables.
+Besides, input tables are classified by three characteristics.
+The first characteristic is semantics. Input tables have either row semantics
or set semantics, as follows:
+* Row semantics means that the result of the table function depends on a
row-by-row basis.
+* Set semantics means that the outcome of the function depends on how the data
is partitioned.
+
+The second characteristic, which applies only to input tables with set
semantics, is whether the table function can generate a result row even if the
input table is empty.
+* If the table function can generate a result row on empty input, the table is
said to be "keep when empty".
+* The alternative is called "prune when empty", meaning that the result would
be pruned out if the input table is empty.
+
+The third characteristic is whether the input table supports pass-through
columns or not. Pass-through columns is a mechanism enabling the table function
to copy every column of an input row into columns of an output row.
+
+The input tables with set semantics may be partitioned on one or more columns.
+The input tables with set semantics may be ordered on one or more columns.
+
+Note:
+* The input tables with row semantics may not be partitioned or ordered.
+* A polymorphic table function may have multiple input tables. However, at
most one input table could have row semantics.
+
#### TUMBLE
In streaming queries, TUMBLE assigns a window for each row of a relation based
on a timestamp column. An assigned window is specified by its beginning and
ending. All assigned windows have the same length, and that's why tumbling
sometimes is named as "fixed windowing".
+The first parameter of TUMBLE table function is a generic table parameter. The
input table has row semantics and supports pass-through columns.
Review Comment:
English needs article: 'the TUBMLE table function' rather than 'TUMBLE table
function'
##########
core/src/main/java/org/apache/calcite/sql/SqlTableFunction.java:
##########
@@ -30,4 +32,15 @@ public interface SqlTableFunction {
* @return strategy to infer the row type of a call to this function
*/
SqlReturnTypeInference getRowTypeInference();
+
+ /**
+ * Returns the table parameter characteristics for <code>ordinal</code>th
argument to this
+ * table function.
Review Comment:
argument or parameter? I think probably parameter.
does it return Optional.empty? Or does it return null?
what is the behavior if ordinal is < 0 or >= the number of parameters?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]