Repository: calcite Updated Branches: refs/heads/master f5b041ff4 -> 09be7e74a
[CALCITE-2045] CREATE TYPE (Shuyi Chen) Close apache/calcite#638 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/570aca3d Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/570aca3d Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/570aca3d Branch: refs/heads/master Commit: 570aca3d4fea34edcb04d0a5ec02f0fcf8925b0c Parents: f5b041f Author: Shuyi Chen <[email protected]> Authored: Tue Jan 30 19:37:56 2018 -0800 Committer: Julian Hyde <[email protected]> Committed: Fri Apr 20 11:11:59 2018 -0700 ---------------------------------------------------------------------- .../adapter/enumerable/RexToLixTranslator.java | 2 + .../apache/calcite/adapter/jdbc/JdbcSchema.java | 13 +++ .../calcite/jdbc/CachingCalciteSchema.java | 37 +++++- .../org/apache/calcite/jdbc/CalciteSchema.java | 98 +++++++++++++++- .../calcite/jdbc/SimpleCalciteSchema.java | 23 +++- .../org/apache/calcite/model/JsonMapSchema.java | 9 ++ .../java/org/apache/calcite/model/JsonRoot.java | 1 + .../java/org/apache/calcite/model/JsonType.java | 49 ++++++++ .../apache/calcite/model/JsonTypeAttribute.java | 36 ++++++ .../org/apache/calcite/model/ModelHandler.java | 37 +++++- .../calcite/prepare/CalciteCatalogReader.java | 7 +- .../apache/calcite/prepare/RelOptTableImpl.java | 13 +++ .../apache/calcite/runtime/CalciteResource.java | 3 + .../java/org/apache/calcite/schema/Schema.java | 16 +++ .../org/apache/calcite/schema/SchemaPlus.java | 4 + .../calcite/schema/impl/AbstractSchema.java | 23 ++++ .../calcite/schema/impl/DelegatingSchema.java | 9 ++ .../org/apache/calcite/sql/SqlDataTypeSpec.java | 59 +++++++--- .../java/org/apache/calcite/sql/SqlKind.java | 10 ++ .../calcite/sql/validate/SqlValidatorImpl.java | 3 + .../calcite/sql/validate/SqlValidatorUtil.java | 31 +++++ .../sql2rel/StandardConvertletTable.java | 3 + .../main/java/org/apache/calcite/util/Util.java | 1 - .../calcite/runtime/CalciteResource.properties | 1 + .../org/apache/calcite/test/CalciteSuite.java | 1 + .../apache/calcite/test/MockCatalogReader.java | 15 ++- .../java/org/apache/calcite/test/ModelTest.java | 16 +++ .../apache/calcite/test/SqlValidatorTest.java | 9 +- .../calcite/test/SqlValidatorTestCase.java | 4 + .../java/org/apache/calcite/test/UdtTest.java | 63 ++++++++++ server/src/main/codegen/config.fmpp | 2 + .../src/main/codegen/includes/parserImpls.ftl | 74 ++++++++++++ .../calcite/sql/ddl/SqlAttributeDefinition.java | 93 +++++++++++++++ .../apache/calcite/sql/ddl/SqlCreateTable.java | 10 +- .../apache/calcite/sql/ddl/SqlCreateType.java | 114 +++++++++++++++++++ .../org/apache/calcite/sql/ddl/SqlDdlNodes.java | 20 ++++ .../apache/calcite/sql/ddl/SqlDropObject.java | 11 +- .../org/apache/calcite/sql/ddl/SqlDropType.java | 37 ++++++ .../apache/calcite/test/ServerParserTest.java | 30 +++++ .../org/apache/calcite/test/ServerTest.java | 44 +++++++ server/src/test/resources/sql/type.iq | 57 ++++++++++ site/_docs/model.md | 32 +++++- site/_docs/reference.md | 28 ++++- 43 files changed, 1102 insertions(+), 46 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java index 083df7c..805216b 100644 --- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java +++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java @@ -780,6 +780,8 @@ public class RexToLixTranslator { final BigDecimal bd = literal.getValueAs(BigDecimal.class); if (javaClass == float.class) { return Expressions.constant(bd, javaClass); + } else if (javaClass == double.class) { + return Expressions.constant(bd, javaClass); } assert javaClass == BigDecimal.class; return Expressions.new_(BigDecimal.class, http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java index eb91b14..52dd865 100644 --- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java +++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcSchema.java @@ -410,6 +410,19 @@ public class JdbcSchema implements Schema { return getTableMap(!snapshot).keySet(); } + protected Map<String, RelProtoDataType> getTypes() { + // TODO: populate map from JDBC metadata + return ImmutableMap.of(); + } + + @Override public RelProtoDataType getType(String name) { + return getTypes().get(name); + } + + @Override public Set<String> getTypeNames() { + return getTypes().keySet(); + } + public Schema getSubSchema(String name) { // JDBC does not support sub-schemas. return null; http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java index 96476f1..486f0d2 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CachingCalciteSchema.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.jdbc; +import org.apache.calcite.rel.type.RelProtoDataType; import org.apache.calcite.schema.Function; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaVersion; @@ -44,21 +45,22 @@ class CachingCalciteSchema extends CalciteSchema { private final Cached<SubSchemaCache> implicitSubSchemaCache; private final Cached<NameSet> implicitTableCache; private final Cached<NameSet> implicitFunctionCache; + private final Cached<NameSet> implicitTypeCache; private boolean cache = true; /** Creates a CachingCalciteSchema. */ CachingCalciteSchema(CalciteSchema parent, Schema schema, String name) { - this(parent, schema, name, null, null, null, null, null, null, null); + this(parent, schema, name, null, null, null, null, null, null, null, null); } private CachingCalciteSchema(CalciteSchema parent, Schema schema, String name, NameMap<CalciteSchema> subSchemaMap, - NameMap<TableEntry> tableMap, NameMap<LatticeEntry> latticeMap, + NameMap<TableEntry> tableMap, NameMap<LatticeEntry> latticeMap, NameMap<TypeEntry> typeMap, NameMultimap<FunctionEntry> functionMap, NameSet functionNames, NameMap<FunctionEntry> nullaryFunctionMap, List<? extends List<String>> path) { - super(parent, schema, name, subSchemaMap, tableMap, latticeMap, + super(parent, schema, name, subSchemaMap, tableMap, latticeMap, typeMap, functionMap, functionNames, nullaryFunctionMap, path); this.implicitSubSchemaCache = new AbstractCached<SubSchemaCache>() { @@ -81,6 +83,13 @@ class CachingCalciteSchema extends CalciteSchema { CachingCalciteSchema.this.schema.getFunctionNames()); } }; + this.implicitTypeCache = + new AbstractCached<NameSet>() { + public NameSet build() { + return NameSet.immutableCopyOf( + CachingCalciteSchema.this.schema.getTypeNames()); + } + }; } public void setCache(boolean cache) { @@ -133,6 +142,19 @@ class CachingCalciteSchema extends CalciteSchema { return null; } + protected TypeEntry getImplicitType(String name, boolean caseSensitive) { + final long now = System.currentTimeMillis(); + final NameSet implicitTypeNames = implicitTypeCache.get(now); + for (String typeName + : implicitTypeNames.range(name, caseSensitive)) { + final RelProtoDataType type = schema.getType(typeName); + if (type != null) { + return typeEntry(name, type); + } + } + return null; + } + protected void addImplicitSubSchemaToBuilder( ImmutableSortedMap.Builder<String, CalciteSchema> builder) { ImmutableSortedMap<String, CalciteSchema> explicitSubSchemas = builder.build(); @@ -177,6 +199,13 @@ class CachingCalciteSchema extends CalciteSchema { builder.addAll(set.iterable()); } + protected void addImplicitTypeNamesToBuilder(ImmutableSortedSet.Builder<String> builder) { + // Add implicit types, case-sensitive. + final long now = System.currentTimeMillis(); + final NameSet set = implicitTypeCache.get(now); + builder.addAll(set.iterable()); + } + protected void addImplicitTablesBasedOnNullaryFunctionsToBuilder( ImmutableSortedMap.Builder<String, Table> builder) { ImmutableSortedMap<String, Table> explicitTables = builder.build(); @@ -217,7 +246,7 @@ class CachingCalciteSchema extends CalciteSchema { protected CalciteSchema snapshot(CalciteSchema parent, SchemaVersion version) { CalciteSchema snapshot = new CachingCalciteSchema(parent, - schema.snapshot(version), name, null, tableMap, latticeMap, + schema.snapshot(version), name, null, tableMap, latticeMap, typeMap, functionMap, functionNames, nullaryFunctionMap, getPath()); for (CalciteSchema subSchema : subSchemaMap.map().values()) { CalciteSchema subSchemaSnapshot = subSchema.snapshot(snapshot, version); http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java index b189e1b..badf781 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/CalciteSchema.java @@ -19,6 +19,7 @@ package org.apache.calcite.jdbc; import org.apache.calcite.linq4j.function.Experimental; import org.apache.calcite.linq4j.tree.Expression; import org.apache.calcite.materialize.Lattice; +import org.apache.calcite.rel.type.RelProtoDataType; import org.apache.calcite.schema.Function; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaPlus; @@ -62,6 +63,7 @@ public abstract class CalciteSchema { * {@link #schema}. */ protected final NameMap<TableEntry> tableMap; protected final NameMultimap<FunctionEntry> functionMap; + protected final NameMap<TypeEntry> typeMap; protected final NameMap<LatticeEntry> latticeMap; protected final NameSet functionNames; protected final NameMap<FunctionEntry> nullaryFunctionMap; @@ -70,7 +72,7 @@ public abstract class CalciteSchema { protected CalciteSchema(CalciteSchema parent, Schema schema, String name, NameMap<CalciteSchema> subSchemaMap, - NameMap<TableEntry> tableMap, NameMap<LatticeEntry> latticeMap, + NameMap<TableEntry> tableMap, NameMap<LatticeEntry> latticeMap, NameMap<TypeEntry> typeMap, NameMultimap<FunctionEntry> functionMap, NameSet functionNames, NameMap<FunctionEntry> nullaryFunctionMap, List<? extends List<String>> path) { @@ -103,6 +105,11 @@ public abstract class CalciteSchema { this.functionNames = Preconditions.checkNotNull(functionNames); this.nullaryFunctionMap = Preconditions.checkNotNull(nullaryFunctionMap); } + if (typeMap == null) { + this.typeMap = new NameMap<>(); + } else { + this.typeMap = Preconditions.checkNotNull(typeMap); + } this.path = path; } @@ -118,6 +125,12 @@ public abstract class CalciteSchema { protected abstract TableEntry getImplicitTable(String tableName, boolean caseSensitive); + /** Returns a type with a given name that is defined implicitly + * (that is, by the underlying {@link Schema} object, not explicitly + * by a call to {@link #add(String, RelProtoDataType)}), or null. */ + protected abstract TypeEntry getImplicitType(String name, + boolean caseSensitive); + /** Returns table function with a given name and zero arguments that is * defined implicitly (that is, by the underlying {@link Schema} object, * not explicitly by a call to {@link #add(String, Function)}), or null. */ @@ -141,6 +154,10 @@ public abstract class CalciteSchema { protected abstract void addImplicitFuncNamesToBuilder( ImmutableSortedSet.Builder<String> builder); + /** Adds implicit type names to a builder. */ + protected abstract void addImplicitTypeNamesToBuilder( + ImmutableSortedSet.Builder<String> builder); + /** Adds implicit table functions to a builder. */ protected abstract void addImplicitTablesBasedOnNullaryFunctionsToBuilder( ImmutableSortedMap.Builder<String, Table> builder); @@ -158,6 +175,11 @@ public abstract class CalciteSchema { return new TableEntryImpl(this, name, table, ImmutableList.<String>of()); } + /** Creates a TableEntryImpl with no SQLs. */ + protected TypeEntryImpl typeEntry(String name, RelProtoDataType relProtoDataType) { + return new TypeEntryImpl(this, name, relProtoDataType); + } + /** Defines a table within this schema. */ public TableEntry add(String tableName, Table table) { return add(tableName, table, ImmutableList.<String>of()); @@ -172,6 +194,14 @@ public abstract class CalciteSchema { return entry; } + /** Defines a type within this schema. */ + public TypeEntry add(String name, RelProtoDataType type) { + final TypeEntry entry = + new TypeEntryImpl(this, name, type); + typeMap.put(name, entry); + return entry; + } + private FunctionEntry add(String name, Function function) { final FunctionEntryImpl entry = new FunctionEntryImpl(this, name, function); @@ -319,6 +349,27 @@ public abstract class CalciteSchema { return Compatible.INSTANCE.navigableSet(builder.build()); } + /** Returns the set of all types names. */ + public final NavigableSet<String> getTypeNames() { + final ImmutableSortedSet.Builder<String> builder = + new ImmutableSortedSet.Builder<>(NameSet.COMPARATOR); + // Add explicit types. + builder.addAll(typeMap.map().keySet()); + // Add implicit types. + addImplicitTypeNamesToBuilder(builder); + return Compatible.INSTANCE.navigableSet(builder.build()); + } + + /** Returns a type, explicit and implicit, with a given + * name. Never null. */ + public final TypeEntry getType(String name, boolean caseSensitive) { + for (Map.Entry<String, TypeEntry> entry + : typeMap.range(name, caseSensitive).entrySet()) { + return entry.getValue(); + } + return getImplicitType(name, caseSensitive); + } + /** Returns a collection of all functions, explicit and implicit, with a given * name. Never null. */ public final Collection<Function> getFunctions(String name, boolean caseSensitive) { @@ -481,6 +532,11 @@ public abstract class CalciteSchema { return true; } + @Experimental + public boolean removeType(String name) { + return typeMap.remove(name) != null; + } + /** * Entry in a schema, such as a table or sub-schema. * @@ -519,6 +575,15 @@ public abstract class CalciteSchema { public abstract Table getTable(); } + /** Membership of a type in a schema. */ + public abstract static class TypeEntry extends Entry { + public TypeEntry(CalciteSchema schema, String name) { + super(schema, name); + } + + public abstract RelProtoDataType getType(); + } + /** Membership of a function in a schema. */ public abstract static class FunctionEntry extends Entry { public FunctionEntry(CalciteSchema schema, String name) { @@ -587,6 +652,15 @@ public abstract class CalciteSchema { return CalciteSchema.this.getTableNames(); } + @Override public RelProtoDataType getType(String name) { + final TypeEntry entry = CalciteSchema.this.getType(name, true); + return entry == null ? null : entry.getType(); + } + + @Override public Set<String> getTypeNames() { + return CalciteSchema.this.getTypeNames(); + } + public Collection<Function> getFunctions(String name) { return CalciteSchema.this.getFunctions(name, true); } @@ -635,6 +709,10 @@ public abstract class CalciteSchema { CalciteSchema.this.add(name, function); } + public void add(String name, RelProtoDataType type) { + CalciteSchema.this.add(name, type); + } + public void add(String name, Lattice lattice) { CalciteSchema.this.add(name, lattice); } @@ -661,6 +739,24 @@ public abstract class CalciteSchema { } /** + * Implementation of {@link TypeEntry} + * where all properties are held in fields. + */ + public static class TypeEntryImpl extends TypeEntry { + private final RelProtoDataType protoDataType; + + /** Creates a TypeEntryImpl. */ + public TypeEntryImpl(CalciteSchema schema, String name, RelProtoDataType protoDataType) { + super(schema, name); + this.protoDataType = protoDataType; + } + + public RelProtoDataType getType() { + return protoDataType; + } + } + + /** * Implementation of {@link FunctionEntry} * where all properties are held in fields. */ http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/jdbc/SimpleCalciteSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/jdbc/SimpleCalciteSchema.java b/core/src/main/java/org/apache/calcite/jdbc/SimpleCalciteSchema.java index df004c7..15ede8b 100644 --- a/core/src/main/java/org/apache/calcite/jdbc/SimpleCalciteSchema.java +++ b/core/src/main/java/org/apache/calcite/jdbc/SimpleCalciteSchema.java @@ -16,6 +16,7 @@ */ package org.apache.calcite.jdbc; +import org.apache.calcite.rel.type.RelProtoDataType; import org.apache.calcite.schema.Function; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaVersion; @@ -42,16 +43,16 @@ class SimpleCalciteSchema extends CalciteSchema { * <p>Use {@link CalciteSchema#createRootSchema(boolean)} * or {@link #add(String, Schema)}. */ SimpleCalciteSchema(CalciteSchema parent, Schema schema, String name) { - this(parent, schema, name, null, null, null, null, null, null, null); + this(parent, schema, name, null, null, null, null, null, null, null, null); } private SimpleCalciteSchema(CalciteSchema parent, Schema schema, String name, NameMap<CalciteSchema> subSchemaMap, - NameMap<TableEntry> tableMap, NameMap<LatticeEntry> latticeMap, + NameMap<TableEntry> tableMap, NameMap<LatticeEntry> latticeMap, NameMap<TypeEntry> typeMap, NameMultimap<FunctionEntry> functionMap, NameSet functionNames, NameMap<FunctionEntry> nullaryFunctionMap, List<? extends List<String>> path) { - super(parent, schema, name, subSchemaMap, tableMap, latticeMap, + super(parent, schema, name, subSchemaMap, tableMap, latticeMap, typeMap, functionMap, functionNames, nullaryFunctionMap, path); } @@ -86,6 +87,15 @@ class SimpleCalciteSchema extends CalciteSchema { return null; } + protected TypeEntry getImplicitType(String name, boolean caseSensitive) { + // Check implicit types. + RelProtoDataType type = schema.getType(name); + if (type != null) { + return typeEntry(name, type); + } + return null; + } + protected void addImplicitSubSchemaToBuilder( ImmutableSortedMap.Builder<String, CalciteSchema> builder) { ImmutableSortedMap<String, CalciteSchema> explicitSubSchemas = builder.build(); @@ -119,6 +129,11 @@ class SimpleCalciteSchema extends CalciteSchema { builder.addAll(schema.getFunctionNames()); } + @Override protected void addImplicitTypeNamesToBuilder( + ImmutableSortedSet.Builder<String> builder) { + builder.addAll(schema.getTypeNames()); + } + protected void addImplicitTablesBasedOnNullaryFunctionsToBuilder( ImmutableSortedMap.Builder<String, Table> builder) { ImmutableSortedMap<String, Table> explicitTables = builder.build(); @@ -155,7 +170,7 @@ class SimpleCalciteSchema extends CalciteSchema { protected CalciteSchema snapshot(CalciteSchema parent, SchemaVersion version) { CalciteSchema snapshot = new SimpleCalciteSchema(parent, - schema.snapshot(version), name, null, tableMap, latticeMap, + schema.snapshot(version), name, null, tableMap, latticeMap, typeMap, functionMap, functionNames, nullaryFunctionMap, getPath()); for (CalciteSchema subSchema : subSchemaMap.map().values()) { CalciteSchema subSchemaSnapshot = subSchema.snapshot(snapshot, version); http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java b/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java index a7e8783..9e98606 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java +++ b/core/src/main/java/org/apache/calcite/model/JsonMapSchema.java @@ -34,6 +34,12 @@ public class JsonMapSchema extends JsonSchema { */ public final List<JsonTable> tables = new ArrayList<>(); + /** Types in this schema. + * + * <p>The list may be empty. + */ + public final List<JsonType> types = new ArrayList<>(); + /** Functions in this schema. * * <p>The list may be empty. @@ -52,6 +58,9 @@ public class JsonMapSchema extends JsonSchema { for (JsonFunction jsonFunction : functions) { jsonFunction.accept(modelHandler); } + for (JsonType jsonType : types) { + jsonType.accept(modelHandler); + } } } http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/model/JsonRoot.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/model/JsonRoot.java b/core/src/main/java/org/apache/calcite/model/JsonRoot.java index dfc517f..7d45013 100644 --- a/core/src/main/java/org/apache/calcite/model/JsonRoot.java +++ b/core/src/main/java/org/apache/calcite/model/JsonRoot.java @@ -31,6 +31,7 @@ import java.util.List; * <!-- CHECKSTYLE: OFF --> * <pre>{@code Root} * {@link JsonSchema} (in collection {@link JsonRoot#schemas schemas}) + * {@link JsonType} (in collection {@link JsonMapSchema#types types}) * {@link JsonTable} (in collection {@link JsonMapSchema#tables tables}) * {@link JsonColumn} (in collection {@link JsonTable#columns columns}) * {@link JsonStream} (in field {@link JsonTable#stream stream}) http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/model/JsonType.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/model/JsonType.java b/core/src/main/java/org/apache/calcite/model/JsonType.java new file mode 100644 index 0000000..08db52f --- /dev/null +++ b/core/src/main/java/org/apache/calcite/model/JsonType.java @@ -0,0 +1,49 @@ +/* + * 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.model; + +import java.util.ArrayList; +import java.util.List; + +/** + * Type schema element. + * + * <p>Occurs within {@link JsonMapSchema#tables}. + * + * @see JsonRoot Description of schema elements + */ +public class JsonType { + /** Name of this type. + * + * <p>Required. + */ + public String name; + + /** Type if this is not a struct. + */ + public String type; + + /** Definition of the attributes of this type. + */ + public final List<JsonTypeAttribute> attributes = new ArrayList<>(); + + public void accept(ModelHandler handler) { + handler.visit(this); + } +} + +// End JsonType.java http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/model/JsonTypeAttribute.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/model/JsonTypeAttribute.java b/core/src/main/java/org/apache/calcite/model/JsonTypeAttribute.java new file mode 100644 index 0000000..19ca36a --- /dev/null +++ b/core/src/main/java/org/apache/calcite/model/JsonTypeAttribute.java @@ -0,0 +1,36 @@ +/* + * 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.model; + +/** + * JSON object representing a type attribute. + */ +public class JsonTypeAttribute { + /** Name of this attribute. + * + * <p>Required. + */ + public String name; + + /** Type of this attribute. + * + * <p>Required. + */ + public String type; +} + +// End JsonTypeAttribute.java http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/model/ModelHandler.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/model/ModelHandler.java b/core/src/main/java/org/apache/calcite/model/ModelHandler.java index 2f2419d..1bcae90 100644 --- a/core/src/main/java/org/apache/calcite/model/ModelHandler.java +++ b/core/src/main/java/org/apache/calcite/model/ModelHandler.java @@ -21,6 +21,8 @@ import org.apache.calcite.avatica.AvaticaUtils; import org.apache.calcite.jdbc.CalciteConnection; import org.apache.calcite.jdbc.CalciteSchema; import org.apache.calcite.materialize.Lattice; +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.schema.AggregateFunction; import org.apache.calcite.schema.ScalarFunction; import org.apache.calcite.schema.Schema; @@ -38,6 +40,7 @@ import org.apache.calcite.schema.impl.TableFunctionImpl; import org.apache.calcite.schema.impl.TableMacroImpl; import org.apache.calcite.schema.impl.ViewTable; import org.apache.calcite.sql.SqlDialectFactory; +import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.util.Pair; import org.apache.calcite.util.Util; @@ -471,6 +474,33 @@ public class ModelHandler { return schema; } + public void visit(final JsonType jsonType) { + checkRequiredAttributes(jsonType, "name"); + try { + final SchemaPlus schema = currentMutableSchema("type"); + schema.add(jsonType.name, typeFactory -> { + if (jsonType.type != null) { + return typeFactory.createSqlType(SqlTypeName.get(jsonType.type)); + } else { + final RelDataTypeFactory.Builder builder = typeFactory.builder(); + for (JsonTypeAttribute jsonTypeAttribute : jsonType.attributes) { + final SqlTypeName typeName = + SqlTypeName.get(jsonTypeAttribute.type); + RelDataType type = typeFactory.createSqlType(typeName); + if (type == null) { + type = currentSchema().getType(jsonTypeAttribute.type) + .apply(typeFactory); + } + builder.add(jsonTypeAttribute.name, type); + } + return builder.build(); + } + }); + } catch (Exception e) { + throw new RuntimeException("Error instantiating " + jsonType, e); + } + } + public void visit(JsonFunction jsonFunction) { // "name" is not required - a class can have several functions checkRequiredAttributes(jsonFunction, "className"); @@ -478,11 +508,8 @@ public class ModelHandler { final SchemaPlus schema = currentMutableSchema("function"); final List<String> path = Util.first(jsonFunction.path, currentSchemaPath()); - create(schema, - jsonFunction.name, - path, - jsonFunction.className, - jsonFunction.methodName); + addFunctions(schema, jsonFunction.name, path, jsonFunction.className, + jsonFunction.methodName, false); } catch (Exception e) { throw new RuntimeException("Error instantiating " + jsonFunction, e); } http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java index 4dc8be7..c49a9cb 100644 --- a/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java +++ b/core/src/main/java/org/apache/calcite/prepare/CalciteCatalogReader.java @@ -173,7 +173,12 @@ public class CalciteCatalogReader implements Prepare.CatalogReader { } public RelDataType getNamedType(SqlIdentifier typeName) { - return null; + CalciteSchema.TypeEntry typeEntry = SqlValidatorUtil.getTypeEntry(getRootSchema(), typeName); + if (typeEntry != null) { + return typeEntry.getType().apply(typeFactory); + } else { + return null; + } } public List<SqlMoniker> getAllSchemaObjectNames(List<String> names) { http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java index 8ed16aa..81d84ad 100644 --- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java +++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java @@ -33,6 +33,7 @@ import org.apache.calcite.rel.logical.LogicalTableScan; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rel.type.RelDataTypeField; +import org.apache.calcite.rel.type.RelProtoDataType; import org.apache.calcite.rel.type.RelRecordType; import org.apache.calcite.runtime.Hook; import org.apache.calcite.schema.ColumnStrategy; @@ -468,6 +469,10 @@ public class RelOptTableImpl extends Prepare.AbstractPreparingTable { throw new UnsupportedOperationException(); } + @Override public void add(String name, RelProtoDataType type) { + throw new UnsupportedOperationException(); + } + @Override public void add(String name, Lattice lattice) { throw new UnsupportedOperationException(); } @@ -500,6 +505,14 @@ public class RelOptTableImpl extends Prepare.AbstractPreparingTable { return schema.getTableNames(); } + @Override public RelProtoDataType getType(String name) { + return schema.getType(name); + } + + @Override public Set<String> getTypeNames() { + return schema.getTypeNames(); + } + @Override public Collection<org.apache.calcite.schema.Function> getFunctions(String name) { return schema.getFunctions(name); http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java index f122076..48079eb 100644 --- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java +++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java @@ -751,6 +751,9 @@ public interface CalciteResource { @BaseMessage("View ''{0}'' not found") ExInst<SqlValidatorException> viewNotFound(String name); + + @BaseMessage("Type ''{0}'' not found") + ExInst<SqlValidatorException> typeNotFound(String name); } // End CalciteResource.java http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/schema/Schema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/schema/Schema.java b/core/src/main/java/org/apache/calcite/schema/Schema.java index 312ab58..05843dc 100644 --- a/core/src/main/java/org/apache/calcite/schema/Schema.java +++ b/core/src/main/java/org/apache/calcite/schema/Schema.java @@ -17,6 +17,7 @@ package org.apache.calcite.schema; import org.apache.calcite.linq4j.tree.Expression; +import org.apache.calcite.rel.type.RelProtoDataType; import java.util.Collection; import java.util.Set; @@ -69,6 +70,21 @@ public interface Schema { Set<String> getTableNames(); /** + * Returns a type with a given name, or null if not found. + * + * @param name Table name + * @return Table, or null + */ + RelProtoDataType getType(String name); + + /** + * Returns the names of the types in this schema. + * + * @return Names of the tables in this schema + */ + Set<String> getTypeNames(); + + /** * Returns a list of functions in this schema with the given name, or * an empty list if there is no such function. * http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/schema/SchemaPlus.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/schema/SchemaPlus.java b/core/src/main/java/org/apache/calcite/schema/SchemaPlus.java index 27576ca..a6e0bdd 100644 --- a/core/src/main/java/org/apache/calcite/schema/SchemaPlus.java +++ b/core/src/main/java/org/apache/calcite/schema/SchemaPlus.java @@ -17,6 +17,7 @@ package org.apache.calcite.schema; import org.apache.calcite.materialize.Lattice; +import org.apache.calcite.rel.type.RelProtoDataType; import org.apache.calcite.util.Bug; import com.google.common.collect.ImmutableList; @@ -73,6 +74,9 @@ public interface SchemaPlus extends Schema { /** Adds a function to this schema. */ void add(String name, Function function); + /** Adds a type to this schema. */ + void add(String name, RelProtoDataType type); + /** Adds a lattice to this schema. */ void add(String name, Lattice lattice); http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/schema/impl/AbstractSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/schema/impl/AbstractSchema.java b/core/src/main/java/org/apache/calcite/schema/impl/AbstractSchema.java index 129d3dd..dc8c25e 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/AbstractSchema.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/AbstractSchema.java @@ -17,6 +17,7 @@ package org.apache.calcite.schema.impl; import org.apache.calcite.linq4j.tree.Expression; +import org.apache.calcite.rel.type.RelProtoDataType; import org.apache.calcite.schema.Function; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaFactory; @@ -93,6 +94,28 @@ public class AbstractSchema implements Schema { } /** + * Returns a map of types in this schema by name. + * + * <p>The implementations of {@link #getTypeNames()} + * and {@link #getType(String)} depend on this map. + * The default implementation of this method returns the empty map. + * Override this method to change their behavior.</p> + * + * @return Map of types in this schema by name + */ + protected Map<String, RelProtoDataType> getTypeMap() { + return ImmutableMap.of(); + } + + public RelProtoDataType getType(String name) { + return getTypeMap().get(name); + } + + public Set<String> getTypeNames() { + return getTypeMap().keySet(); + } + + /** * Returns a multi-map of functions in this schema by name. * It is a multi-map because functions are overloaded; there may be more than * one function in a schema with a given name (as long as they have different http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/schema/impl/DelegatingSchema.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/schema/impl/DelegatingSchema.java b/core/src/main/java/org/apache/calcite/schema/impl/DelegatingSchema.java index e222100..7c8bb96 100644 --- a/core/src/main/java/org/apache/calcite/schema/impl/DelegatingSchema.java +++ b/core/src/main/java/org/apache/calcite/schema/impl/DelegatingSchema.java @@ -17,6 +17,7 @@ package org.apache.calcite.schema.impl; import org.apache.calcite.linq4j.tree.Expression; +import org.apache.calcite.rel.type.RelProtoDataType; import org.apache.calcite.schema.Function; import org.apache.calcite.schema.Schema; import org.apache.calcite.schema.SchemaPlus; @@ -66,6 +67,14 @@ public class DelegatingSchema implements Schema { return schema.getTableNames(); } + public RelProtoDataType getType(String name) { + return schema.getType(name); + } + + public Set<String> getTypeNames() { + return schema.getTypeNames(); + } + public Collection<Function> getFunctions(String name) { return schema.getFunctions(name); } http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java index 7c4e2cb..cb921a4 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java @@ -59,6 +59,7 @@ public class SqlDataTypeSpec extends SqlNode { private final SqlIdentifier collectionsTypeName; private final SqlIdentifier typeName; + private final SqlIdentifier baseTypeName; private final int scale; private final int precision; private final String charSetName; @@ -101,11 +102,28 @@ public class SqlDataTypeSpec extends SqlNode { } /** + * Creates a type specification that has no base type. + */ + public SqlDataTypeSpec( + SqlIdentifier collectionsTypeName, + SqlIdentifier typeName, + int precision, + int scale, + String charSetName, + TimeZone timeZone, + Boolean nullable, + SqlParserPos pos) { + this(collectionsTypeName, typeName, typeName, precision, scale, charSetName, + timeZone, nullable, pos); + } + + /** * Creates a type specification. */ public SqlDataTypeSpec( SqlIdentifier collectionsTypeName, SqlIdentifier typeName, + SqlIdentifier baseTypeName, int precision, int scale, String charSetName, @@ -115,6 +133,7 @@ public class SqlDataTypeSpec extends SqlNode { super(pos); this.collectionsTypeName = collectionsTypeName; this.typeName = typeName; + this.baseTypeName = baseTypeName; this.precision = precision; this.scale = scale; this.charSetName = charSetName; @@ -268,27 +287,26 @@ public class SqlDataTypeSpec extends SqlNode { } /** - * Throws an error if the type is not built-in. + * Throws an error if the type is not found. */ public RelDataType deriveType(SqlValidator validator) { - String name = typeName.getSimple(); + RelDataType type = null; + if (typeName.isSimple()) { + if (null != collectionsTypeName) { + final String collectionName = collectionsTypeName.getSimple(); + if (SqlTypeName.get(collectionName) == null) { + throw validator.newValidationError(this, + RESOURCE.unknownDatatypeName(collectionName)); + } + } - // for now we only support builtin datatypes - if (SqlTypeName.get(name) == null) { - throw validator.newValidationError(this, - RESOURCE.unknownDatatypeName(name)); + RelDataTypeFactory typeFactory = validator.getTypeFactory(); + type = deriveType(typeFactory); } - - if (null != collectionsTypeName) { - final String collectionName = collectionsTypeName.getSimple(); - if (SqlTypeName.get(collectionName) == null) { - throw validator.newValidationError(this, - RESOURCE.unknownDatatypeName(collectionName)); - } + if (type == null) { + type = validator.getValidatedNodeType(typeName); } - - RelDataTypeFactory typeFactory = validator.getTypeFactory(); - return deriveType(typeFactory); + return type; } /** @@ -308,9 +326,14 @@ public class SqlDataTypeSpec extends SqlNode { */ public RelDataType deriveType(RelDataTypeFactory typeFactory, boolean nullable) { + if (!typeName.isSimple()) { + return null; + } final String name = typeName.getSimple(); - final SqlTypeName sqlTypeName = - Preconditions.checkNotNull(SqlTypeName.get(name)); + final SqlTypeName sqlTypeName = SqlTypeName.get(name); + if (sqlTypeName == null) { + return null; + } // NOTE jvs 15-Jan-2009: earlier validation is supposed to // have caught these, which is why it's OK for them http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/sql/SqlKind.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java index 76d7f3c..a2cb6d0 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java @@ -941,6 +941,9 @@ public enum SqlKind { /** Column declaration. */ COLUMN_DECL, + /** Attribute definition. */ + ATTRIBUTE_DEF, + /** {@code CHECK} constraint. */ CHECK, @@ -1019,6 +1022,12 @@ public enum SqlKind { /** {@code DROP INDEX} DDL statement. */ DROP_INDEX, + /** {@code CREATE TYPE} DDL statement. */ + CREATE_TYPE, + + /** {@code DROP TYPE} DDL statement. */ + DROP_TYPE, + /** DDL statement not handled above. * * <p><b>Note to other projects</b>: If you are extending Calcite's SQL parser @@ -1085,6 +1094,7 @@ public enum SqlKind { DROP_MATERIALIZED_VIEW, CREATE_SEQUENCE, ALTER_SEQUENCE, DROP_SEQUENCE, CREATE_INDEX, ALTER_INDEX, DROP_INDEX, + CREATE_TYPE, DROP_TYPE, SET_OPTION, OTHER_DDL); /** http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java index 9c2170e..d80ba61 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java @@ -1545,6 +1545,9 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { if (original != null && original != node) { return getValidatedNodeType(original); } + if (node instanceof SqlIdentifier) { + return getCatalogReader().getNamedType((SqlIdentifier) node); + } return null; } http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java index 394e353..d4c082d 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorUtil.java @@ -951,6 +951,37 @@ public class SqlValidatorUtil { } /** + * Finds a {@link org.apache.calcite.jdbc.CalciteSchema.TypeEntry} in a + * given schema whose type has the given name, possibly qualified. + * + * @param rootSchema root schema + * @param typeName name of the type, may be qualified or fully-qualified + * + * @return TypeEntry with a table with the given name, or null + */ + public static CalciteSchema.TypeEntry getTypeEntry( + CalciteSchema rootSchema, SqlIdentifier typeName) { + final String name; + final List<String> path; + if (typeName.isSimple()) { + path = ImmutableList.of(); + name = typeName.getSimple(); + } else { + path = Util.skipLast(typeName.names); + name = Util.last(typeName.names); + } + CalciteSchema schema = rootSchema; + for (String p : path) { + if (schema == rootSchema + && SqlNameMatchers.withCaseSensitive(true).matches(p, schema.getName())) { + continue; + } + schema = schema.getSubSchema(p, true); + } + return schema == null ? null : schema.getType(name, false); + } + + /** * Finds a {@link org.apache.calcite.jdbc.CalciteSchema.TableEntry} in a * given catalog reader whose table has the given name, possibly qualified. * http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java index fe92d4b..8c7ffc1 100644 --- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java +++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java @@ -572,6 +572,9 @@ public class StandardConvertletTable extends ReflectiveConvertletTable { } RexNode arg = cx.convertExpression(left); RelDataType type = dataType.deriveType(typeFactory); + if (type == null) { + type = cx.getValidator().getValidatedNodeType(dataType.getTypeName()); + } if (arg.getType().isNullable()) { type = typeFactory.createTypeWithNullability(type, true); } http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/java/org/apache/calcite/util/Util.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/util/Util.java b/core/src/main/java/org/apache/calcite/util/Util.java index 201fe2b..64ab61f 100644 --- a/core/src/main/java/org/apache/calcite/util/Util.java +++ b/core/src/main/java/org/apache/calcite/util/Util.java @@ -158,7 +158,6 @@ public class Util { }); //~ Methods ---------------------------------------------------------------- - /** * Does nothing with its argument. Returns whether it is ensured that * the call produces a single value http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties ---------------------------------------------------------------------- diff --git a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties index 5a0f888..d1ea199 100644 --- a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties +++ b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties @@ -244,4 +244,5 @@ CreateTableRequiresColumnTypes=Type required for column ''{0}'' in CREATE TABLE ViewExists=View ''{0}'' already exists and REPLACE not specified SchemaNotFound=Schema ''{0}'' not found ViewNotFound=View ''{0}'' not found +TypeNotFound=Type ''{0}'' not found # End CalciteResource.properties http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/test/java/org/apache/calcite/test/CalciteSuite.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java b/core/src/test/java/org/apache/calcite/test/CalciteSuite.java index 585e8ed..a1d87a2 100644 --- a/core/src/test/java/org/apache/calcite/test/CalciteSuite.java +++ b/core/src/test/java/org/apache/calcite/test/CalciteSuite.java @@ -147,6 +147,7 @@ import org.junit.runners.Suite; // slow tests (above 1s) UdfTest.class, + UdtTest.class, TableFunctionTest.class, PlannerTest.class, RelBuilderTest.class, http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java index e179d05..df1bffe 100644 --- a/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java +++ b/core/src/test/java/org/apache/calcite/test/MockCatalogReader.java @@ -177,6 +177,11 @@ public class MockCatalogReader extends CalciteCatalogReader { final InitializerExpressionFactory countingInitializerExpressionFactory = new CountingFactory(ImmutableList.of("DEPTNO")); + registerType( + ImmutableList.of(salesSchema.getCatalogName(), salesSchema.getName(), + "customBigInt"), + typeFactory -> typeFactory.createSqlType(SqlTypeName.BIGINT)); + // Register "EMP" table. final MockTable empTable = MockTable.create(this, salesSchema, "EMP", false, 14, null, @@ -621,6 +626,14 @@ public class MockCatalogReader extends CalciteCatalogReader { //~ Methods ---------------------------------------------------------------- + protected void registerType(final List<String> names, final RelProtoDataType relProtoDataType) { + assert names.get(0).equals(DEFAULT_CATALOG); + final List<String> schemaPath = Util.skipLast(names); + final CalciteSchema schema = SqlValidatorUtil.getSchema(rootSchema, + schemaPath, SqlNameMatchers.withCaseSensitive(true)); + schema.add(Util.last(names), relProtoDataType); + } + protected void registerTable(final MockTable table) { table.onRegister(typeFactory); final WrapperTable wrapperTable = new WrapperTable(table); @@ -658,7 +671,7 @@ public class MockCatalogReader extends CalciteCatalogReader { if (typeName.equalsDeep(addressType.getSqlIdentifier(), Litmus.IGNORE)) { return addressType; } else { - return null; + return super.getNamedType(typeName); } } http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/test/java/org/apache/calcite/test/ModelTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/ModelTest.java b/core/src/test/java/org/apache/calcite/test/ModelTest.java index 35e78fb..158527d 100644 --- a/core/src/test/java/org/apache/calcite/test/ModelTest.java +++ b/core/src/test/java/org/apache/calcite/test/ModelTest.java @@ -24,6 +24,7 @@ import org.apache.calcite.model.JsonLattice; import org.apache.calcite.model.JsonMapSchema; import org.apache.calcite.model.JsonRoot; import org.apache.calcite.model.JsonTable; +import org.apache.calcite.model.JsonTypeAttribute; import org.apache.calcite.model.JsonView; import com.fasterxml.jackson.core.JsonParser; @@ -61,6 +62,17 @@ public class ModelTest { + " schemas: [\n" + " {\n" + " name: 'FoodMart',\n" + + " types: [\n" + + " {\n" + + " name: 'mytype1',\n" + + " attributes: [\n" + + " {\n" + + " name: 'f1',\n" + + " type: 'BIGINT'\n" + + " }\n" + + " ]\n" + + " }\n" + + " ],\n" + " tables: [\n" + " {\n" + " name: 'time_by_day',\n" @@ -87,6 +99,10 @@ public class ModelTest { assertEquals(1, root.schemas.size()); final JsonMapSchema schema = (JsonMapSchema) root.schemas.get(0); assertEquals("FoodMart", schema.name); + assertEquals(1, schema.types.size()); + final List<JsonTypeAttribute> attributes = schema.types.get(0).attributes; + assertEquals("f1", attributes.get(0).name); + assertEquals("BIGINT", attributes.get(0).type); assertEquals(2, schema.tables.size()); final JsonTable table0 = schema.tables.get(0); assertEquals("time_by_day", table0.name); http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java index 32c50e2..7fa1026 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java @@ -955,10 +955,17 @@ public class SqlValidatorTest extends SqlValidatorTestCase { "INTEGER NOT NULL MULTISET NOT NULL"); } + @Test public void testCastRegisteredType() { + checkExpFails("cast(123 as customBigInt)", + "class org.apache.calcite.sql.SqlIdentifier: CUSTOMBIGINT"); + checkExpType("cast(123 as sales.customBigInt)", "BIGINT NOT NULL"); + checkExpType("cast(123 as catalog.sales.customBigInt)", "BIGINT NOT NULL"); + } + @Test public void testCastFails() { checkExpFails( "cast('foo' as ^bar^)", - "(?s).*Unknown datatype name 'BAR'"); + "class org.apache.calcite.sql.SqlIdentifier: BAR"); checkWholeExpFails( "cast(multiset[1] as integer)", "(?s).*Cast function cannot convert value of type INTEGER MULTISET to type INTEGER"); http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java index 554c184..77e8753 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTestCase.java @@ -334,6 +334,10 @@ public class SqlValidatorTestCase { if (matcher.matches()) { actualLine = Integer.parseInt(matcher.group(1)); actualColumn = Integer.parseInt(matcher.group(2)); + } else { + if (actualMessage.toString().matches(expectedMsgPattern)) { + return; + } } } } http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/core/src/test/java/org/apache/calcite/test/UdtTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/UdtTest.java b/core/src/test/java/org/apache/calcite/test/UdtTest.java new file mode 100644 index 0000000..8741844 --- /dev/null +++ b/core/src/test/java/org/apache/calcite/test/UdtTest.java @@ -0,0 +1,63 @@ +/* + * 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.test; + +import org.junit.Test; + +/** + * Tests for user-defined types. + */ +public class UdtTest { + private CalciteAssert.AssertThat withUdt() { + final String model = "{\n" + + " version: '1.0',\n" + + " schemas: [\n" + + " {\n" + + " name: 'adhoc',\n" + + " types: [\n" + + " {\n" + + " name: 'mytype1',\n" + + " type: 'BIGINT'\n" + + " },\n" + + " {\n" + + " name: 'mytype2',\n" + + " attributes: [\n" + + " {\n" + + " name: 'ii',\n" + + " type: 'INTEGER'\n" + + " },\n" + + " {\n" + + " name: 'jj',\n" + + " type: 'INTEGER'\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}"; + return CalciteAssert.model(model); + } + + @Test public void testUdt() { + final String sql = "select CAST(\"id\" AS \"adhoc\".mytype1) as ld " + + "from (VALUES ROW(1, 'SameName')) AS \"t\" (\"id\", \"desc\")"; + withUdt().query(sql).returns("LD=1\n"); + } +} + +// End UdtTest.java http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/main/codegen/config.fmpp ---------------------------------------------------------------------- diff --git a/server/src/main/codegen/config.fmpp b/server/src/main/codegen/config.fmpp index 08b715a..34fe90c 100644 --- a/server/src/main/codegen/config.fmpp +++ b/server/src/main/codegen/config.fmpp @@ -68,6 +68,7 @@ data: { "SqlCreateMaterializedView" "SqlCreateSchema" "SqlCreateTable" + "SqlCreateType" "SqlCreateView" ] @@ -77,6 +78,7 @@ data: { "SqlDropMaterializedView" "SqlDropSchema" "SqlDropTable" + "SqlDropType" "SqlDropView" ] http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/main/codegen/includes/parserImpls.ftl ---------------------------------------------------------------------- diff --git a/server/src/main/codegen/includes/parserImpls.ftl b/server/src/main/codegen/includes/parserImpls.ftl index 9c54540..0fd9b87 100644 --- a/server/src/main/codegen/includes/parserImpls.ftl +++ b/server/src/main/codegen/includes/parserImpls.ftl @@ -191,6 +191,69 @@ void TableElement(List<SqlNode> list) : ) } +SqlNodeList AttributeDefList() : +{ + final Span s; + final List<SqlNode> list = Lists.newArrayList(); +} +{ + <LPAREN> { s = span(); } + AttributeDef(list) + ( + <COMMA> AttributeDef(list) + )* + <RPAREN> { + return new SqlNodeList(list, s.end(this)); + } +} + +void AttributeDef(List<SqlNode> list) : +{ + final SqlIdentifier id; + final SqlDataTypeSpec type; + final boolean nullable; + SqlNode e = null; + final Span s = Span.of(); +} +{ + id = SimpleIdentifier() + ( + type = DataType() + ( + <NULL> { nullable = true; } + | + <NOT> <NULL> { nullable = false; } + | + { nullable = true; } + ) + ) + [ <DEFAULT_> e = Expression(ExprContext.ACCEPT_SUB_QUERY) ] + { + list.add(SqlDdlNodes.attribute(s.add(id).end(this), id, + type.withNullable(nullable), e, null)); + } +} + +SqlCreate SqlCreateType(Span s, boolean replace) : +{ + final SqlIdentifier id; + SqlNodeList attributeDefList = null; + SqlDataTypeSpec type = null; +} +{ + <TYPE> + id = CompoundIdentifier() + <AS> + ( + attributeDefList = AttributeDefList() + | + type = DataType() + ) + { + return SqlDdlNodes.createType(s.end(this), replace, id, attributeDefList, type); + } +} + SqlCreate SqlCreateTable(Span s, boolean replace) : { final boolean ifNotExists; @@ -257,6 +320,17 @@ SqlDrop SqlDropSchema(Span s, boolean replace) : } } +SqlDrop SqlDropType(Span s, boolean replace) : +{ + final boolean ifExists; + final SqlIdentifier id; +} +{ + <TYPE> ifExists = IfExistsOpt() id = CompoundIdentifier() { + return SqlDdlNodes.dropType(s.end(this), ifExists, id); + } +} + SqlDrop SqlDropTable(Span s, boolean replace) : { final boolean ifExists; http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java ---------------------------------------------------------------------- diff --git a/server/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java b/server/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java new file mode 100644 index 0000000..1e519ec --- /dev/null +++ b/server/src/main/java/org/apache/calcite/sql/ddl/SqlAttributeDefinition.java @@ -0,0 +1,93 @@ +/* + * 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.ddl; + +import org.apache.calcite.sql.SqlCall; +import org.apache.calcite.sql.SqlCollation; +import org.apache.calcite.sql.SqlDataTypeSpec; +import org.apache.calcite.sql.SqlIdentifier; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.sql.SqlOperator; +import org.apache.calcite.sql.SqlSpecialOperator; +import org.apache.calcite.sql.SqlWriter; +import org.apache.calcite.sql.parser.SqlParserPos; + +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * Parse tree for SqlAttributeDefinition, + * which is part of a {@link SqlCreateType}. + */ +public class SqlAttributeDefinition extends SqlCall { + private static final SqlSpecialOperator OPERATOR = + new SqlSpecialOperator("ATTRIBUTE_DEF", SqlKind.ATTRIBUTE_DEF); + + final SqlIdentifier name; + final SqlDataTypeSpec dataType; + final SqlNode expression; + final SqlCollation collation; + + /** Creates a SqlAttributeDefinition; use {@link SqlDdlNodes#attribute}. */ + SqlAttributeDefinition(SqlParserPos pos, SqlIdentifier name, + SqlDataTypeSpec dataType, SqlNode expression, SqlCollation collation) { + super(pos); + this.name = name; + this.dataType = dataType; + this.expression = expression; + this.collation = collation; + } + + @Override public SqlOperator getOperator() { + return OPERATOR; + } + + @Override public List<SqlNode> getOperandList() { + return ImmutableList.of(name, dataType); + } + + @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) { + name.unparse(writer, 0, 0); + dataType.unparse(writer, 0, 0); + if (collation != null) { + writer.keyword("COLLATE"); + collation.unparse(writer, 0, 0); + } + if (dataType.getNullable() != null && !dataType.getNullable()) { + writer.keyword("NOT NULL"); + } + if (expression != null) { + writer.keyword("DEFAULT"); + exp(writer); + } + } + + // TODO: refactor this to a util class to share with SqlColumnDeclaration + private void exp(SqlWriter writer) { + if (writer.isAlwaysUseParentheses()) { + expression.unparse(writer, 0, 0); + } else { + writer.sep("("); + expression.unparse(writer, 0, 0); + writer.sep(")"); + } + } +} + +// End SqlAttributeDefinition.java http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java ---------------------------------------------------------------------- diff --git a/server/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java b/server/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java index 22cc2d3..5ae3669 100644 --- a/server/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java +++ b/server/src/main/java/org/apache/calcite/sql/ddl/SqlCreateTable.java @@ -166,7 +166,15 @@ public class SqlCreateTable extends SqlCreate for (Ord<SqlNode> c : Ord.zip(columnList)) { if (c.e instanceof SqlColumnDeclaration) { final SqlColumnDeclaration d = (SqlColumnDeclaration) c.e; - final RelDataType type = d.dataType.deriveType(typeFactory, true); + RelDataType type = d.dataType.deriveType(typeFactory, true); + final Pair<CalciteSchema, String> pairForType = + SqlDdlNodes.schema(context, true, d.dataType.getTypeName()); + if (type == null) { + CalciteSchema.TypeEntry typeEntry = pairForType.left.getType(pairForType.right, false); + if (typeEntry != null) { + type = typeEntry.getType().apply(typeFactory); + } + } builder.add(d.name.getSimple(), type); if (d.strategy != ColumnStrategy.VIRTUAL) { storedBuilder.add(d.name.getSimple(), type); http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java ---------------------------------------------------------------------- diff --git a/server/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java b/server/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java new file mode 100644 index 0000000..c6d7991 --- /dev/null +++ b/server/src/main/java/org/apache/calcite/sql/ddl/SqlCreateType.java @@ -0,0 +1,114 @@ +/* + * 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.ddl; + +import org.apache.calcite.jdbc.CalcitePrepare; +import org.apache.calcite.jdbc.CalciteSchema; +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.rel.type.RelDataTypeFactory; +import org.apache.calcite.sql.SqlCreate; +import org.apache.calcite.sql.SqlDataTypeSpec; +import org.apache.calcite.sql.SqlExecutableStatement; +import org.apache.calcite.sql.SqlIdentifier; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.sql.SqlNodeList; +import org.apache.calcite.sql.SqlOperator; +import org.apache.calcite.sql.SqlSpecialOperator; +import org.apache.calcite.sql.SqlWriter; +import org.apache.calcite.sql.parser.SqlParserPos; +import org.apache.calcite.util.ImmutableNullableList; +import org.apache.calcite.util.Pair; + +import com.google.common.base.Preconditions; + +import java.util.List; + +/** + * Parse tree for {@code CREATE TYPE} statement. + */ +public class SqlCreateType extends SqlCreate + implements SqlExecutableStatement { + private final SqlIdentifier name; + private final SqlNodeList attributeDefs; + private final SqlDataTypeSpec dataType; + + private static final SqlOperator OPERATOR = + new SqlSpecialOperator("CREATE TYPE", SqlKind.CREATE_TYPE); + + /** Creates a SqlCreateType. */ + SqlCreateType(SqlParserPos pos, boolean replace, SqlIdentifier name, + SqlNodeList attributeDefs, SqlDataTypeSpec dataType) { + super(OPERATOR, pos, replace, false); + this.name = Preconditions.checkNotNull(name); + this.attributeDefs = attributeDefs; // may be null + this.dataType = dataType; // may be null + } + + @Override public void execute(CalcitePrepare.Context context) { + final Pair<CalciteSchema, String> pair = + SqlDdlNodes.schema(context, true, name); + pair.left.add(pair.right, typeFactory -> { + if (dataType != null) { + return dataType.deriveType(typeFactory); + } else { + final RelDataTypeFactory.Builder builder = typeFactory.builder(); + for (SqlNode def : attributeDefs) { + final SqlAttributeDefinition attributeDef = + (SqlAttributeDefinition) def; + final SqlDataTypeSpec typeSpec = attributeDef.dataType; + RelDataType type = typeSpec.deriveType(typeFactory); + if (type == null) { + Pair<CalciteSchema, String> pair1 = + SqlDdlNodes.schema(context, false, typeSpec.getTypeName()); + type = pair1.left.getType(pair1.right, false).getType() + .apply(typeFactory); + } + builder.add(attributeDef.name.getSimple(), type); + } + return builder.build(); + } + }); + } + + @Override public List<SqlNode> getOperandList() { + return ImmutableNullableList.of(name, attributeDefs); + } + + @Override public void unparse(SqlWriter writer, int leftPrec, int rightPrec) { + if (getReplace()) { + writer.keyword("CREATE OR REPLACE"); + } else { + writer.keyword("CREATE"); + } + writer.keyword("TYPE"); + name.unparse(writer, leftPrec, rightPrec); + writer.keyword("AS"); + if (attributeDefs != null) { + SqlWriter.Frame frame = writer.startList("(", ")"); + for (SqlNode a : attributeDefs) { + writer.sep(","); + a.unparse(writer, 0, 0); + } + writer.endList(frame); + } else if (dataType != null) { + dataType.unparse(writer, leftPrec, rightPrec); + } + } +} + +// End SqlCreateType.java http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/main/java/org/apache/calcite/sql/ddl/SqlDdlNodes.java ---------------------------------------------------------------------- diff --git a/server/src/main/java/org/apache/calcite/sql/ddl/SqlDdlNodes.java b/server/src/main/java/org/apache/calcite/sql/ddl/SqlDdlNodes.java index 057c2ee..d35e7cc 100644 --- a/server/src/main/java/org/apache/calcite/sql/ddl/SqlDdlNodes.java +++ b/server/src/main/java/org/apache/calcite/sql/ddl/SqlDdlNodes.java @@ -21,6 +21,7 @@ import org.apache.calcite.jdbc.CalciteSchema; import org.apache.calcite.rel.RelRoot; import org.apache.calcite.schema.ColumnStrategy; import org.apache.calcite.sql.SqlCall; +import org.apache.calcite.sql.SqlCollation; import org.apache.calcite.sql.SqlDataTypeSpec; import org.apache.calcite.sql.SqlDrop; import org.apache.calcite.sql.SqlIdentifier; @@ -69,6 +70,13 @@ public class SqlDdlNodes { library, optionList); } + /** Creates a CREATE TYPE. */ + public static SqlCreateType createType(SqlParserPos pos, boolean replace, + SqlIdentifier name, SqlNodeList attributeList, + SqlDataTypeSpec dataTypeSpec) { + return new SqlCreateType(pos, replace, name, attributeList, dataTypeSpec); + } + /** Creates a CREATE TABLE. */ public static SqlCreateTable createTable(SqlParserPos pos, boolean replace, boolean ifNotExists, SqlIdentifier name, SqlNodeList columnList, @@ -97,6 +105,12 @@ public class SqlDdlNodes { return new SqlDropSchema(pos, foreign, ifExists, name); } + /** Creates a DROP TYPE. */ + public static SqlDropType dropType(SqlParserPos pos, boolean ifExists, + SqlIdentifier name) { + return new SqlDropType(pos, ifExists, name); + } + /** Creates a DROP TABLE. */ public static SqlDropTable dropTable(SqlParserPos pos, boolean ifExists, SqlIdentifier name) { @@ -121,6 +135,12 @@ public class SqlDdlNodes { return new SqlColumnDeclaration(pos, name, dataType, expression, strategy); } + /** Creates a attribute definition. */ + public static SqlNode attribute(SqlParserPos pos, SqlIdentifier name, + SqlDataTypeSpec dataType, SqlNode expression, SqlCollation collation) { + return new SqlAttributeDefinition(pos, name, dataType, expression, collation); + } + /** Creates a CHECK constraint. */ public static SqlNode check(SqlParserPos pos, SqlIdentifier name, SqlNode expression) { http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/main/java/org/apache/calcite/sql/ddl/SqlDropObject.java ---------------------------------------------------------------------- diff --git a/server/src/main/java/org/apache/calcite/sql/ddl/SqlDropObject.java b/server/src/main/java/org/apache/calcite/sql/ddl/SqlDropObject.java index 81672f2..523c96e 100644 --- a/server/src/main/java/org/apache/calcite/sql/ddl/SqlDropObject.java +++ b/server/src/main/java/org/apache/calcite/sql/ddl/SqlDropObject.java @@ -34,8 +34,8 @@ import java.util.List; import static org.apache.calcite.util.Static.RESOURCE; /** - * Base class for parse trees of {@code DROP TABLE}, {@code DROP VIEW} and - * {@code DROP MATERIALIZED VIEW} statements. + * Base class for parse trees of {@code DROP TABLE}, {@code DROP VIEW}, + * {@code DROP MATERIALIZED VIEW} and {@code DROP TYPE} statements. */ abstract class SqlDropObject extends SqlDrop implements SqlExecutableStatement { @@ -84,6 +84,13 @@ abstract class SqlDropObject extends SqlDrop RESOURCE.viewNotFound(name.getSimple())); } break; + case DROP_TYPE: + existed = schema.removeType(name.getSimple()); + if (!existed && !ifExists) { + throw SqlUtil.newContextException(name.getParserPosition(), + RESOURCE.typeNotFound(name.getSimple())); + } + break; default: throw new AssertionError(getKind()); } http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/main/java/org/apache/calcite/sql/ddl/SqlDropType.java ---------------------------------------------------------------------- diff --git a/server/src/main/java/org/apache/calcite/sql/ddl/SqlDropType.java b/server/src/main/java/org/apache/calcite/sql/ddl/SqlDropType.java new file mode 100644 index 0000000..fcad768 --- /dev/null +++ b/server/src/main/java/org/apache/calcite/sql/ddl/SqlDropType.java @@ -0,0 +1,37 @@ +/* + * 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.ddl; + +import org.apache.calcite.sql.SqlIdentifier; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlOperator; +import org.apache.calcite.sql.SqlSpecialOperator; +import org.apache.calcite.sql.parser.SqlParserPos; + +/** + * Parse tree for {@code DROP TYPE} statement. + */ +public class SqlDropType extends SqlDropObject { + private static final SqlOperator OPERATOR = + new SqlSpecialOperator("DROP TYPE", SqlKind.DROP_TYPE); + + SqlDropType(SqlParserPos pos, boolean ifExists, SqlIdentifier name) { + super(OPERATOR, pos, ifExists, name); + } +} + +// End SqlDropType.java http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/test/java/org/apache/calcite/test/ServerParserTest.java ---------------------------------------------------------------------- diff --git a/server/src/test/java/org/apache/calcite/test/ServerParserTest.java b/server/src/test/java/org/apache/calcite/test/ServerParserTest.java index 8cdf336..3bb7c39 100644 --- a/server/src/test/java/org/apache/calcite/test/ServerParserTest.java +++ b/server/src/test/java/org/apache/calcite/test/ServerParserTest.java @@ -92,6 +92,21 @@ public class ServerParserTest extends SqlParserTest { sql(sql).ok(expected); } + @Test public void testCreateTypeWithAttributeList() { + sql("create type x.mytype1 as (i int not null, j varchar(5) null)") + .ok("CREATE TYPE `X`.`MYTYPE1` AS (`I` INTEGER NOT NULL, `J` VARCHAR(5))"); + } + + @Test public void testCreateTypeWithBaseType() { + sql("create type mytype1 as varchar(5)") + .ok("CREATE TYPE `MYTYPE1` AS VARCHAR(5)"); + } + + @Test public void testCreateOrReplaceTypeWith() { + sql("create or replace type mytype1 as varchar(5)") + .ok("CREATE OR REPLACE TYPE `MYTYPE1` AS VARCHAR(5)"); + } + @Test public void testCreateTable() { sql("create table x (i int not null, j varchar(5) null)") .ok("CREATE TABLE `X` (`I` INTEGER NOT NULL, `J` VARCHAR(5))"); @@ -210,6 +225,21 @@ public class ServerParserTest extends SqlParserTest { .ok("DROP FOREIGN SCHEMA `X`"); } + @Test public void testDropType() { + sql("drop type X") + .ok("DROP TYPE `X`"); + } + + @Test public void testDropTypeIfExists() { + sql("drop type if exists X") + .ok("DROP TYPE IF EXISTS `X`"); + } + + @Test public void testDropTypeTrailingIfExistsFails() { + sql("drop type X ^if^ exists") + .fails("(?s)Encountered \"if\" at.*"); + } + @Test public void testDropTable() { sql("drop table x") .ok("DROP TABLE `X`"); http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/test/java/org/apache/calcite/test/ServerTest.java ---------------------------------------------------------------------- diff --git a/server/src/test/java/org/apache/calcite/test/ServerTest.java b/server/src/test/java/org/apache/calcite/test/ServerTest.java index 92885ff..835c19a 100644 --- a/server/src/test/java/org/apache/calcite/test/ServerTest.java +++ b/server/src/test/java/org/apache/calcite/test/ServerTest.java @@ -20,7 +20,9 @@ import org.apache.calcite.config.CalciteConnectionProperty; import org.apache.calcite.sql.parser.ddl.SqlDdlParserImpl; import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import java.sql.Connection; import java.sql.DriverManager; @@ -43,6 +45,9 @@ public class ServerTest { static final String URL = "jdbc:calcite:"; + @Rule + public ExpectedException thrown = ExpectedException.none(); + static Connection connect() throws SQLException { return DriverManager.getConnection(URL, CalciteAssert.propBuilder() @@ -81,6 +86,45 @@ public class ServerTest { } } + @Test public void testCreateType() throws Exception { + try (Connection c = connect(); + Statement s = c.createStatement()) { + boolean b = s.execute("create type mytype1 as BIGINT"); + assertThat(b, is(false)); + b = s.execute("create or replace type mytype2 as (i int not null, jj mytype1)"); + assertThat(b, is(false)); + b = s.execute("create type mytype3 as (i int not null, jj mytype2)"); + assertThat(b, is(false)); + b = s.execute("create or replace type mytype1 as DOUBLE"); + assertThat(b, is(false)); + b = s.execute("create table t (c mytype1 NOT NULL)"); + assertThat(b, is(false)); + b = s.execute("create type mytype4 as BIGINT"); + assertThat(b, is(false)); + int x = s.executeUpdate("insert into t values 12.0"); + assertThat(x, is(1)); + x = s.executeUpdate("insert into t values 3.0"); + assertThat(x, is(1)); + try (ResultSet r = s.executeQuery("select CAST(c AS mytype4) from t")) { + assertThat(r.next(), is(true)); + assertThat(r.getInt(1), is(12)); + assertThat(r.next(), is(true)); + assertThat(r.getInt(1), is(3)); + assertThat(r.next(), is(false)); + } + } + } + + @Test public void testDropType() throws Exception { + try (Connection c = connect(); + Statement s = c.createStatement()) { + boolean b = s.execute("create type mytype1 as BIGINT"); + assertThat(b, is(false)); + b = s.execute("drop type mytype1"); + assertThat(b, is(false)); + } + } + @Test public void testCreateTable() throws Exception { try (Connection c = connect(); Statement s = c.createStatement()) { http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/server/src/test/resources/sql/type.iq ---------------------------------------------------------------------- diff --git a/server/src/test/resources/sql/type.iq b/server/src/test/resources/sql/type.iq new file mode 100644 index 0000000..64314e9 --- /dev/null +++ b/server/src/test/resources/sql/type.iq @@ -0,0 +1,57 @@ +# type.iq - Type DDL +# +# 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. +# +!use server +!set outputformat mysql + +create type myint1 as int; +(0 rows modified) + +!update + +# Create a basic table +create table t (i myint1 not null, j int not null); +(0 rows modified) + +!update + +select * from t; +I INTEGER(10) NOT NULL +J INTEGER(10) NOT NULL +!type + +insert into t values (1, 2); +(1 row modified) + +!update + +select * from t; ++---+---+ +| I | J | ++---+---+ +| 1 | 2 | ++---+---+ +(1 row) + +!ok + +drop table t; +(0 rows modified) + +!update + +# End type.iq http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/site/_docs/model.md ---------------------------------------------------------------------- diff --git a/site/_docs/model.md b/site/_docs/model.md index 2675453..0f646d0 100644 --- a/site/_docs/model.md +++ b/site/_docs/model.md @@ -102,7 +102,7 @@ A particular schema implementation can override the `Schema.contentsHaveChangedSince` method to tell Calcite when it should consider its cache to be out of date. -Tables, functions and sub-schemas explicitly created in a schema are +Tables, functions, types, and sub-schemas explicitly created in a schema are not affected by this caching mechanism. They always appear in the schema immediately, and are never flushed. @@ -115,7 +115,8 @@ Like base class <a href="#schema">Schema</a>, occurs within `root.schemas`. name: 'foodmart', type: 'map', tables: [ Table... ], - functions: [ Function... ] + functions: [ Function... ], + types: [ Type... ] } {% endhighlight %} @@ -128,6 +129,8 @@ defines the tables in this schema. `functions` (optional list of <a href="#function">Function</a> elements) defines the functions in this schema. +`types` defines the types in this schema. + ### Custom Schema Like base class <a href="#schema">Schema</a>, occurs within `root.schemas`. @@ -370,6 +373,31 @@ if found, creates an aggregate function. `path` (optional list of string) is the path for resolving this function. +### Type + +Occurs within `root.schemas.types`. + +{% highlight json %} +{ + name: 'mytype1', + type: 'BIGINT', + attributes: [ + { + name: 'f1', + type: 'BIGINT' + } + ] +} +{% endhighlight %} + +`name` (required string) is the name of this type. + +`type` (optional) is the SQL type. + +`attributes` (optional) is the attribute list of this type. +If `attributes` and `type` both exist at the same level, +`type` takes precedence. + ### Lattice Occurs within `root.schemas.lattices`. http://git-wip-us.apache.org/repos/asf/calcite/blob/570aca3d/site/_docs/reference.md ---------------------------------------------------------------------- diff --git a/site/_docs/reference.md b/site/_docs/reference.md index 9d77fe3..b210854 100644 --- a/site/_docs/reference.md +++ b/site/_docs/reference.md @@ -2087,11 +2087,13 @@ ddlStatement: | createTableStatement | createViewStatement | createMaterializedViewStatement + | createTypeStatement | dropSchemaStatement | dropForeignSchemaStatement | dropTableStatement | dropViewStatement | dropMaterializedViewStatement + | dropTypeStatement createSchemaStatement: CREATE [ OR REPLACE ] SCHEMA [ IF NOT EXISTS ] name @@ -2112,6 +2114,19 @@ createTableStatement: [ '(' tableElement [, tableElement ]* ')' ] [ AS query ] +createTypeStatement: + CREATE [ OR REPLACE ] TYPE name AS + { + baseType + | '(' attributeDef [, attributeDef ]* ')' + } + +attributeDef: + attributeName type + [ COLLATE collation ] + [ NULL | NOT NULL ] + [ DEFAULT expression ] + tableElement: columnName type [ columnGenerator ] [ columnConstraint ] | columnName @@ -2145,19 +2160,22 @@ createMaterializedViewStatement: AS query dropSchemaStatement: - DROP SCHEMA name [ IF EXISTS ] + DROP SCHEMA [ IF EXISTS ] name dropForeignSchemaStatement: - DROP FOREIGN SCHEMA name [ IF EXISTS ] + DROP FOREIGN SCHEMA [ IF EXISTS ] name dropTableStatement: - DROP TABLE name [ IF EXISTS ] + DROP TABLE [ IF EXISTS ] name dropViewStatement: - DROP VIEW name [ IF EXISTS ] + DROP VIEW [ IF EXISTS ] name dropMaterializedViewStatement: - DROP MATERIALIZED VIEW name [ IF EXISTS ] + DROP MATERIALIZED VIEW [ IF EXISTS ] name + +dropTypeStatement: + DROP TYPE [ IF EXISTS ] name {% endhighlight %} In *createTableStatement*, if you specify *AS query*, you may omit the list of
