This is an automated email from the ASF dual-hosted git repository.
vogievetsky pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new 623b075d12 fix nested column sql operator return type inference
(#12851)
623b075d12 is described below
commit 623b075d127350f58d5981fe292e5d1f9ed72fcb
Author: Clint Wylie <[email protected]>
AuthorDate: Wed Aug 3 15:39:08 2022 -0700
fix nested column sql operator return type inference (#12851)
* fix nested column sql operator return type inference
* oops, final
---
.../java/org/apache/druid/sql/SqlLifecycle.java | 30 +-
.../builtin/NestedDataOperatorConversions.java | 43 +--
.../druid/sql/calcite/planner/DruidPlanner.java | 3 +-
.../druid/sql/calcite/table/RowSignatures.java | 37 +-
.../druid/sql/calcite/BaseCalciteQueryTest.java | 110 +++++-
.../druid/sql/calcite/CalciteIngestionDmlTest.java | 3 +-
.../sql/calcite/CalciteNestedDataQueryTest.java | 378 +++++++++++++++++----
.../sql/calcite/planner/DruidRexExecutorTest.java | 7 +-
8 files changed, 489 insertions(+), 122 deletions(-)
diff --git a/sql/src/main/java/org/apache/druid/sql/SqlLifecycle.java
b/sql/src/main/java/org/apache/druid/sql/SqlLifecycle.java
index 9007c77535..b3b9fee826 100644
--- a/sql/src/main/java/org/apache/druid/sql/SqlLifecycle.java
+++ b/sql/src/main/java/org/apache/druid/sql/SqlLifecycle.java
@@ -28,6 +28,7 @@ import org.apache.calcite.tools.RelConversionException;
import org.apache.calcite.tools.ValidationException;
import org.apache.druid.java.util.common.DateTimes;
import org.apache.druid.java.util.common.ISE;
+import org.apache.druid.java.util.common.Pair;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.guava.Sequence;
import org.apache.druid.java.util.common.guava.SequenceWrapper;
@@ -40,6 +41,7 @@ import org.apache.druid.query.QueryContext;
import org.apache.druid.query.QueryContexts;
import org.apache.druid.query.QueryInterruptedException;
import org.apache.druid.query.QueryTimeoutException;
+import org.apache.druid.segment.column.RowSignature;
import org.apache.druid.server.QueryScheduler;
import org.apache.druid.server.QueryStats;
import org.apache.druid.server.RequestLogLine;
@@ -55,6 +57,7 @@ import org.apache.druid.sql.calcite.planner.PlannerContext;
import org.apache.druid.sql.calcite.planner.PlannerFactory;
import org.apache.druid.sql.calcite.planner.PlannerResult;
import org.apache.druid.sql.calcite.planner.PrepareResult;
+import org.apache.druid.sql.calcite.table.RowSignatures;
import org.apache.druid.sql.http.SqlParameter;
import org.apache.druid.sql.http.SqlQuery;
@@ -357,8 +360,11 @@ public class SqlLifecycle
return plannerResult.run();
}
+ /**
+ * Only for testing... returns result row signature and sequence of results
+ */
@VisibleForTesting
- public Sequence<Object[]> runSimple(
+ public Pair<RowSignature, Sequence<Object[]>> runSimple(
String sql,
Map<String, Object> queryContext,
List<SqlParameter> parameters,
@@ -381,14 +387,20 @@ public class SqlLifecycle
throw e;
}
- return Sequences.wrap(result, new SequenceWrapper()
- {
- @Override
- public void after(boolean isDone, Throwable thrown)
- {
- finalizeStateAndEmitLogsAndMetrics(thrown, null, -1);
- }
- });
+ return new Pair<>(
+ RowSignatures.fromRelDataType(plannerResult.rowType().getFieldNames(),
plannerResult.rowType()),
+ Sequences.wrap(
+ result,
+ new SequenceWrapper()
+ {
+ @Override
+ public void after(boolean isDone, Throwable thrown)
+ {
+ finalizeStateAndEmitLogsAndMetrics(thrown, null, -1);
+ }
+ }
+ )
+ );
}
@VisibleForTesting
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/NestedDataOperatorConversions.java
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/NestedDataOperatorConversions.java
index 68e2f07501..e275434cd5 100644
---
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/NestedDataOperatorConversions.java
+++
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/NestedDataOperatorConversions.java
@@ -29,6 +29,7 @@ import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.OperandTypes;
import org.apache.calcite.sql.type.SqlOperandCountRanges;
+import org.apache.calcite.sql.type.SqlReturnTypeInference;
import org.apache.calcite.sql.type.SqlTypeFamily;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.druid.java.util.common.StringUtils;
@@ -56,6 +57,12 @@ import java.util.List;
public class NestedDataOperatorConversions
{
+ public static final SqlReturnTypeInference NESTED_RETURN_TYPE_INFERENCE =
opBinding -> RowSignatures.makeComplexType(
+ opBinding.getTypeFactory(),
+ NestedDataComplexTypeSerde.TYPE,
+ true
+ );
+
public static class GetPathOperatorConversion implements
SqlOperatorConversion
{
private static final String FUNCTION_NAME =
StringUtils.toUpperCase("get_path");
@@ -236,13 +243,7 @@ public class NestedDataOperatorConversions
private static final SqlFunction SQL_FUNCTION = OperatorConversions
.operatorBuilder(FUNCTION_NAME)
.operandTypeChecker(OperandTypes.family(new
SqlTypeFamily[]{SqlTypeFamily.ANY, SqlTypeFamily.CHARACTER, SqlTypeFamily.ANY,
SqlTypeFamily.ANY, SqlTypeFamily.ANY}))
- .returnTypeCascadeNullable(
- new RowSignatures.ComplexSqlType(
- SqlTypeName.OTHER,
- NestedDataComplexTypeSerde.TYPE,
- true
- ).getSqlTypeName()
- )
+ .returnTypeInference(NESTED_RETURN_TYPE_INFERENCE)
.functionCategory(SqlFunctionCategory.SYSTEM)
.build();
@@ -429,16 +430,12 @@ public class NestedDataOperatorConversions
continue;
}
operandTypes[i] = typeFactory.createTypeWithNullability(
- typeFactory.createSqlType(SqlTypeName.ANY), true);
+ typeFactory.createSqlType(SqlTypeName.ANY),
+ true
+ );
}
})
- .returnTypeCascadeNullable(
- new RowSignatures.ComplexSqlType(
- SqlTypeName.OTHER,
- NestedDataComplexTypeSerde.TYPE,
- true
- ).getSqlTypeName()
- )
+ .returnTypeInference(NESTED_RETURN_TYPE_INFERENCE)
.functionCategory(SqlFunctionCategory.SYSTEM)
.build();
@@ -484,13 +481,7 @@ public class NestedDataOperatorConversions
private static final SqlFunction SQL_FUNCTION = OperatorConversions
.operatorBuilder(StringUtils.toUpperCase(FUNCTION_NAME))
.operandTypes(SqlTypeFamily.ANY)
- .returnTypeCascadeNullable(
- new RowSignatures.ComplexSqlType(
- SqlTypeName.OTHER,
- NestedDataComplexTypeSerde.TYPE,
- true
- ).getSqlTypeName()
- )
+ .returnTypeInference(NESTED_RETURN_TYPE_INFERENCE)
.functionCategory(SqlFunctionCategory.USER_DEFINED_FUNCTION)
.build();
@@ -566,13 +557,7 @@ public class NestedDataOperatorConversions
private static final SqlFunction SQL_FUNCTION = OperatorConversions
.operatorBuilder(StringUtils.toUpperCase(FUNCTION_NAME))
.operandTypes(SqlTypeFamily.ANY)
- .returnTypeCascadeNullable(
- new RowSignatures.ComplexSqlType(
- SqlTypeName.OTHER,
- NestedDataComplexTypeSerde.TYPE,
- true
- ).getSqlTypeName()
- )
+ .returnTypeInference(NESTED_RETURN_TYPE_INFERENCE)
.functionCategory(SqlFunctionCategory.USER_DEFINED_FUNCTION)
.build();
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidPlanner.java
b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidPlanner.java
index e3feaa2a2f..33a96a46fb 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidPlanner.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidPlanner.java
@@ -409,7 +409,8 @@ public class DruidPlanner implements Closeable
// because no values were provided. (Values are not required in the
PREPARE case
// but now that we're planning, we require them.)
RelNode parameterized = possiblyLimitedRoot.rel.accept(
- new RelParameterizerShuttle(plannerContext));
+ new RelParameterizerShuttle(plannerContext)
+ );
final DruidRel<?> druidRel = (DruidRel<?>) planner.transform(
CalciteRulesManager.DRUID_CONVENTION_RULES,
planner.getEmptyTraitSet()
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/table/RowSignatures.java
b/sql/src/main/java/org/apache/druid/sql/calcite/table/RowSignatures.java
index 04d49573ce..13e2c268d0 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/table/RowSignatures.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/table/RowSignatures.java
@@ -147,10 +147,7 @@ public class RowSignatures
}
break;
case COMPLEX:
- type = typeFactory.createTypeWithNullability(
- new ComplexSqlType(SqlTypeName.OTHER, columnType, true),
- true
- );
+ type = makeComplexType(typeFactory, columnType, true);
break;
default:
throw new ISE("valueType[%s] not translatable", columnType);
@@ -164,7 +161,37 @@ public class RowSignatures
}
/**
- * Calcite {@link RelDataType} for Druid complex columns, to preserve
complex type information
+ * Creates a {@link ComplexSqlType} using the supplied {@link
RelDataTypeFactory} to ensure that the
+ * {@link ComplexSqlType} is interned. This is important because Calcite
checks that the references are equal
+ * instead of the objects being equivalent.
+ *
+ * This method uses {@link
RelDataTypeFactory#createTypeWithNullability(RelDataType, boolean) ensures that
if the
+ * type factory is a {@link
org.apache.calcite.rel.type.RelDataTypeFactoryImpl} that the type is passed
through
+ * {@link
org.apache.calcite.rel.type.RelDataTypeFactoryImpl#canonize(RelDataType)} which
interns the type.
+ */
+ public static RelDataType makeComplexType(RelDataTypeFactory typeFactory,
ColumnType columnType, boolean isNullable)
+ {
+ return typeFactory.createTypeWithNullability(
+ new ComplexSqlType(SqlTypeName.OTHER, columnType, isNullable),
+ isNullable
+ );
+ }
+
+ /**
+ * Calcite {@link RelDataType} for Druid complex columns, to preserve
complex type information.
+ *
+ * If using with other operations of a {@link RelDataTypeFactory}, consider
wrapping the creation of this type in
+ * {@link RelDataTypeFactory#createTypeWithNullability(RelDataType, boolean)
to ensure that if the type factory is a
+ * {@link org.apache.calcite.rel.type.RelDataTypeFactoryImpl} that the type
is passed through
+ * {@link
org.apache.calcite.rel.type.RelDataTypeFactoryImpl#canonize(RelDataType)} which
interns the type.
+ *
+ * If {@link SqlTypeName} is going to be {@link SqlTypeName#OTHER} and a
{@link RelDataTypeFactory} is available,
+ * consider using {@link #makeComplexType(RelDataTypeFactory, ColumnType,
boolean)}.
+ *
+ * This type does not work well with {@link
org.apache.calcite.sql.type.ReturnTypes#explicit(RelDataType)}, which
+ * will create new {@link RelDataType} using {@link SqlTypeName} during
return type inference, so implementors of
+ * {@link org.apache.druid.sql.calcite.expression.SqlOperatorConversion}
should implement the
+ * {@link org.apache.calcite.sql.type.SqlReturnTypeInference} directly for
best results.
*/
public static final class ComplexSqlType extends AbstractSqlType
{
diff --git
a/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java
b/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java
index 8faee4fdf6..bcd33dad13 100644
--- a/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/calcite/BaseCalciteQueryTest.java
@@ -34,8 +34,10 @@ import org.apache.druid.hll.VersionOneHyperLogLogCollector;
import org.apache.druid.jackson.DefaultObjectMapper;
import org.apache.druid.java.util.common.DateTimes;
import org.apache.druid.java.util.common.Intervals;
+import org.apache.druid.java.util.common.Pair;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.granularity.Granularity;
+import org.apache.druid.java.util.common.guava.Sequence;
import org.apache.druid.java.util.common.io.Closer;
import org.apache.druid.java.util.common.logger.Logger;
import org.apache.druid.math.expr.ExprMacroTable;
@@ -73,6 +75,7 @@ import org.apache.druid.query.timeseries.TimeseriesQuery;
import org.apache.druid.query.topn.TopNQueryConfig;
import org.apache.druid.segment.column.ColumnHolder;
import org.apache.druid.segment.column.ColumnType;
+import org.apache.druid.segment.column.RowSignature;
import org.apache.druid.segment.join.JoinType;
import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
import org.apache.druid.server.QueryStackTests;
@@ -652,7 +655,27 @@ public class BaseCalciteQueryTest extends CalciteTestBase
sql,
CalciteTests.REGULAR_USER_AUTH_RESULT,
expectedQueries,
- expectedResults
+ expectedResults,
+ null
+ );
+ }
+
+ public void testQuery(
+ final String sql,
+ final List<Query> expectedQueries,
+ final List<Object[]> expectedResults,
+ final RowSignature expectedResultRowSignature
+ ) throws Exception
+ {
+ testQuery(
+ PLANNER_CONFIG_DEFAULT,
+ QUERY_CONTEXT_DEFAULT,
+ DEFAULT_PARAMETERS,
+ sql,
+ CalciteTests.REGULAR_USER_AUTH_RESULT,
+ expectedQueries,
+ expectedResults,
+ expectedResultRowSignature
);
}
@@ -670,7 +693,8 @@ public class BaseCalciteQueryTest extends CalciteTestBase
sql,
CalciteTests.REGULAR_USER_AUTH_RESULT,
expectedQueries,
- expectedResults
+ expectedResults,
+ null
);
}
@@ -688,7 +712,8 @@ public class BaseCalciteQueryTest extends CalciteTestBase
sql,
CalciteTests.REGULAR_USER_AUTH_RESULT,
expectedQueries,
- expectedResults
+ expectedResults,
+ null
);
}
@@ -707,7 +732,8 @@ public class BaseCalciteQueryTest extends CalciteTestBase
sql,
authenticationResult,
expectedQueries,
- expectedResults
+ expectedResults,
+ null
);
}
@@ -741,7 +767,7 @@ public class BaseCalciteQueryTest extends CalciteTestBase
{
log.info("SQL: %s", sql);
queryLogHook.clearRecordedQueries();
- final List<Object[]> plannerResults =
+ final Pair<RowSignature, List<Object[]>> plannerResults =
getResults(plannerConfig, queryContext, DEFAULT_PARAMETERS, sql,
authenticationResult);
verifyResults(sql, expectedQueries, expectedResults, plannerResults);
}
@@ -763,7 +789,30 @@ public class BaseCalciteQueryTest extends CalciteTestBase
sql,
authenticationResult,
expectedQueries,
- new DefaultResultsVerifier(expectedResults),
+ expectedResults,
+ null
+ );
+ }
+
+ public void testQuery(
+ final PlannerConfig plannerConfig,
+ final Map<String, Object> queryContext,
+ final List<SqlParameter> parameters,
+ final String sql,
+ final AuthenticationResult authenticationResult,
+ final List<Query> expectedQueries,
+ final List<Object[]> expectedResults,
+ final RowSignature expectedResultSignature
+ ) throws Exception
+ {
+ testQuery(
+ plannerConfig,
+ queryContext,
+ parameters,
+ sql,
+ authenticationResult,
+ expectedQueries,
+ new DefaultResultsVerifier(expectedResults, expectedResultSignature),
null
);
}
@@ -812,12 +861,12 @@ public class BaseCalciteQueryTest extends CalciteTestBase
expectedExceptionInitializer.accept(expectedException);
}
- final List<Object[]> plannerResults = getResults(plannerConfig,
theQueryContext, parameters, sql, authenticationResult);
+ final Pair<RowSignature, List<Object[]>> plannerResults =
getResults(plannerConfig, theQueryContext, parameters, sql,
authenticationResult);
verifyResults(sql, theQueries, plannerResults, expectedResultsVerifier);
}
}
- public List<Object[]> getResults(
+ public Pair<RowSignature, List<Object[]>> getResults(
final PlannerConfig plannerConfig,
final Map<String, Object> queryContext,
final List<SqlParameter> parameters,
@@ -838,7 +887,7 @@ public class BaseCalciteQueryTest extends CalciteTestBase
);
}
- public List<Object[]> getResults(
+ public Pair<RowSignature, List<Object[]>> getResults(
final PlannerConfig plannerConfig,
final Map<String, Object> queryContext,
final List<SqlParameter> parameters,
@@ -858,32 +907,43 @@ public class BaseCalciteQueryTest extends CalciteTestBase
authorizerMapper,
objectMapper
);
+ SqlLifecycle lifecycle = sqlLifecycleFactory.factorize();
- return sqlLifecycleFactory.factorize().runSimple(sql, queryContext,
parameters, authenticationResult).toList();
+ Pair<RowSignature, Sequence<Object[]>> result = lifecycle.runSimple(
+ sql,
+ queryContext,
+ parameters,
+ authenticationResult
+ );
+ return new Pair<>(
+ result.lhs,
+ result.rhs.toList()
+ );
}
public void verifyResults(
final String sql,
final List<Query> expectedQueries,
final List<Object[]> expectedResults,
- final List<Object[]> results
+ final Pair<RowSignature, List<Object[]>> results
)
{
- verifyResults(sql, expectedQueries, results, new
DefaultResultsVerifier(expectedResults));
+ verifyResults(sql, expectedQueries, results, new
DefaultResultsVerifier(expectedResults, null));
}
public void verifyResults(
final String sql,
final List<Query> expectedQueries,
- final List<Object[]> results,
+ final Pair<RowSignature, List<Object[]>> results,
final ResultsVerifier expectedResultsVerifier
)
{
- for (int i = 0; i < results.size(); i++) {
- log.info("row #%d: %s", i, Arrays.toString(results.get(i)));
+ for (int i = 0; i < results.rhs.size(); i++) {
+ log.info("row #%d: %s", i, Arrays.toString(results.rhs.get(i)));
}
- expectedResultsVerifier.verify(sql, results);
+ expectedResultsVerifier.verifyRowSignature(results.lhs);
+ expectedResultsVerifier.verify(sql, results.rhs);
verifyQueries(sql, expectedQueries);
}
@@ -1222,16 +1282,32 @@ public class BaseCalciteQueryTest extends
CalciteTestBase
@FunctionalInterface
public interface ResultsVerifier
{
+ default void verifyRowSignature(RowSignature rowSignature)
+ {
+ // do nothing
+ }
+
void verify(String sql, List<Object[]> results);
}
public class DefaultResultsVerifier implements ResultsVerifier
{
protected final List<Object[]> expectedResults;
+ @Nullable
+ protected final RowSignature expectedResultRowSignature;
- public DefaultResultsVerifier(List<Object[]> expectedResults)
+ public DefaultResultsVerifier(List<Object[]> expectedResults, RowSignature
expectedSignature)
{
this.expectedResults = expectedResults;
+ this.expectedResultRowSignature = expectedSignature;
+ }
+
+ @Override
+ public void verifyRowSignature(RowSignature rowSignature)
+ {
+ if (expectedResultRowSignature != null) {
+ Assert.assertEquals(expectedResultRowSignature, rowSignature);
+ }
}
@Override
diff --git
a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteIngestionDmlTest.java
b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteIngestionDmlTest.java
index 8200fa2dc1..64c094923a 100644
---
a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteIngestionDmlTest.java
+++
b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteIngestionDmlTest.java
@@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableSet;
import org.apache.druid.data.input.impl.CsvInputFormat;
import org.apache.druid.data.input.impl.InlineInputSource;
import org.apache.druid.java.util.common.ISE;
+import org.apache.druid.java.util.common.Pair;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.granularity.Granularity;
import org.apache.druid.query.Query;
@@ -310,7 +311,7 @@ public class CalciteIngestionDmlTest extends
BaseCalciteQueryTest
analyzeResources(plannerConfig, new AuthConfig(), sql, queryContext,
authenticationResult)
);
- final List<Object[]> results =
+ final Pair<RowSignature, List<Object[]>> results =
getResults(plannerConfig, queryContext, Collections.emptyList(),
sql, authenticationResult);
verifyResults(
diff --git
a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java
b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java
index 724f716bb9..1001604c6d 100644
---
a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java
+++
b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java
@@ -56,6 +56,7 @@ import org.apache.druid.segment.IndexBuilder;
import org.apache.druid.segment.NestedDataDimensionSchema;
import org.apache.druid.segment.QueryableIndex;
import org.apache.druid.segment.column.ColumnType;
+import org.apache.druid.segment.column.RowSignature;
import org.apache.druid.segment.incremental.IncrementalIndexSchema;
import org.apache.druid.segment.nested.NestedDataComplexTypeSerde;
import org.apache.druid.segment.serde.ComplexMetrics;
@@ -230,7 +231,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -263,7 +268,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -296,7 +305,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -329,7 +342,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
new Object[]{NullHandling.defaultStringValue(), 5L},
new Object[]{"2", 1L},
new Object[]{"hello", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -371,7 +388,13 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
},
new Object[]{"100", "100", "100", 2L},
new Object[]{"200", "200", "200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.STRING)
+ .add("EXPR$2", ColumnType.STRING)
+ .add("EXPR$3", ColumnType.LONG)
+ .build()
);
}
@@ -413,7 +436,13 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
},
new Object[]{"100", "100", "100", 2L},
new Object[]{"200", "200", "200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.STRING)
+ .add("EXPR$2", ColumnType.STRING)
+ .add("EXPR$3", ColumnType.LONG)
+ .build()
);
}
@@ -448,7 +477,12 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
new Object[]{NullHandling.defaultStringValue(),
NullHandling.defaultStringValue(), 4L},
new Object[]{"100", "100", 2L},
new Object[]{"200", "200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.STRING)
+ .add("EXPR$2", ColumnType.LONG)
+ .build()
);
}
@@ -483,7 +517,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
"100",
2L
}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -519,7 +557,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
"100",
2L
}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -555,7 +597,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
"100",
2L
}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -591,7 +637,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
"100",
1L
}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -622,7 +672,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
- ImmutableList.of(new Object[]{"100", 1L})
+ ImmutableList.of(new Object[]{"100", 1L}),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -656,7 +710,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 1L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -690,7 +748,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -721,7 +783,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
- ImmutableList.of()
+ ImmutableList.of(),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -755,7 +821,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -788,7 +858,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -821,7 +895,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -853,7 +931,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{"100", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -887,7 +969,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -921,7 +1007,48 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
+ );
+ }
+
+ @Test
+ public void testGroupByPathNumericBoundFilterLongNoUpperNumeric() throws
Exception
+ {
+ testQuery(
+ "SELECT "
+ + "JSON_VALUE(nest, '$.x' RETURNING BIGINT),"
+ + "SUM(cnt) "
+ + "FROM druid.nested WHERE JSON_VALUE(nest, '$.x' RETURNING BIGINT) >=
100 GROUP BY 1",
+ ImmutableList.of(
+ GroupByQuery.builder()
+ .setDataSource(DATA_SOURCE)
+ .setInterval(querySegmentSpec(Filtration.eternity()))
+ .setGranularity(Granularities.ALL)
+ .setVirtualColumns(
+ new NestedFieldVirtualColumn("nest", "$.x", "v0",
ColumnType.LONG)
+ )
+ .setDimensions(
+ dimensions(
+ new DefaultDimensionSpec("v0", "d0",
ColumnType.LONG)
+ )
+ )
+ .setDimFilter(bound("v0", "100", null, false, false,
null, StringComparators.NUMERIC))
+ .setAggregatorSpecs(aggregators(new
LongSumAggregatorFactory("a0", "cnt")))
+ .setContext(QUERY_CONTEXT_DEFAULT)
+ .build()
+ ),
+ ImmutableList.of(
+ new Object[]{100L, 2L},
+ new Object[]{200L, 1L}
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.LONG)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -955,7 +1082,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -988,7 +1119,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"2.02", 2L},
new Object[]{"3.03", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1021,7 +1156,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"2.02", 2L},
new Object[]{"3.03", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1053,7 +1192,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{"2.02", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1087,7 +1230,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"2.02", 2L},
new Object[]{"3.03", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1121,7 +1268,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"2.02", 2L},
new Object[]{"3.03", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1155,7 +1306,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"2.02", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1188,7 +1343,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1222,7 +1381,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 1L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1256,7 +1419,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 4L},
new Object[]{"100", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1288,7 +1455,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{"100", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1321,7 +1492,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{"100", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1354,7 +1529,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{"100", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1387,7 +1566,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{"100", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1421,7 +1604,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1455,7 +1642,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 2L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1489,7 +1680,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"100", 1L},
new Object[]{"200", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1522,7 +1717,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{"100", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1545,7 +1744,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{400.0}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.DOUBLE)
+ .build()
);
}
@@ -1581,7 +1783,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{200.0}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.DOUBLE)
+ .build()
);
}
@@ -1615,7 +1820,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{100.0}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.DOUBLE)
+ .build()
);
}
@@ -1640,7 +1848,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{2.1}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.DOUBLE)
+ .build()
);
}
@@ -1677,7 +1888,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{2.1}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.DOUBLE)
+ .build()
);
}
@@ -1710,7 +1924,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{1.1}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.DOUBLE)
+ .build()
);
}
@@ -1733,7 +1950,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{400L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.LONG)
+ .build()
);
}
@@ -1757,7 +1977,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{700L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.LONG)
+ .build()
);
}
@@ -1780,7 +2003,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{400L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.LONG)
+ .build()
);
}
@@ -1804,7 +2030,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
),
ImmutableList.of(
new Object[]{700L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.LONG)
+ .build()
);
}
@@ -1842,7 +2071,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{null, 5L},
new Object[]{"[\"array\",\"n\"]", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING_ARRAY)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1880,7 +2113,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{null, 5L},
new Object[]{"[\"array\",\"n\"]", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING_ARRAY)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1919,7 +2156,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
new Object[]{null, 4L},
new Object[]{"[\"x\",\"y\",\"z\",\"mixed\",\"mixed2\"]", 2L},
new Object[]{"[\"x\",\"y\",\"z\",\"mixed2\"]", 1L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING_ARRAY)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1957,7 +2198,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{"[\"$\"]", 5L},
new Object[]{"[\"$.n.x\",\"$.array[0]\",\"$.array[1]\"]", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING_ARRAY)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -1989,7 +2234,11 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
ImmutableList.of(
new Object[]{NullHandling.defaultStringValue(), 5L},
new Object[]{"b", 2L}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", ColumnType.STRING)
+ .add("EXPR$1", ColumnType.LONG)
+ .build()
);
}
@@ -2052,7 +2301,12 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
new Object[]{null, null},
new Object[]{"{\"x\":1}",
"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":1}}"},
new Object[]{null, "2"}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", NestedDataComplexTypeSerde.TYPE)
+ .add("EXPR$1", NestedDataComplexTypeSerde.TYPE)
+ .build()
+
);
}
@@ -2097,7 +2351,10 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
new Object[]{"{\"x\":null,\"n\":null}"},
new Object[]{"{\"x\":\"100\",\"n\":{\"x\":1}}"},
new Object[]{"{\"x\":null,\"n\":null}"}
- )
+ ),
+ RowSignature.builder()
+ .add("EXPR$0", NestedDataComplexTypeSerde.TYPE)
+ .build()
);
}
@@ -2156,7 +2413,14 @@ public class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
new Object[]{"eee", "\"eee\"", "\"eee\"", "{\"foo\":1}", null},
new Object[]{"aaa", "\"aaa\"", "\"aaa\"", "{\"foo\":1}",
"{\"array\":[\"a\",\"b\"],\"n\":{\"x\":1}}"},
new Object[]{"ddd", "\"ddd\"", "\"ddd\"", "{\"foo\":1}", "2"}
- )
+ ),
+ RowSignature.builder()
+ .add("string", ColumnType.STRING)
+ .add("EXPR$1", NestedDataComplexTypeSerde.TYPE)
+ .add("EXPR$2", NestedDataComplexTypeSerde.TYPE)
+ .add("EXPR$3", NestedDataComplexTypeSerde.TYPE)
+ .add("EXPR$4", NestedDataComplexTypeSerde.TYPE)
+ .build()
);
}
}
diff --git
a/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidRexExecutorTest.java
b/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidRexExecutorTest.java
index c846432979..492287b84d 100644
---
a/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidRexExecutorTest.java
+++
b/sql/src/test/java/org/apache/druid/sql/calcite/planner/DruidRexExecutorTest.java
@@ -34,7 +34,6 @@ import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.type.ArraySqlType;
import org.apache.calcite.sql.type.BasicSqlType;
-import org.apache.calcite.sql.type.ReturnTypes;
import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
import org.apache.calcite.sql.type.SqlTypeFamily;
import org.apache.calcite.sql.type.SqlTypeName;
@@ -72,8 +71,10 @@ public class DruidRexExecutorTest extends
InitializedNullHandlingTest
.operandTypes(SqlTypeFamily.ANY)
.requiredOperands(0)
.returnTypeInference(
- ReturnTypes.explicit(
- new RowSignatures.ComplexSqlType(SqlTypeName.OTHER,
ColumnType.ofComplex("hyperUnique"), true)
+ opBinding -> RowSignatures.makeComplexType(
+ opBinding.getTypeFactory(),
+ ColumnType.ofComplex("hyperUnique"),
+ true
)
)
.functionCategory(SqlFunctionCategory.USER_DEFINED_FUNCTION)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]