diff --git a/src/Core/Settings.h b/src/Core/Settings.h index 61fcf658ba8..36d93f5814a 100644 --- a/src/Core/Settings.h +++ b/src/Core/Settings.h @@ -416,6 +416,8 @@ struct Settings : public SettingsCollection M(SettingBool, allow_nondeterministic_mutations, false, "Allow non-deterministic functions in ALTER UPDATE/ALTER DELETE statements", 0) \ M(SettingSeconds, lock_acquire_timeout, DBMS_DEFAULT_LOCK_ACQUIRE_TIMEOUT_SEC, "How long locking request should wait before failing", 0) \ \ + M(SettingBool, allow_experimental_geo_types, false, "Allow geo data types such as Point, Ring, Polygon, MultiPolygon", 0) \ + \ /** Obsolete settings that do nothing but left for compatibility reasons. Remove each one after half a year of obsolescence. */ \ \ M(SettingBool, allow_experimental_low_cardinality_type, true, "Obsolete setting, does nothing. Will be removed after 2019-08-13", 0) \ diff --git a/src/DataTypes/DataTypeCustomGeo.cpp b/src/DataTypes/DataTypeCustomGeo.cpp index d3d808a1b50..2f70e9f732a 100644 --- a/src/DataTypes/DataTypeCustomGeo.cpp +++ b/src/DataTypes/DataTypeCustomGeo.cpp @@ -19,62 +19,89 @@ private: DataTypePtr tuple; public: - DataTypeCustomPointSerialization() : tuple(std::make_unique( - DataTypes({std::make_unique(), std::make_unique()}))) + DataTypeCustomPointSerialization() {} void serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const override { - tuple->serializeAsText(column, row_num, ostr, settings); + nestedDataType()->serializeAsText(column, row_num, ostr, settings); } void deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const override { - tuple->deserializeAsWholeText(column, istr, settings); + nestedDataType()->deserializeAsWholeText(column, istr, settings); + } + + static DataTypePtr nestedDataType() { + static auto dataType = DataTypePtr(std::make_unique( + DataTypes({std::make_unique(), std::make_unique()}))); + return dataType; + } +}; + +class DataTypeCustomRingSerialization : public DataTypeCustomSimpleTextSerialization +{ +public: + DataTypeCustomRingSerialization() + {} + + void serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const override + { + nestedDataType()->serializeAsText(column, row_num, ostr, settings); + } + + void deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const override + { + nestedDataType()->deserializeAsWholeText(column, istr, settings); + } + + static DataTypePtr nestedDataType() { + static auto dataType = DataTypePtr(std::make_unique(DataTypeCustomPointSerialization::nestedDataType())); + return dataType; } }; class DataTypeCustomPolygonSerialization : public DataTypeCustomSimpleTextSerialization { -private: - DataTypePtr array; - public: - DataTypeCustomPolygonSerialization() : array(std::make_unique(std::make_unique(std::make_unique( - DataTypes({std::make_unique(), std::make_unique()}))))) + DataTypeCustomPolygonSerialization() {} void serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const override { - array->serializeAsText(column, row_num, ostr, settings); + nestedDataType()->serializeAsText(column, row_num, ostr, settings); } void deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const override { - array->deserializeAsWholeText(column, istr, settings); + nestedDataType()->deserializeAsWholeText(column, istr, settings); + } + + static DataTypePtr nestedDataType() { + static auto dataType = DataTypePtr(std::make_unique(DataTypeCustomRingSerialization::nestedDataType())); + return dataType; } }; class DataTypeCustomMultiPolygonSerialization : public DataTypeCustomSimpleTextSerialization { -private: - DataTypePtr array; - public: - DataTypeCustomMultiPolygonSerialization() : array( - std::make_unique(std::make_unique( - std::make_unique(std::make_unique( - DataTypes({std::make_unique(), std::make_unique()})))))) + DataTypeCustomMultiPolygonSerialization() {} void serializeText(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const override { - array->serializeAsText(column, row_num, ostr, settings); + nestedDataType()->serializeAsText(column, row_num, ostr, settings); } void deserializeText(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const override { - array->deserializeAsWholeText(column, istr, settings); + nestedDataType()->deserializeAsWholeText(column, istr, settings); + } + + static DataTypePtr nestedDataType() { + static auto dataType = DataTypePtr(std::make_unique(DataTypeCustomPolygonSerialization::nestedDataType())); + return dataType; } }; @@ -89,12 +116,18 @@ void registerDataTypeDomainGeo(DataTypeFactory & factory) std::make_unique(std::make_unique("Point"), std::make_unique())); }); - // Custom type for polygon with holes stored as Array(Array(Point)) - // Each element of outer array represents a simple polygon without holes stored as array of points + // Custom type for simple polygon without holes stored as Array(Point) + factory.registerSimpleDataTypeCustom("Ring", [] + { + return std::make_pair(DataTypeFactory::instance().get("Array(Point)"), + std::make_unique(std::make_unique("Ring"), std::make_unique())); + }); + + // Custom type for polygon with holes stored as Array(Ring) // First element of outer array is outer shape of polygon and all the following are holes factory.registerSimpleDataTypeCustom("Polygon", [] { - return std::make_pair(DataTypeFactory::instance().get("Array(Array(Point))"), + return std::make_pair(DataTypeFactory::instance().get("Array(Ring)"), std::make_unique(std::make_unique("Polygon"), std::make_unique())); }); diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index 43a0a7f608e..b9f11476edc 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -70,6 +70,7 @@ namespace ErrorCodes extern const int BAD_DATABASE_FOR_TEMPORARY_TABLE; extern const int SUSPICIOUS_TYPE_FOR_LOW_CARDINALITY; extern const int DICTIONARY_ALREADY_EXISTS; + extern const int ILLEGAL_COLUMN; } @@ -381,7 +382,6 @@ ConstraintsDescription InterpreterCreateQuery::getConstraintsDescription(const A return res; } - InterpreterCreateQuery::TableProperties InterpreterCreateQuery::setProperties(ASTCreateQuery & create) const { TableProperties properties; @@ -471,6 +471,21 @@ void InterpreterCreateQuery::validateTableStructure(const ASTCreateQuery & creat } } } + + if (!create.attach && !context.getSettingsRef().allow_experimental_geo_types) + { + for (const auto & name_and_type_pair : properties.columns.getAllPhysical()) + { + const auto& type = name_and_type_pair.type->getName(); + if (type == "MultiPolygon" || type == "Polygon" || type == "Ring" || type == "Point") + { + String message = "Cannot create table with column '" + name_and_type_pair.name + "' which type is '" + + type + "' because experimental geo types are not allowed. " + + "Set setting allow_experimental_geo_types = 1 in order to allow it."; + throw Exception(message, ErrorCodes::ILLEGAL_COLUMN); + } + } + } } void InterpreterCreateQuery::setEngine(ASTCreateQuery & create) const diff --git a/tests/queries/0_stateless/01291_geo_types.reference b/tests/queries/0_stateless/01291_geo_types.reference new file mode 100644 index 00000000000..baf7b25a231 --- /dev/null +++ b/tests/queries/0_stateless/01291_geo_types.reference @@ -0,0 +1 @@ +(0,0) [(0,0),(10,0),(10,10),(0,10)] [[(20,20),(50,20),(50,50),(20,50)],[(30,30),(50,50),(50,30)]] [[[(0,0),(10,0),(10,10),(0,10)]],[[(20,20),(50,20),(50,50),(20,50)],[(30,30),(50,50),(50,30)]]] diff --git a/tests/queries/0_stateless/01291_geo_types.sql b/tests/queries/0_stateless/01291_geo_types.sql new file mode 100644 index 00000000000..0d923f08ccd --- /dev/null +++ b/tests/queries/0_stateless/01291_geo_types.sql @@ -0,0 +1,9 @@ +DROP TABLE IF EXISTS geo; + +SET allow_experimental_geo_types = 1; + +CREATE TABLE geo (a Point, b Ring, c Polygon, d MultiPolygon) ENGINE=Memory(); + +INSERT INTO geo VALUES((0, 0), [(0, 0), (10, 0), (10, 10), (0, 10)], [[(20, 20), (50, 20), (50, 50), (20, 50)], [(30, 30), (50, 50), (50, 30)]], [[[(0, 0), (10, 0), (10, 10), (0, 10)]], [[(20, 20), (50, 20), (50, 50), (20, 50)],[(30, 30), (50, 50), (50, 30)]]]); + +SELECT * from geo;