This is an automated email from the ASF dual-hosted git repository.
clintropolis 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 72f9c067eb6 fix: clustered segment catalog spec complex handling
(#19842)
72f9c067eb6 is described below
commit 72f9c067eb68be8742c19a34d51ed6ebd48597d4
Author: Clint Wylie <[email protected]>
AuthorDate: Wed Aug 5 23:09:02 2026 -0700
fix: clustered segment catalog spec complex handling (#19842)
---
.../druid/msq/util/DimensionSchemaUtils.java | 10 +-
.../druid/segment/DimensionHandlerUtils.java | 70 ++++++++++-
.../druid/segment/DimensionHandlerUtilsTest.java | 129 ++++++++++++++++++++-
.../ClusteredValueGroupsBaseTableMetadata.java | 14 +--
.../ClusteredValueGroupsBaseTableMetadataTest.java | 121 ++++++++++++++++++-
5 files changed, 311 insertions(+), 33 deletions(-)
diff --git
a/multi-stage-query/src/main/java/org/apache/druid/msq/util/DimensionSchemaUtils.java
b/multi-stage-query/src/main/java/org/apache/druid/msq/util/DimensionSchemaUtils.java
index 424700c30f0..4b7e6e7eb2b 100644
---
a/multi-stage-query/src/main/java/org/apache/druid/msq/util/DimensionSchemaUtils.java
+++
b/multi-stage-query/src/main/java/org/apache/druid/msq/util/DimensionSchemaUtils.java
@@ -31,8 +31,6 @@ import org.apache.druid.java.util.emitter.EmittingLogger;
import org.apache.druid.java.util.emitter.service.AlertEvent;
import org.apache.druid.segment.AutoTypeColumnSchema;
import org.apache.druid.segment.DimensionHandlerUtils;
-import org.apache.druid.segment.column.ColumnCapabilities;
-import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.ValueType;
@@ -81,9 +79,7 @@ public class DimensionSchemaUtils
// for complex types that are not COMPLEX<json>, we still want to use
the handler since 'auto' typing
// only works for the 'standard' built-in types
if (queryType != null && queryType.is(ValueType.COMPLEX) &&
!ColumnType.NESTED_DATA.equals(queryType)) {
- final ColumnCapabilities capabilities =
ColumnCapabilitiesImpl.createDefault().setType(queryType);
- return DimensionHandlerUtils.getHandlerFromCapabilities(column,
capabilities, null)
- .getDimensionSchema(capabilities);
+ return DimensionHandlerUtils.getComplexDimensionSchema(column,
queryType);
}
if (queryType != null && (queryType.isPrimitive() ||
queryType.isPrimitiveArray())) {
@@ -111,9 +107,7 @@ public class DimensionSchemaUtils
} else if (dimensionType.getType() == ValueType.ARRAY) {
return new AutoTypeColumnSchema(column, dimensionType, null);
} else {
- final ColumnCapabilities capabilities =
ColumnCapabilitiesImpl.createDefault().setType(dimensionType);
- return DimensionHandlerUtils.getHandlerFromCapabilities(column,
capabilities, null)
- .getDimensionSchema(capabilities);
+ return DimensionHandlerUtils.getComplexDimensionSchema(column,
dimensionType);
}
}
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/DimensionHandlerUtils.java
b/processing/src/main/java/org/apache/druid/segment/DimensionHandlerUtils.java
index e129ceb4177..e5d4804bcaa 100644
---
a/processing/src/main/java/org/apache/druid/segment/DimensionHandlerUtils.java
+++
b/processing/src/main/java/org/apache/druid/segment/DimensionHandlerUtils.java
@@ -24,8 +24,10 @@ import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Doubles;
import com.google.common.primitives.Floats;
import org.apache.druid.common.guava.GuavaUtils;
+import org.apache.druid.data.input.impl.DimensionSchema;
import org.apache.druid.data.input.impl.DimensionSchema.MultiValueHandling;
import org.apache.druid.error.DruidException;
+import org.apache.druid.error.InvalidInput;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.java.util.common.ISE;
import org.apache.druid.java.util.common.StringUtils;
@@ -130,17 +132,75 @@ public final class DimensionHandlerUtils
}
if (capabilities.is(ValueType.COMPLEX) &&
capabilities.getComplexTypeName() != null) {
- DimensionHandlerProvider provider =
DIMENSION_HANDLER_PROVIDERS.get(capabilities.getComplexTypeName());
- if (provider == null) {
- throw new ISE("Can't find DimensionHandlerProvider for typeName [%s]",
capabilities.getComplexTypeName());
- }
- return provider.get(dimensionName);
+ return getHandlerForComplexType(dimensionName,
capabilities.getComplexTypeName());
}
// Return a StringDimensionHandler by default (null columns will be
treated as String typed)
return new StringDimensionHandler(dimensionName, multiValueHandling, true,
false);
}
+ /**
+ * The {@link DimensionHandler} registered for a complex type. Complex
columns are stored by type-specific handlers,
+ * so a type contributed by an extension becomes storable as soon as that
extension registers one.
+ *
+ * @throws DruidException if no handler is registered for the type, which
usually means the extension defining it is
+ * not loaded
+ */
+ public static DimensionHandler<?, ?, ?> getHandlerForComplexType(String
dimensionName, String complexTypeName)
+ {
+ final DimensionHandlerProvider provider =
DIMENSION_HANDLER_PROVIDERS.get(complexTypeName);
+ if (provider == null) {
+ throw InvalidInput.exception(
+ "Complex type[%s] for dimension[%s] is not a valid type",
+ complexTypeName,
+ dimensionName
+ );
+ }
+ return provider.get(dimensionName);
+ }
+
+ /**
+ * The {@link DimensionSchema} to use when storing a complex column of the
given type, for callers that have a
+ * declared type rather than an existing column. Handlers are free to
consult the {@link ColumnCapabilities} they
+ * are given, so a default set describing the type is supplied on the
caller's behalf.
+ * <p>
+ * The schema the handler produces must describe the column that was asked
for, since a {@link DimensionSchema}
+ * selects its own handler at ingest time (via {@link
DimensionSchema#getDimensionHandler()}, which reads
+ * {@link DimensionSchema#getColumnType()}). A schema of some other type
would quietly store the column as that type
+ * instead, contradicting the type the caller declared, and one of some
other name would store a different column
+ * entirely.
+ *
+ * @throws DruidException if the type is not a named complex type, if no
handler is registered for it (which usually
+ * means the extension defining it is not loaded), or
if the registered handler does not
+ * describe the column that was asked for
+ */
+ public static DimensionSchema getComplexDimensionSchema(String
dimensionName, ColumnType type)
+ {
+ if (!type.is(ValueType.COMPLEX) || type.getComplexTypeName() == null) {
+ throw InvalidInput.exception("Type[%s] for dimension[%s] is not a named
complex type", type, dimensionName);
+ }
+ final DimensionSchema schema = getHandlerForComplexType(dimensionName,
type.getComplexTypeName())
+
.getDimensionSchema(ColumnCapabilitiesImpl.createDefault().setType(type));
+ if (!type.equals(schema.getColumnType())) {
+ throw DruidException.defensive(
+ "Dimension handler for type[%s] produced a schema of type[%s] for
dimension[%s]; a column cannot be stored"
+ + " as a type other than the one it declares",
+ type,
+ schema.getColumnType(),
+ dimensionName
+ );
+ }
+ if (!dimensionName.equals(schema.getName())) {
+ throw DruidException.defensive(
+ "Dimension handler for type[%s] produced a schema for dimension[%s]
instead of dimension[%s]",
+ type,
+ schema.getName(),
+ dimensionName
+ );
+ }
+ return schema;
+ }
+
public static List<ColumnType>
getValueTypesFromDimensionSpecs(List<DimensionSpec> dimSpecs)
{
List<ColumnType> types = new ArrayList<>(dimSpecs.size());
diff --git
a/processing/src/test/java/org/apache/druid/segment/DimensionHandlerUtilsTest.java
b/processing/src/test/java/org/apache/druid/segment/DimensionHandlerUtilsTest.java
index 1985aeb68d4..d48931122d6 100644
---
a/processing/src/test/java/org/apache/druid/segment/DimensionHandlerUtilsTest.java
+++
b/processing/src/test/java/org/apache/druid/segment/DimensionHandlerUtilsTest.java
@@ -26,6 +26,7 @@ import org.apache.druid.data.input.impl.FloatDimensionSchema;
import org.apache.druid.data.input.impl.LongDimensionSchema;
import org.apache.druid.data.input.impl.NewSpatialDimensionSchema;
import org.apache.druid.data.input.impl.StringDimensionSchema;
+import org.apache.druid.error.DruidException;
import org.apache.druid.java.util.common.ISE;
import org.apache.druid.segment.column.ColumnCapabilities;
import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
@@ -82,11 +83,15 @@ public class DimensionHandlerUtilsTest extends
InitializedNullHandlingTest
public void testGetHandlerFromUnknownComplexCapabilities()
{
ColumnCapabilities capabilities = new
ColumnCapabilitiesImpl().setType(ColumnType.ofComplex("unknown"));
- ISE ex = Assertions.assertThrows(
- ISE.class,
- () -> DimensionHandlerUtils.getHandlerFromCapabilities(DIM_NAME,
capabilities, null)
+ Throwable t = Assertions.assertThrows(
+ DruidException.class,
+ () -> DimensionHandlerUtils.getHandlerFromCapabilities(
+ DIM_NAME,
+ capabilities,
+ null
+ )
);
- Assertions.assertTrue(ex.getMessage().contains("Can't find
DimensionHandlerProvider for typeName [unknown]"));
+ Assertions.assertEquals("Complex type[unknown] for dimension[dim] is not a
valid type", t.getMessage());
}
@Test
@@ -320,26 +325,138 @@ public class DimensionHandlerUtilsTest extends
InitializedNullHandlingTest
private static class TestDimensionSchema extends DimensionSchema
{
+ private final String typeName;
protected TestDimensionSchema(
String name,
MultiValueHandling multiValueHandling,
boolean createBitmapIndex
)
+ {
+ this(name, multiValueHandling, createBitmapIndex, TYPE);
+ }
+
+ protected TestDimensionSchema(
+ String name,
+ MultiValueHandling multiValueHandling,
+ boolean createBitmapIndex,
+ String typeName
+ )
{
super(name, multiValueHandling, createBitmapIndex);
+ this.typeName = typeName;
}
@Override
public String getTypeName()
{
- return TYPE;
+ return typeName;
}
@Override
public ColumnType getColumnType()
{
- return ColumnType.ofComplex(TYPE);
+ return ColumnType.ofComplex(typeName);
}
}
+
+ @Test
+ public void testGetComplexDimensionSchema()
+ {
+ Assertions.assertEquals(
+ new TestDimensionSchema("x", null, false),
+ DimensionHandlerUtils.getComplexDimensionSchema("x",
ColumnType.ofComplex(TYPE))
+ );
+ }
+
+ @Test
+ public void testGetComplexDimensionSchemaUnregisteredType()
+ {
+ Throwable t = Assertions.assertThrows(
+ DruidException.class,
+ () -> DimensionHandlerUtils.getComplexDimensionSchema("x",
ColumnType.ofComplex("noSuchType"))
+ );
+ Assertions.assertEquals("Complex type[noSuchType] for dimension[x] is not
a valid type", t.getMessage());
+ }
+
+ @Test
+ public void testGetComplexDimensionSchemaRejectsNonComplexType()
+ {
+ Throwable t = Assertions.assertThrows(
+ DruidException.class,
+ () -> DimensionHandlerUtils.getComplexDimensionSchema("x",
ColumnType.STRING)
+ );
+ Assertions.assertEquals("Type[STRING] for dimension[x] is not a named
complex type", t.getMessage());
+ }
+
+ /**
+ * A schema selects its own handler at ingest time, so a handler that hands
back a schema of some other type would
+ * quietly store the column as that type rather than the one the caller
declared.
+ */
+ @Test
+ public void testGetComplexDimensionSchemaRejectsSchemaOfOtherType()
+ {
+ final String typeName = "otherTypeSchemaType";
+ DimensionHandlerUtils.registerDimensionHandlerProvider(
+ typeName,
+ d -> new DoubleDimensionHandler(d)
+ {
+ @Override
+ public DimensionSchema getDimensionSchema(ColumnCapabilities
capabilities)
+ {
+ return new DoubleDimensionSchema(d);
+ }
+ }
+ );
+ Throwable t = Assertions.assertThrows(
+ DruidException.class,
+ () -> DimensionHandlerUtils.getComplexDimensionSchema("x",
ColumnType.ofComplex(typeName))
+ );
+ Assertions.assertEquals(
+ "Dimension handler for type[COMPLEX<otherTypeSchemaType>] produced a
schema of type[DOUBLE] for dimension[x];"
+ + " a column cannot be stored as a type other than the one it
declares",
+ t.getMessage()
+ );
+ }
+
+ /**
+ * Likewise, a handler that hands back a schema for some other column would
store a different column entirely.
+ */
+ @Test
+ public void testGetComplexDimensionSchemaRejectsSchemaOfOtherName()
+ {
+ final String typeName = "otherNameSchemaType";
+ DimensionHandlerUtils.registerDimensionHandlerProvider(
+ typeName,
+ d -> new DoubleDimensionHandler(d)
+ {
+ @Override
+ public DimensionSchema getDimensionSchema(ColumnCapabilities
capabilities)
+ {
+ return new TestDimensionSchema("y", null, false, typeName);
+ }
+ }
+ );
+ Throwable t = Assertions.assertThrows(
+ DruidException.class,
+ () -> DimensionHandlerUtils.getComplexDimensionSchema("x",
ColumnType.ofComplex(typeName))
+ );
+ Assertions.assertEquals(
+ "Dimension handler for type[COMPLEX<otherNameSchemaType>] produced a
schema for dimension[y] instead of"
+ + " dimension[x]",
+ t.getMessage()
+ );
+ }
+
+ @Test
+ public void testGetHandlerForComplexType()
+ {
+
Assertions.assertNotNull(DimensionHandlerUtils.getHandlerForComplexType("x",
TYPE));
+ Throwable t = Assertions.assertThrows(
+ DruidException.class,
+ () -> DimensionHandlerUtils.getHandlerForComplexType("x", "noSuchType")
+ );
+ Assertions.assertEquals("Complex type[noSuchType] for dimension[x] is not
a valid type", t.getMessage());
+ }
+
}
diff --git
a/server/src/main/java/org/apache/druid/catalog/model/ClusteredValueGroupsBaseTableMetadata.java
b/server/src/main/java/org/apache/druid/catalog/model/ClusteredValueGroupsBaseTableMetadata.java
index feaf647e402..dd0dca87794 100644
---
a/server/src/main/java/org/apache/druid/catalog/model/ClusteredValueGroupsBaseTableMetadata.java
+++
b/server/src/main/java/org/apache/druid/catalog/model/ClusteredValueGroupsBaseTableMetadata.java
@@ -27,10 +27,11 @@ import
org.apache.druid.data.input.impl.ClusteredValueGroupsBaseTableProjectionS
import org.apache.druid.data.input.impl.DimensionSchema;
import org.apache.druid.error.InvalidInput;
import org.apache.druid.segment.AutoTypeColumnSchema;
-import org.apache.druid.segment.NestedDataColumnSchema;
+import org.apache.druid.segment.DimensionHandlerUtils;
import org.apache.druid.segment.VirtualColumns;
import org.apache.druid.segment.column.ColumnHolder;
import org.apache.druid.segment.column.ColumnType;
+import org.apache.druid.segment.column.ValueType;
import org.apache.druid.utils.CollectionUtils;
import javax.annotation.Nullable;
@@ -209,14 +210,11 @@ public class ClusteredValueGroupsBaseTableMetadata
implements DatasourceBaseTabl
// FLOAT ARRAY as DOUBLE ARRAY).
return DimensionSchema.getDefaultSchemaForBuiltInType(column.name(),
druidType);
}
- if (ColumnType.NESTED_DATA.equals(druidType)) {
- return new NestedDataColumnSchema(column.name(),
NestedDataColumnSchema.DEFAULT_FORMAT_VERSION);
+ if (druidType.is(ValueType.COMPLEX)) {
+ return DimensionHandlerUtils.getComplexDimensionSchema(column.name(),
druidType);
}
- // Other complex types cannot be ingested into a clustered base table:
there is no dimension handler for them,
- // and clustered base tables have no aggregators to produce them.
throw InvalidInput.exception(
- "column [%s] has unsupported type [%s] for a clustered base table;
supported types are primitive, primitive"
- + " array, and COMPLEX<json> columns",
+ "column [%s] has unsupported type [%s] for a clustered base table",
column.name(),
druidType
);
@@ -260,8 +258,6 @@ public class ClusteredValueGroupsBaseTableMetadata
implements DatasourceBaseTabl
// The auto schema stores FLOAT as DOUBLE.
expectedType = autoColumnType(declaredType);
}
- // A NestedDataColumnSchema always reports COMPLEX<json>, so this also
restricts json schemas to columns declared
- // as COMPLEX<json>.
if (!expectedType.equals(customSchema.getColumnType())) {
throw InvalidInput.exception(
"columnSchemas entry [%s] of type [%s] does not match the column's
declared type [%s]; column schemas"
diff --git
a/server/src/test/java/org/apache/druid/catalog/model/ClusteredValueGroupsBaseTableMetadataTest.java
b/server/src/test/java/org/apache/druid/catalog/model/ClusteredValueGroupsBaseTableMetadataTest.java
index a31a8e4dad8..3d63673a3e0 100644
---
a/server/src/test/java/org/apache/druid/catalog/model/ClusteredValueGroupsBaseTableMetadataTest.java
+++
b/server/src/test/java/org/apache/druid/catalog/model/ClusteredValueGroupsBaseTableMetadataTest.java
@@ -29,12 +29,18 @@ import
org.apache.druid.data.input.impl.DoubleDimensionSchema;
import org.apache.druid.data.input.impl.LongDimensionSchema;
import org.apache.druid.data.input.impl.StringDimensionSchema;
import org.apache.druid.error.DruidException;
+import org.apache.druid.guice.BuiltInTypesModule;
import org.apache.druid.jackson.DefaultObjectMapper;
+import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.math.expr.ExprMacroTable;
import org.apache.druid.segment.AutoTypeColumnSchema;
import org.apache.druid.segment.DefaultColumnFormatConfig;
+import org.apache.druid.segment.DimensionHandler;
+import org.apache.druid.segment.DimensionHandlerUtils;
+import org.apache.druid.segment.DoubleDimensionHandler;
import org.apache.druid.segment.NestedDataColumnSchema;
import org.apache.druid.segment.VirtualColumns;
+import org.apache.druid.segment.column.ColumnCapabilities;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
import org.apache.druid.testing.InitializedNullHandlingTest;
@@ -48,6 +54,10 @@ import java.util.Map;
public class ClusteredValueGroupsBaseTableMetadataTest extends
InitializedNullHandlingTest
{
+ static {
+ BuiltInTypesModule.registerHandlersAndSerde();
+ }
+
private final ObjectMapper mapper = new
DefaultObjectMapper().setInjectableValues(
new InjectableValues.Std()
.addValue(ExprMacroTable.class, ExprMacroTable.nil())
@@ -428,7 +438,8 @@ public class ClusteredValueGroupsBaseTableMetadataTest
extends InitializedNullHa
);
// Declared types are retained in the ingestion schema rather than left to
inference: arrays cast an auto column
// to the declared type (an all-null batch has no values to infer from;
FLOAT ARRAY is stored as DOUBLE ARRAY by
- // the auto schema), and COMPLEX<json> uses the dedicated nested column
schema.
+ // the auto schema). COMPLEX<json> resolves through its dimension handler
to an uncast auto column, which is how
+ // json columns are stored everywhere else.
Assert.assertEquals(
ClusteredValueGroupsBaseTableProjectionSpec.builder()
.columns(
@@ -437,8 +448,8 @@ public class ClusteredValueGroupsBaseTableMetadataTest
extends InitializedNullHa
new
AutoTypeColumnSchema("tags", ColumnType.STRING_ARRAY, null),
new
AutoTypeColumnSchema("vals", ColumnType.LONG_ARRAY, null),
new
AutoTypeColumnSchema("ratios", ColumnType.DOUBLE_ARRAY, null),
- new
NestedDataColumnSchema("attrs", NestedDataColumnSchema.DEFAULT_FORMAT_VERSION),
- new
NestedDataColumnSchema("attrs2", NestedDataColumnSchema.DEFAULT_FORMAT_VERSION),
+
AutoTypeColumnSchema.of("attrs"),
+
AutoTypeColumnSchema.of("attrs2"),
new
AutoTypeColumnSchema("vals2", ColumnType.LONG_ARRAY, null)
)
.clusteringColumns("tenant")
@@ -447,8 +458,13 @@ public class ClusteredValueGroupsBaseTableMetadataTest
extends InitializedNullHa
);
}
+ /**
+ * A complex type with no registered dimension handler cannot be stored, and
the handler lookup reports it rather
+ * than the type being rejected as unsupported in general: the handler may
simply belong to an extension that is not
+ * loaded on the service validating the spec.
+ */
@Test
- public void testCreateSpecUnsupportedComplexTypeFails()
+ public void testCreateSpecComplexTypeWithoutHandlerFails()
{
final DatasourceBaseTableMetadata metadata = new
ClusteredValueGroupsBaseTableMetadata(
Collections.singletonList("tenant"),
@@ -461,7 +477,75 @@ public class ClusteredValueGroupsBaseTableMetadataTest
extends InitializedNullHa
new ColumnSpec("unique_things", "COMPLEX<hyperUnique>", null)
);
final DruidException e = Assert.assertThrows(DruidException.class, () ->
metadata.createSpec(columns));
- Assert.assertTrue(e.getMessage().contains("column [unique_things] has
unsupported type [COMPLEX<hyperUnique>]"));
+ Assert.assertEquals(
+ "Complex type[hyperUnique] for dimension[unique_things] is not a valid
type",
+ e.getMessage()
+ );
+ }
+
+ /**
+ * A complex type that does have a registered handler resolves through it,
which is how types contributed by
+ * extensions become declarable.
+ */
+ @Test
+ public void testCreateSpecComplexTypeWithRegisteredHandler()
+ {
+ final String typeName = "clusteredBaseTableTestType";
+ // Only getDimensionSchema is exercised; the handler's storage behavior is
irrelevant to building a spec.
+ DimensionHandlerUtils.registerDimensionHandlerProvider(
+ typeName,
+ name -> new DoubleDimensionHandler(name)
+ {
+ @Override
+ public DimensionSchema getDimensionSchema(ColumnCapabilities
capabilities)
+ {
+ return new TestComplexDimensionSchema(name, typeName);
+ }
+ }
+ );
+
+ final DatasourceBaseTableMetadata metadata = new
ClusteredValueGroupsBaseTableMetadata(
+ Collections.singletonList("tenant"),
+ null,
+ null
+ );
+ final List<ColumnSpec> columns = Arrays.asList(
+ new ColumnSpec("tenant", Columns.SQL_VARCHAR, null),
+ new ColumnSpec(Columns.TIME_COLUMN, null, null),
+ new ColumnSpec("sketch", StringUtils.format("COMPLEX<%s>", typeName),
null)
+ );
+
+ final List<DimensionSchema> specColumns =
metadata.createSpec(columns).getDimensionsSpec().getDimensions();
+ final DimensionSchema stored = specColumns.get(specColumns.size() - 1);
+ Assert.assertEquals("sketch", stored.getName());
+ Assert.assertEquals(ColumnType.ofComplex(typeName),
stored.getColumnType());
+ }
+
+ @Test
+ public void testCreateSpecNestedTypeUsesRegisteredHandler()
+ {
+ final DatasourceBaseTableMetadata metadata = new
ClusteredValueGroupsBaseTableMetadata(
+ Collections.singletonList("tenant"),
+ null,
+ null
+ );
+ final List<ColumnSpec> columns = Arrays.asList(
+ new ColumnSpec("tenant", Columns.SQL_VARCHAR, null),
+ new ColumnSpec(Columns.TIME_COLUMN, null, null),
+ new ColumnSpec("payload", ColumnType.NESTED_DATA.asTypeString(), null)
+ );
+
+ final List<DimensionSchema> specColumns =
metadata.createSpec(columns).getDimensionsSpec().getDimensions();
+ final DimensionSchema stored = specColumns.get(specColumns.size() - 1);
+ Assert.assertEquals(AutoTypeColumnSchema.of("payload"), stored);
+ Assert.assertEquals(ColumnType.NESTED_DATA, stored.getColumnType());
+ // The schema a json column used to get here, retained for backwards
compatibility, selects the same handler
+ // (DimensionHandler has no equals, so compare the class and the dimension
spec it hands out, which carries the
+ // type the handler stores).
+ final DimensionHandler<?, ?, ?> legacyHandler =
+ new NestedDataColumnSchema("payload",
NestedDataColumnSchema.DEFAULT_FORMAT_VERSION).getDimensionHandler();
+ Assert.assertEquals(legacyHandler.getClass(),
stored.getDimensionHandler().getClass());
+ Assert.assertEquals(legacyHandler.getDimensionSpec(),
stored.getDimensionHandler().getDimensionSpec());
}
@Test
@@ -594,4 +678,31 @@ public class ClusteredValueGroupsBaseTableMetadataTest
extends InitializedNullHa
.usingGetClass()
.verify();
}
+
+ /**
+ * Minimal complex {@link DimensionSchema}, the shape an honest handler for
a complex type returns: the column type
+ * it reports is the type it was registered for.
+ */
+ private static class TestComplexDimensionSchema extends DimensionSchema
+ {
+ private final String typeName;
+
+ TestComplexDimensionSchema(String name, String typeName)
+ {
+ super(name, null, false);
+ this.typeName = typeName;
+ }
+
+ @Override
+ public String getTypeName()
+ {
+ return typeName;
+ }
+
+ @Override
+ public ColumnType getColumnType()
+ {
+ return ColumnType.ofComplex(typeName);
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]