diff --git a/deps/init/oceanbase.el7.aarch64.deps b/deps/init/oceanbase.el7.aarch64.deps index b85d29c9aa..f32950451c 100644 --- a/deps/init/oceanbase.el7.aarch64.deps +++ b/deps/init/oceanbase.el7.aarch64.deps @@ -30,6 +30,7 @@ devdeps-s2geometry-0.9.0-12023092021.el7.aarch64.rpm devdeps-icu-69.1-72022112416.el7.aarch64.rpm devdeps-cos-c-sdk-5.0.16-52023070517.el7.aarch64.rpm devdeps-s3-cpp-sdk-1.11.156-102023122011.el7.aarch64.rpm +devdeps-protobuf-c-1.4.1-100000072023102410.el7.aarch64.rpm [tools] obdevtools-binutils-2.30-12022100413.el7.aarch64.rpm diff --git a/deps/init/oceanbase.el7.x86_64.deps b/deps/init/oceanbase.el7.x86_64.deps index 961972bf90..f68e560f95 100644 --- a/deps/init/oceanbase.el7.x86_64.deps +++ b/deps/init/oceanbase.el7.x86_64.deps @@ -33,6 +33,7 @@ devdeps-icu-69.1-72022112416.el7.x86_64.rpm devdeps-cos-c-sdk-5.0.16-52023070517.el7.x86_64.rpm devdeps-cloud-qpl-1.1.0-272023061419.el7.x86_64.rpm devdeps-s3-cpp-sdk-1.11.156-102023122011.el7.x86_64.rpm +devdeps-protobuf-c-1.4.1-100000062023102016.el7.x86_64.rpm [tools] obdevtools-binutils-2.30-12022100413.el7.x86_64.rpm diff --git a/deps/init/oceanbase.el8.aarch64.deps b/deps/init/oceanbase.el8.aarch64.deps index 2db23605f3..5b2ab60a24 100644 --- a/deps/init/oceanbase.el8.aarch64.deps +++ b/deps/init/oceanbase.el8.aarch64.deps @@ -30,6 +30,7 @@ devdeps-s2geometry-0.9.0-12023092021.el8.aarch64.rpm devdeps-icu-69.1-72022112416.el8.aarch64.rpm devdeps-cos-c-sdk-5.0.16-52023070517.el8.aarch64.rpm devdeps-s3-cpp-sdk-1.11.156-102023122011.el8.aarch64.rpm +devdeps-protobuf-c-1.4.1-100000072023102410.el8.aarch64.rpm [tools] obdevtools-binutils-2.30-12022100413.el8.aarch64.rpm diff --git a/deps/init/oceanbase.el8.x86_64.deps b/deps/init/oceanbase.el8.x86_64.deps index b4fb28e900..9a0d4d6068 100644 --- a/deps/init/oceanbase.el8.x86_64.deps +++ b/deps/init/oceanbase.el8.x86_64.deps @@ -32,6 +32,7 @@ devdeps-icu-69.1-72022112416.el8.x86_64.rpm devdeps-cos-c-sdk-5.0.16-52023070517.el8.x86_64.rpm devdeps-cloud-qpl-1.1.0-272023061419.el8.x86_64.rpm devdeps-s3-cpp-sdk-1.11.156-102023122011.el8.x86_64.rpm +devdeps-protobuf-c-1.4.1-100000062023102016.el8.x86_64.rpm [tools] obdevtools-binutils-2.30-12022100413.el8.x86_64.rpm diff --git a/deps/oblib/src/CMakeLists.txt b/deps/oblib/src/CMakeLists.txt index a48cc1420e..5f923ac613 100644 --- a/deps/oblib/src/CMakeLists.txt +++ b/deps/oblib/src/CMakeLists.txt @@ -206,6 +206,7 @@ target_link_libraries(oblib_base_base_base ${DEP_DIR}/lib/libicui18n.a ${DEP_DIR}/lib/libicustubdata.a ${DEP_DIR}/lib/libicuuc.a + ${DEP_DIR}/lib/libprotobuf-c.a -L${DEP_DIR}/var/usr/lib64 -L${DEP_DIR}/var/usr/lib -L${DEP_3RD_DIR}/usr/lib @@ -230,6 +231,7 @@ target_link_libraries(oblib_base_base_base ${DEP_DIR}/lib/libicui18n.a ${DEP_DIR}/lib/libicustubdata.a ${DEP_DIR}/lib/libicuuc.a + ${DEP_DIR}/lib/libprotobuf-c.a -L${DEP_DIR}/var/usr/lib64 -L${DEP_DIR}/var/usr/lib -L${DEP_3RD_DIR}/usr/lib diff --git a/deps/oblib/src/common/ob_accuracy.cpp b/deps/oblib/src/common/ob_accuracy.cpp index 4bef95e9cd..68eb9d6b31 100644 --- a/deps/oblib/src/common/ob_accuracy.cpp +++ b/deps/oblib/src/common/ob_accuracy.cpp @@ -72,6 +72,7 @@ const ObAccuracy ObAccuracy::DDL_DEFAULT_ACCURACY[ObMaxType] = { ObAccuracy(OB_MAX_LONGTEXT_LENGTH), // geometry ObAccuracy(), // user defined type in sql ObAccuracy(10, 0), // decimal int + ObAccuracy(), // collection type in sql }; const ObAccuracy ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE + 1][ObMaxType] = { @@ -127,6 +128,7 @@ const ObAccuracy ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE + 1][ObMaxType] = ObAccuracy(OB_MAX_LONGTEXT_LENGTH), // geometry ObAccuracy(), // user defined type in sql ObAccuracy(10, 0), // decimal int + ObAccuracy(), // collection type in sql }, { ObAccuracy(), // null. @@ -180,6 +182,7 @@ const ObAccuracy ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE + 1][ObMaxType] = ObAccuracy(OB_MAX_LONGTEXT_LENGTH), // geometry ObAccuracy(), // user defined type in sql ObAccuracy(10, 0), // decimal int + ObAccuracy(), // collection type in sql } }; @@ -235,6 +238,7 @@ const ObAccuracy ObAccuracy::MAX_ACCURACY[ObMaxType] = { ObAccuracy(OB_MAX_LONGTEXT_LENGTH), // geometry ObAccuracy(), // user defined type in sql ObAccuracy(OB_MAX_DECIMAL_PRECISION, OB_MAX_DECIMAL_SCALE), // decimal int + ObAccuracy(), // collection type in sql }; const ObAccuracy ObAccuracy::MAX_ACCURACY2[ORACLE_MODE + 1][ObMaxType] = { @@ -290,6 +294,7 @@ const ObAccuracy ObAccuracy::MAX_ACCURACY2[ORACLE_MODE + 1][ObMaxType] = { ObAccuracy(OB_MAX_LONGTEXT_LENGTH), // geometry ObAccuracy(), // user defined type in sql ObAccuracy(OB_MAX_DECIMAL_PRECISION, OB_MAX_DECIMAL_SCALE), // decimal int + ObAccuracy(), // collection type in sql }, { /* Oracle */ ObAccuracy(), // null. @@ -343,6 +348,7 @@ const ObAccuracy ObAccuracy::MAX_ACCURACY2[ORACLE_MODE + 1][ObMaxType] = { ObAccuracy(OB_MAX_LONGTEXT_LENGTH), // geometry ObAccuracy(), // user defined type in sql ObAccuracy(OB_MAX_DECIMAL_PRECISION, OB_MAX_DECIMAL_SCALE), // decimal int + ObAccuracy(), // collection type in sql } }; @@ -398,6 +404,7 @@ const ObAccuracy ObAccuracy::DML_DEFAULT_ACCURACY[ObMaxType] = { ObAccuracy(OB_MAX_LONGTEXT_LENGTH), // geometry ObAccuracy(), // user defined type in sql ObAccuracy(), // decimal int + ObAccuracy(), // collection type in sql }; const ObAccuracy ObAccuracy::MAX_ACCURACY_OLD[ObMaxType] = { diff --git a/deps/oblib/src/common/ob_field.cpp b/deps/oblib/src/common/ob_field.cpp index f4d5b2e6dd..93bbbadf6d 100644 --- a/deps/oblib/src/common/ob_field.cpp +++ b/deps/oblib/src/common/ob_field.cpp @@ -457,6 +457,7 @@ int ObField::get_field_mb_length(const ObObjType type, break; case ObExtendTC: case ObUserDefinedSQLTC: + case ObCollectionSQLTC: ret = OB_NOT_SUPPORTED; LOG_WARN("not supported get_field_mb_length for extend type", K(ret)); break; diff --git a/deps/oblib/src/common/object/ob_obj_compare.cpp b/deps/oblib/src/common/object/ob_obj_compare.cpp index 6af1fe4950..f997f86cdf 100644 --- a/deps/oblib/src/common/object/ob_obj_compare.cpp +++ b/deps/oblib/src/common/object/ob_obj_compare.cpp @@ -2049,6 +2049,119 @@ int ObObjCmpFuncs::cmp_func(const ObObj &obj1, \ return -ObObjCmpFuncs::cmp_func(obj2, obj1, ctx); \ } +// ObUserDefinedSQLTC vs ObUserDefinedSQLTC +// for udt nested null bitmap +#define DEFINE_CMP_OP_FUNC_UDT_UDT(op, op_str) \ + template <> inline \ + int ObObjCmpFuncs::cmp_op_func(const ObObj &obj1, \ + const ObObj &obj2, \ + const ObCompareCtx &cmp_ctx) \ + { \ + OBJ_TYPE_CLASS_CHECK(obj1, ObUserDefinedSQLTC); \ + OBJ_TYPE_CLASS_CHECK(obj2, ObUserDefinedSQLTC); \ + ObCollationType cs_type = cmp_ctx.cmp_cs_type_; \ + if (CS_TYPE_INVALID == cs_type) { \ + if (obj1.get_collation_type() != obj2.get_collation_type() \ + || CS_TYPE_INVALID == obj1.get_collation_type()) { \ + LOG_ERROR_RET(common::OB_ERR_UNEXPECTED, "invalid collation", K(obj1.get_collation_type()), K(obj2.get_collation_type()), K(obj1), K(obj2)); \ + } else { \ + cs_type = obj1.get_collation_type(); \ + } \ + } \ + return CS_TYPE_INVALID != cs_type \ + ? static_cast(ObCharset::strcmpsp(cs_type, obj1.v_.string_, obj1.val_len_, \ + obj2.v_.string_, obj2.val_len_, CALC_WITH_END_SPACE(obj1, obj2, cmp_ctx)) op_str 0) \ + : CR_OB_ERROR; \ + } + +#define DEFINE_CMP_FUNC_UDT_UDT() \ + template <> inline \ + int ObObjCmpFuncs::cmp_func(const ObObj &obj1, \ + const ObObj &obj2, \ + const ObCompareCtx &cmp_ctx) \ + { \ + OBJ_TYPE_CLASS_CHECK(obj1, ObUserDefinedSQLTC); \ + OBJ_TYPE_CLASS_CHECK(obj2, ObUserDefinedSQLTC); \ + ObCollationType cs_type = cmp_ctx.cmp_cs_type_; \ + if (CS_TYPE_INVALID == cs_type) { \ + if (obj1.get_collation_type() != obj2.get_collation_type() \ + || CS_TYPE_INVALID == obj1.get_collation_type()) { \ + LOG_ERROR_RET(common::OB_ERR_UNEXPECTED, "invalid collation", K(obj1.get_collation_type()), K(obj2.get_collation_type()), K(obj1), K(obj2)); \ + } else { \ + cs_type = obj1.get_collation_type(); \ + } \ + } \ + return CS_TYPE_INVALID != cs_type \ + ? INT_TO_CR(ObCharset::strcmpsp(cs_type, obj1.v_.string_, obj1.val_len_, \ + obj2.v_.string_, obj2.val_len_, CALC_WITH_END_SPACE(obj1, obj2, cmp_ctx))) \ + : CR_OB_ERROR; \ + } + +#define DEFINE_CMP_OP_FUNC_COLLECTION_COLLECTION(op, op_str) \ + template <> inline \ + int ObObjCmpFuncs::cmp_op_func(const ObObj &obj1, \ + const ObObj &obj2, \ + const ObCompareCtx &cmp_ctx) \ + { \ + int ret = CR_OB_ERROR; \ + OBJ_TYPE_CLASS_CHECK(obj1, ObCollectionSQLTC);\ + OBJ_TYPE_CLASS_CHECK(obj2, ObCollectionSQLTC);\ + ObCollationType cs_type = cmp_ctx.cmp_cs_type_; \ + if (CS_TYPE_INVALID == cs_type) { \ + if (obj1.get_collation_type() != obj2.get_collation_type() \ + || CS_TYPE_INVALID == obj1.get_collation_type()) { \ + LOG_ERROR_RET(common::OB_ERR_UNEXPECTED, "invalid collation", K(obj1.get_collation_type()), K(obj2.get_collation_type()), K(obj1), K(obj2)); \ + } else { \ + cs_type = obj1.get_collation_type(); \ + } \ + } \ + if (obj1.is_outrow_lob() || obj2.is_outrow_lob()) { \ + LOG_ERROR("not support outrow lobs", K(obj1), K(obj2)); \ + ret = CR_OB_ERROR; \ + } else { \ + ObString data_str1 = obj1.get_string();\ + ObString data_str2 = obj2.get_string();\ + ret = CS_TYPE_INVALID != cs_type \ + ? static_cast(ObCharset::strcmpsp(cs_type, data_str1.ptr(), data_str1.length(), \ + data_str2.ptr(), data_str2.length(), \ + CALC_WITH_END_SPACE(obj1, obj2, cmp_ctx)) op_str 0) \ + : CR_OB_ERROR; \ + } \ + return ret; \ + } + +#define DEFINE_CMP_FUNC_COLLECTION_COLLECTION() \ + template <> inline \ + int ObObjCmpFuncs::cmp_func(const ObObj &obj1, \ + const ObObj &obj2, \ + const ObCompareCtx &cmp_ctx) \ + { \ + int ret = CR_OB_ERROR; \ + OBJ_TYPE_CLASS_CHECK(obj1, ObCollectionSQLTC);\ + OBJ_TYPE_CLASS_CHECK(obj2, ObCollectionSQLTC);\ + ObCollationType cs_type = cmp_ctx.cmp_cs_type_; \ + if (CS_TYPE_INVALID == cs_type) { \ + if (obj1.get_collation_type() != obj2.get_collation_type() \ + || CS_TYPE_INVALID == obj1.get_collation_type()) { \ + LOG_ERROR_RET(common::OB_ERR_UNEXPECTED, "invalid collation", K(obj1.get_collation_type()), K(obj2.get_collation_type()), K(obj1), K(obj2)); \ + } else { \ + cs_type = obj1.get_collation_type(); \ + } \ + } \ + if (obj1.is_outrow_lob() || obj2.is_outrow_lob()) { \ + LOG_ERROR("not support outrow lobs", K(obj1), K(obj2)); \ + ret = CR_OB_ERROR; \ + } else { \ + ObString data_str1 = obj1.get_string();\ + ObString data_str2 = obj2.get_string();\ + ret = CS_TYPE_INVALID != cs_type \ + ? INT_TO_CR(ObCharset::strcmpsp(cs_type, data_str1.ptr(), data_str1.length(), \ + data_str2.ptr(), data_str2.length(), \ + CALC_WITH_END_SPACE(obj1, obj2, cmp_ctx))) \ + : CR_OB_ERROR; \ + } \ + return ret; \ + } //============================== #define DEFINE_CMP_FUNCS(tc, type) \ @@ -2506,6 +2619,24 @@ int ObObjCmpFuncs::cmp_func(const ObObj &obj1, \ DEFINE_CMP_OP_FUNC_GEOMETRY_GEOMETRY(CO_NE, !=); \ DEFINE_CMP_FUNC_GEOMETRY_GEOMETRY() +#define DEFINE_CMP_FUNCS_UDT_UDT() \ + DEFINE_CMP_OP_FUNC_UDT_UDT(CO_EQ, ==); \ + DEFINE_CMP_OP_FUNC_UDT_UDT(CO_LE, <=); \ + DEFINE_CMP_OP_FUNC_UDT_UDT(CO_LT, < ); \ + DEFINE_CMP_OP_FUNC_UDT_UDT(CO_GE, >=); \ + DEFINE_CMP_OP_FUNC_UDT_UDT(CO_GT, > ); \ + DEFINE_CMP_OP_FUNC_UDT_UDT(CO_NE, !=); \ + DEFINE_CMP_FUNC_UDT_UDT() + +#define DEFINE_CMP_FUNCS_COLLECTION_COLLECTION() \ + DEFINE_CMP_OP_FUNC_COLLECTION_COLLECTION(CO_EQ, ==); \ + DEFINE_CMP_OP_FUNC_COLLECTION_COLLECTION(CO_LE, <=); \ + DEFINE_CMP_OP_FUNC_COLLECTION_COLLECTION(CO_LT, < ); \ + DEFINE_CMP_OP_FUNC_COLLECTION_COLLECTION(CO_GE, >=); \ + DEFINE_CMP_OP_FUNC_COLLECTION_COLLECTION(CO_GT, > ); \ + DEFINE_CMP_OP_FUNC_COLLECTION_COLLECTION(CO_NE, !=); \ + DEFINE_CMP_FUNC_COLLECTION_COLLECTION() + #define DEFINE_CMP_FUNCS_STRING_TEXT() \ DEFINE_CMP_OP_FUNC_STRING_TEXT(CO_EQ, ==); \ DEFINE_CMP_OP_FUNC_STRING_TEXT(CO_LE, <=); \ @@ -2659,6 +2790,8 @@ DEFINE_CMP_FUNCS_TEXT_STRING(); DEFINE_CMP_FUNCS_LOB_LOB(); DEFINE_CMP_FUNCS_JSON_JSON(); DEFINE_CMP_FUNCS_GEOMETRY_GEOMETRY(); +DEFINE_CMP_FUNCS_UDT_UDT(); +DEFINE_CMP_FUNCS_COLLECTION_COLLECTION(); DEFINE_CMP_FUNCS_ENUMSETINNER_INT(); DEFINE_CMP_FUNCS_ENUMSETINNER_UINT(); @@ -2843,6 +2976,8 @@ DEFINE_CMP_FUNCS_NULLSAFE_ENTRY(ObDecimalIntTC, ObUIntTC, ObMaxTC, ObMaxTC) DEFINE_CMP_FUNCS_NULLSAFE_ENTRY(ObDecimalIntTC, ObNumberTC, ObMaxTC, ObMaxTC) DEFINE_CMP_FUNCS_NULLSAFE_ENTRY(ObDecimalIntTC, ObEnumSetTC, ObMaxTC, ObMaxTC) +DEFINE_CMP_FUNCS_NULLSAFE_ENTRY(ObUserDefinedSQLTC, ObUserDefinedSQLTC, ObMaxTC, ObMaxTC) +DEFINE_CMP_FUNCS_NULLSAFE_ENTRY(ObCollectionSQLTC, ObCollectionSQLTC, ObMaxTC, ObMaxTC) DEFINE_CMP_FUNCS_NULLSAFE_LEFTNULL_ENTRY(ObExtendTC) DEFINE_CMP_FUNCS_NULLSAFE_LEFTNULL_ENTRY(ObMaxTC) DEFINE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObExtendTC) @@ -2878,6 +3013,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt DECLARE_CMP_FUNCS_NULLSAFE_LEFTNULL_ENTRY(ObMaxTC),// decimalint + NULL, // collection }, { // int DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -2905,7 +3041,8 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // json NULL, // geometry NULL, // udt - DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObIntTC, ObDecimalIntTC, ObMaxTC, ObMaxTC) // decimal int + DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObIntTC, ObDecimalIntTC, ObMaxTC, ObMaxTC), // decimal int + NULL, // collection }, { // uint DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -2933,7 +3070,8 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // json NULL, // geometry NULL, // udt - DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObUIntTC, ObDecimalIntTC, ObMaxTC, ObMaxTC) // decimal int + DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObUIntTC, ObDecimalIntTC, ObMaxTC, ObMaxTC), // decimal int + NULL, // collection }, { // float DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -2962,6 +3100,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // double DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -2990,6 +3129,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // number DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3017,7 +3157,8 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // json NULL, // geometry NULL, // udt - DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObNumberTC, ObDecimalIntTC, ObMaxTC, ObMaxTC) // decimal int + DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObNumberTC, ObDecimalIntTC, ObMaxTC, ObMaxTC), // decimal int + NULL, // collection }, { // datetime DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3046,6 +3187,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimalint + NULL, // collection }, { // date DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3074,6 +3216,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // time DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3102,6 +3245,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // year DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3130,6 +3274,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // string DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3158,6 +3303,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // extend DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObExtendTC), @@ -3186,6 +3332,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObExtendTC, ObMaxTC, ObExtendTC, ObMaxTC), // decimalint + NULL, // collection }, { // unknown DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3214,6 +3361,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // text DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3242,6 +3390,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // bit DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3270,6 +3419,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { //enumset DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3297,7 +3447,8 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // json NULL, // geometry NULL, // udt - DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObEnumSetTC, ObDecimalIntTC, ObMaxTC, ObMaxT) + DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObEnumSetTC, ObDecimalIntTC, ObMaxTC, ObMaxTC), + NULL, // collection }, { //enumsetInner DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3325,7 +3476,8 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // json NULL, // geometry NULL, // udt - DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObEnumSetInnerTC, ObDecimalIntTC, ObMaxTC, ObMaxTC) // decimal int + DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObEnumSetInnerTC, ObDecimalIntTC, ObMaxTC, ObMaxTC), // decimal int + NULL, // collection }, { // otimestamp DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3354,6 +3506,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // raw DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3382,6 +3535,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // interval DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3410,6 +3564,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // rowid DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3438,6 +3593,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // lob DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3466,6 +3622,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // json DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3494,6 +3651,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // geometry DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3522,6 +3680,7 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObGeometryTC, ObGeometryTC, ObMaxTC, ObMaxTC), // geometry NULL, // udt NULL, // decimal int + NULL, // collection }, { // udt DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), @@ -3548,8 +3707,9 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // lob NULL, // json NULL, // geometry - NULL, // udt + DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObUserDefinedSQLTC, ObUserDefinedSQLTC, ObMaxTC, ObMaxTC), // udt NULL, // decimal int + NULL, // collection }, { // decimal int DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), // null @@ -3578,7 +3738,39 @@ const obj_cmp_func_nullsafe ObObjCmpFuncs::cmp_funcs_nullsafe[ObMaxTC][ObMaxTC] NULL, // geometry NULL, // udt DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObDecimalIntTC, ObDecimalIntTC, ObMaxTC, ObMaxTC), // decimalint + NULL, // collection } + , + { // collection + DECLARE_CMP_FUNCS_NULLSAFE_RIGHTNULL_ENTRY(ObMaxTC), + NULL, // int + NULL, // uint + NULL, // float + NULL, // double + NULL, // number + NULL, // datetime + NULL, // date + NULL, // time + NULL, // year + NULL, // string + NULL, // extend + NULL, // unknown + NULL, // text + NULL, // bit + NULL, // enumset + NULL, //enumsetInner will not go here + NULL, // otimestamp + NULL, // raw + NULL, // interval + NULL, // rowid + NULL, // lob + NULL, // json + NULL, // geometry + NULL, // udt + NULL, // decimalint + DECLARE_CMP_FUNCS_NULLSAFE_ENTRY(ObCollectionSQLTC, ObCollectionSQLTC, ObMaxTC, ObMaxTC), // collection +}, + }; const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = @@ -3610,6 +3802,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY(ObNullTC, ObMaxTC),//geometry DEFINE_CMP_FUNCS_ENTRY(ObNullTC, ObMaxTC),//udt DEFINE_CMP_FUNCS_ENTRY(ObNullTC, ObMaxTC), // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // int DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3638,6 +3831,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY(ObIntTC, ObDecimalIntTC), // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // uint DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3666,6 +3860,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY(ObUIntTC, ObDecimalIntTC), // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // float DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3694,6 +3889,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // double DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3722,6 +3918,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // number DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3750,6 +3947,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY(ObNumberTC, ObDecimalIntTC), // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // datetime DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3778,6 +3976,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // date DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3806,6 +4005,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // time DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3834,6 +4034,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // year DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3862,6 +4063,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // string DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3890,6 +4092,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // extend DEFINE_CMP_FUNCS_ENTRY(ObExtendTC, ObNullTC), @@ -3918,6 +4121,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY(ObExtendTC, ObMaxTC), // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // unknown DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3946,6 +4150,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, //decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // text DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -3974,6 +4179,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, //decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // bit DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -4002,6 +4208,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { //enumset DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -4030,6 +4237,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY(ObEnumSetTC, ObDecimalIntTC), // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { //enumsetInner DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -4058,6 +4266,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY(ObEnumSetInnerTC, ObDecimalIntTC), // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // otimestamp DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -4086,6 +4295,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // raw DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), @@ -4114,6 +4324,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // interval DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), //null @@ -4142,6 +4353,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // rowid DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), //null @@ -4170,6 +4382,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // lob DEFINE_CMP_FUNCS_ENTRY_NULL, //null @@ -4198,6 +4411,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // json DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), //null @@ -4226,6 +4440,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // geometry DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), //null @@ -4254,6 +4469,7 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY(ObGeometryTC, ObGeometryTC), //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, //udt DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // udt DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), //null @@ -4280,8 +4496,9 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //lob DEFINE_CMP_FUNCS_ENTRY_NULL, //json DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry - DEFINE_CMP_FUNCS_ENTRY_NULL, //udt + DEFINE_CMP_FUNCS_ENTRY(ObUserDefinedSQLTC, ObUserDefinedSQLTC), // compare for udt nested null bitmap DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, { // decimalint DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), //null @@ -4310,7 +4527,37 @@ const obj_cmp_func ObObjCmpFuncs::cmp_funcs[ObMaxTC][ObMaxTC][CO_MAX] = DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry DEFINE_CMP_FUNCS_ENTRY_NULL, // udt DEFINE_CMP_FUNCS_ENTRY(ObDecimalIntTC, ObDecimalIntTC), // decimal int + DEFINE_CMP_FUNCS_ENTRY_NULL, // collection }, + { // collection + DEFINE_CMP_FUNCS_ENTRY(ObMaxTC, ObNullTC), //null + DEFINE_CMP_FUNCS_ENTRY_NULL, // int + DEFINE_CMP_FUNCS_ENTRY_NULL, // uint + DEFINE_CMP_FUNCS_ENTRY_NULL, // float + DEFINE_CMP_FUNCS_ENTRY_NULL, // double + DEFINE_CMP_FUNCS_ENTRY_NULL, // number + DEFINE_CMP_FUNCS_ENTRY_NULL, // datetime + DEFINE_CMP_FUNCS_ENTRY_NULL, // date + DEFINE_CMP_FUNCS_ENTRY_NULL, // time + DEFINE_CMP_FUNCS_ENTRY_NULL, // year + DEFINE_CMP_FUNCS_ENTRY_NULL, // string + DEFINE_CMP_FUNCS_ENTRY_NULL, //extend + DEFINE_CMP_FUNCS_ENTRY_NULL, // unknown + DEFINE_CMP_FUNCS_ENTRY_NULL, // text + DEFINE_CMP_FUNCS_ENTRY_NULL, // bit + DEFINE_CMP_FUNCS_ENTRY_NULL, // enumset + DEFINE_CMP_FUNCS_ENTRY_NULL, // enumsetInner will not go here + DEFINE_CMP_FUNCS_ENTRY_NULL, // otimestamp + DEFINE_CMP_FUNCS_ENTRY_NULL, // raw + DEFINE_CMP_FUNCS_ENTRY_NULL, // interval + DEFINE_CMP_FUNCS_ENTRY_NULL, //rowid + DEFINE_CMP_FUNCS_ENTRY_NULL, //lob + DEFINE_CMP_FUNCS_ENTRY_NULL, //json + DEFINE_CMP_FUNCS_ENTRY_NULL, //geometry + DEFINE_CMP_FUNCS_ENTRY_NULL, //udt + DEFINE_CMP_FUNCS_ENTRY_NULL, // decimal int + DEFINE_CMP_FUNCS_ENTRY(ObCollectionSQLTC, ObCollectionSQLTC), // collection + } }; const ObObj ObObjCmpFuncs::cmp_res_objs_bool[CR_BOOL_CNT] = diff --git a/deps/oblib/src/common/object/ob_obj_funcs.h b/deps/oblib/src/common/object/ob_obj_funcs.h index b285f584c2..0ec746126b 100644 --- a/deps/oblib/src/common/object/ob_obj_funcs.h +++ b/deps/oblib/src/common/object/ob_obj_funcs.h @@ -194,6 +194,7 @@ template <> case ObJsonType: case ObGeometryType: case ObUserDefinedSQLType: + case ObCollectionSQLType: default: break; } @@ -3431,13 +3432,7 @@ inline int obj_val_serialize(const ObObj &obj, char* buf, int ret = OB_SUCCESS; OB_UNIS_ENCODE(obj.get_meta().get_subschema_id()); OB_UNIS_ENCODE(obj.get_meta().get_udt_flags()); - if (OB_FAIL(ret)) { - } else if (obj.get_meta().is_xml_sql_type()) { - OB_UNIS_ENCODE(obj.get_string()); - } else { // need callback for different types? - ret = OB_NOT_SUPPORTED; - COMMON_LOG(WARN, "unsupported udt type", K(ret), K(obj.get_meta()), K(buf_len), K(pos)); - } + OB_UNIS_ENCODE(obj.get_string()); return ret; } @@ -3450,16 +3445,10 @@ inline int obj_val_deserialize(ObObj &obj, const char* buf OB_UNIS_DECODE(subschema_id); OB_UNIS_DECODE(udt_flags); - if (OB_FAIL(ret)) { - } else if (ob_is_xml_sql_type(ObUserDefinedSQLType, subschema_id)) { - ObString blob; - OB_UNIS_DECODE(blob); - if (OB_SUCC(ret)) { - obj.set_sql_udt(blob.ptr(), blob.length(), subschema_id, udt_flags); - } - } else { - ret = OB_NOT_SUPPORTED; - COMMON_LOG(WARN, "unsupported udt type", K(ret), K(subschema_id), K(udt_flags)); + ObString blob; + OB_UNIS_DECODE(blob); + if (OB_SUCC(ret)) { + obj.set_sql_udt(blob.ptr(), blob.length(), subschema_id, udt_flags); } return ret; } @@ -3473,7 +3462,113 @@ inline int64_t obj_val_get_serialize_size(const ObObj &obj OB_UNIS_ADD_LEN(obj.get_string()); return len; } -} // end namespace common -} // end namespace oceanbase + +// DEF_TEXT_PRINT_FUNCS(ObCollectionSQLType); +template <> +inline int obj_print_sql(const ObObj &obj, char *buffer, int64_t length, + int64_t &pos, const ObObjPrintParams ¶ms) +{ + UNUSED(params); + int ret = OB_SUCCESS; + ObString udt_data; + if (OB_FAIL(obj.get_udt_print_data(udt_data, buffer, length, pos, true))) { + } else if (OB_FAIL(databuff_printf(buffer, length, pos, "'"))) { + } else { + ObHexEscapeSqlStr sql_str(udt_data); + pos += sql_str.to_string(buffer + pos, length - pos); + ret = databuff_printf(buffer, length, pos, "'"); + } + return ret; +} + +template <> +inline int obj_print_str(const ObObj &obj, char *buffer, int64_t length, + int64_t &pos, const ObObjPrintParams ¶ms) +{ + UNUSED(params); + int ret = OB_SUCCESS; + ObString udt_data; + if (OB_FAIL(obj.get_udt_print_data(udt_data, buffer, length, pos, true))) { + } else { + ret = databuff_printf(buffer, length, pos, "'%.*s'", udt_data.length(), udt_data.ptr()); + } + return ret; +} + +template <> +inline int obj_print_plain_str(const ObObj &obj, char *buffer, int64_t length, + int64_t &pos, const ObObjPrintParams ¶ms) +{ + int ret = OB_SUCCESS; + ObObj tmp_obj = obj; + ObString udt_data; + if (OB_FAIL(obj.get_udt_print_data(udt_data, buffer, length, pos, true))) { + } else { + tmp_obj.set_string(obj.get_type(), udt_data); + tmp_obj.set_collation_type(CS_TYPE_BINARY); + ret = obj_print_plain_str(tmp_obj, buffer, length, pos, params); + } + return ret; +} +template <> +inline int obj_print_json(const ObObj &obj, char *buf, int64_t buf_len, + int64_t &pos, const ObObjPrintParams ¶ms) +{ + UNUSED(params); + int ret = OB_SUCCESS; + ObString udt_data; + if (OB_FAIL(obj.get_udt_print_data(udt_data, buf, buf_len, pos, true))) { + } else { + J_OBJ_START(); + PRINT_META(); + BUF_PRINTO("COLLECTION"); + J_COLON(); + BUF_PRINTO(udt_data); + J_OBJ_END(); + } + return ret; +} + +// DEF_TEXT_SERIALIZE_FUNCS(ObCollectionSQLType, TYPE, VTYPE) +template <> +inline int obj_val_serialize(const ObObj &obj, char* buf, const int64_t buf_len, int64_t& pos) +{ + int ret = OB_SUCCESS; + OB_UNIS_ENCODE(obj.get_meta().get_subschema_id()); + OB_UNIS_ENCODE(obj.get_meta().get_udt_flags()); + OB_UNIS_ENCODE(obj.get_string()); + return ret; +} + +template <> +inline int obj_val_deserialize(ObObj &obj, const char* buf, const int64_t data_len, int64_t& pos) +{ + int ret = OB_SUCCESS; + uint16_t subschema_id = uint16_t(); + uint8_t udt_flags = uint8_t(); + + OB_UNIS_DECODE(subschema_id); + OB_UNIS_DECODE(udt_flags); + ObString blob; + OB_UNIS_DECODE(blob); + if (OB_SUCC(ret)) { + obj.set_sql_collection(blob.ptr(), blob.length(), subschema_id, udt_flags); + } + return ret; +} + +template <> +inline int64_t obj_val_get_serialize_size(const ObObj &obj) +{ + int64_t len = 0; + OB_UNIS_ADD_LEN(obj.get_meta().get_subschema_id()); + OB_UNIS_ADD_LEN(obj.get_meta().get_udt_flags()); + OB_UNIS_ADD_LEN(obj.get_string()); + return len; +} + +DEF_UDT_CS_FUNCS(ObCollectionSQLType); +} +} #endif // diff --git a/deps/oblib/src/common/object/ob_obj_type.cpp b/deps/oblib/src/common/object/ob_obj_type.cpp index 45f773537a..a256e3ea7e 100644 --- a/deps/oblib/src/common/object/ob_obj_type.cpp +++ b/deps/oblib/src/common/object/ob_obj_type.cpp @@ -105,6 +105,7 @@ const char *ob_sql_type_str(ObObjType type) "GEOMETRY", "UDT", "DECIMAL_INT", + "COLLECTION", "" }, { @@ -158,9 +159,10 @@ const char *ob_sql_type_str(ObObjType type) "ROWID", "LOB", "JSON", - "GEOMETRY", + "SDO_GEOMETRY", "UDT", "DECIMAL_INT", + "COLLECTION", "" } }; @@ -394,8 +396,8 @@ DEF_TYPE_STR_FUNCS(set, "set", ""); DEF_TYPE_STR_FUNCS_PRECISION(number_float, "float", ""); DEF_TYPE_TEXT_FUNCS_LENGTH(lob, (lib::is_oracle_mode() ? "clob" : "longtext"), (lib::is_oracle_mode() ? "blob" : "longblob")); DEF_TYPE_TEXT_FUNCS_LENGTH(json, "json", "json"); -DEF_TYPE_TEXT_FUNCS_LENGTH(geometry, "geometry", "geometry"); DEF_TYPE_STR_FUNCS_PRECISION_SCALE(decimal_int, "decimal", "", "number"); +DEF_TYPE_TEXT_FUNCS_LENGTH(geometry, (lib::is_oracle_mode() ? "sdo_geometry" : "geometry"), (lib::is_oracle_mode() ? "sdo_geometry" : "geometry")); /////////////////////////////////////////////////////////// DEF_TYPE_STR_FUNCS_WITHOUT_ACCURACY_FOR_NON_STRING(null, "null", ""); @@ -444,8 +446,8 @@ DEF_TYPE_STR_FUNCS_WITHOUT_ACCURACY_FOR_STRING(nchar, "nchar", "nchar"); DEF_TYPE_STR_FUNCS_WITHOUT_ACCURACY_FOR_NON_STRING(urowid, "urowid", ""); DEF_TYPE_STR_FUNCS_WITHOUT_ACCURACY_FOR_STRING(lob, (lib::is_oracle_mode() ? "clob" : "longtext"), (lib::is_oracle_mode() ? "blob" : "longblob")); DEF_TYPE_STR_FUNCS_WITHOUT_ACCURACY_FOR_STRING(json, "json", "json"); -DEF_TYPE_STR_FUNCS_WITHOUT_ACCURACY_FOR_STRING(geometry, "geometry", "geometry"); DEF_TYPE_STR_FUNCS_WITHOUT_ACCURACY_FOR_NON_STRING(decimal_int, "decimal", ""); +DEF_TYPE_STR_FUNCS_WITHOUT_ACCURACY_FOR_STRING(geometry, (lib::is_oracle_mode() ? "sdo_geometry" : "geometry"), (lib::is_oracle_mode() ? "sdo_geometry" : "geometry")); int ob_empty_str(char *buff, int64_t buff_length, ObCollationType coll_type) @@ -517,16 +519,24 @@ int ob_geometry_sub_type_str(char *buff, int64_t buff_length, int64_t &pos, cons return ret; } -int ob_udt_sub_type_str(char *buff, int64_t buff_length, int64_t &pos, const uint64_t sub_type, bool is_sql_type = false) +int ob_udt_sub_type_str(char *buff, + int64_t buff_length, + int64_t &pos, const common::ObIArray &type_info, + const uint64_t sub_type, + bool is_sql_type = false) { int ret = OB_SUCCESS; if (is_sql_type && sub_type == ObXMLSqlType) { ret = databuff_printf(buff, buff_length, pos, "XMLTYPE"); } else if (sub_type == T_OBJ_XML) { ret = databuff_printf(buff, buff_length, pos, "XMLTYPE"); - } else { + } else if (sub_type == T_OBJ_SDO_GEOMETRY) { + ret = databuff_printf(buff, buff_length, pos, "SDO_GEOMETRY"); + } else if (type_info.empty()) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("undefined geometry type", K(ret), K(sub_type), K(is_sql_type)); + LOG_WARN("unexpected column sub type", K(ret), K(sub_type), K(is_sql_type)); + } else { + ret = databuff_printf(buff, buff_length, pos, "%.*s", type_info.at(0).length(), type_info.at(0).ptr()); } return ret; } @@ -750,8 +760,9 @@ int ob_sql_type_str(char *buff, ob_lob_str,//lob ob_json_str,//json ob_geometry_str,//geometry - nullptr, + nullptr, // udt ob_decimal_int_str, //decimal int + nullptr, // collection ob_empty_str // MAX }; static_assert(sizeof(sql_type_name) / sizeof(ObSqlTypeStrFunc) == ObMaxType + 1, "Not enough initializer"); @@ -759,10 +770,11 @@ int ob_sql_type_str(char *buff, if (OB_FAIL(ob_geometry_sub_type_str(buff, buff_length, pos, static_cast(sub_type)))) { LOG_WARN("fail to get geometry sub type str", K(ret), K(sub_type), K(buff), K(buff_length), K(pos)); } - } else if (lib::is_oracle_mode() && (ob_is_user_defined_sql_type(type) || sub_type == T_OBJ_XML)) { - if (OB_FAIL(ob_udt_sub_type_str(buff, buff_length, pos, sub_type, true))) { - LOG_WARN("fail to get udt sub type str", K(ret), K(sub_type), K(buff), K(buff_length), K(pos)); - } + } else if (lib::is_oracle_mode() && (ob_is_user_defined_sql_type(type) || sub_type == T_OBJ_XML || sub_type == T_OBJ_SDO_GEOMETRY)) { + ObSEArray dummy_arr; + if (OB_FAIL(ob_udt_sub_type_str(buff, buff_length, pos, dummy_arr, sub_type, true))) { + LOG_WARN("fail to get udt sub type str", K(ret), K(sub_type), K(buff), K(buff_length), K(pos)); + } } else { ret = sql_type_name[OB_LIKELY(type < ObMaxType) ? type : ObMaxType](buff, buff_length, pos, length, precision, scale, coll_type); } @@ -835,8 +847,9 @@ int ob_sql_type_str(char *buff, ob_lob_str_without_accuracy,//lob ob_json_str_without_accuracy,//json ob_geometry_str_without_accuracy,//geometry - nullptr, + nullptr,//udt ob_decimal_int_str_without_accuracy,//decimal int + nullptr,//collection ob_empty_str // MAX }; static_assert(sizeof(sql_type_name) / sizeof(obSqlTypeStrWithoutAccuracyFunc) == ObMaxType + 1, "Not enough initializer"); @@ -882,8 +895,8 @@ int ob_sql_type_str(const ObObjMeta &obj_meta, LOG_WARN("fail to get geometry sub type str", K(ret), K(sub_type), K(buff), K(buff_length), K(pos)); } } else if (lib::is_oracle_mode() && obj_meta.is_ext()) { - if (OB_FAIL(ob_udt_sub_type_str(buff, buff_length, pos, sub_type))) { - LOG_WARN("fail to get udt sub type str", K(ret), K(accuracy.get_accuracy()), K(buff), K(buff_length), K(pos)); + if (OB_FAIL(ob_udt_sub_type_str(buff, buff_length, pos, type_info, sub_type))) { + LOG_WARN("fail to get udt sub type str", K(ret), K(sub_type), K(buff), K(buff_length), K(pos)); } } else { ObObjType datatype = obj_meta.get_type(); @@ -936,6 +949,7 @@ const char *ob_sql_tc_str(ObObjTypeClass tc) "GEOMETRY", "UDT", "DECIMAL_INT", + "COLLECTION", "" }; static_assert(sizeof(sql_tc_name) / sizeof(const char *) == ObMaxTC + 1, "Not enough initializer"); diff --git a/deps/oblib/src/common/object/ob_obj_type.h b/deps/oblib/src/common/object/ob_obj_type.h index 92072fc50f..e9d757e271 100644 --- a/deps/oblib/src/common/object/ob_obj_type.h +++ b/deps/oblib/src/common/object/ob_obj_type.h @@ -92,7 +92,7 @@ enum ObObjType ObUserDefinedSQLType = 49, // User defined type in SQL ObDecimalIntType = 50, // decimal int type - // ! occupy for ob_gis_42x: ObCollectionSQLType = 51, // collection(varray and nested table) in SQL + ObCollectionSQLType = 51, // collection(varray and nested table) in SQL ObMaxType // invalid type, or count of obj type }; @@ -126,7 +126,7 @@ enum ObObjOType ObOJsonType = 24, ObOGeometryType = 25, ObOUDTSqlType = 26, - // !occupy for ob_gis_42x: ObOCollectionSqlType = 27, + ObOCollectionSqlType = 27, ObOMaxType //invalid type, or count of ObObjOType }; @@ -213,7 +213,7 @@ static ObObjOType OBJ_TYPE_TO_O_TYPE[ObMaxType+1] = { ObOGeometryType, //ObGeometryType = 48, ObOUDTSqlType, //ObUserDefinedSQLType = 49, ObONumberType, //ObDecimalIntType = 50, - // ! occupy for ob_gis_42x: ObCollectionSQLType = 51, // collection(varray and nested table) in SQL + ObOCollectionSqlType, //ObCollectionSQLType = 51, ObONotSupport //ObMaxType, }; @@ -246,7 +246,7 @@ enum ObObjTypeClass ObGeometryTC = 23, // geometry type class ObUserDefinedSQLTC = 24, // user defined type class in SQL ObDecimalIntTC = 25, // decimal int class - // ! occupy for ob_gis_42x: ObCollectionSQLTC = 26, // collection type class in SQL + ObCollectionSQLTC = 26, // collection type class in SQL ObMaxTC, // invalid type classes are below, only used as the result of XXXX_type_promotion() // to indicate that the two obj can't be promoted to the same type. @@ -308,7 +308,8 @@ enum ObObjTypeClass (ObJsonType, ObJsonTC), \ (ObGeometryType, ObGeometryTC), \ (ObUserDefinedSQLType, ObUserDefinedSQLTC),\ - (ObDecimalIntType, ObDecimalIntTC) + (ObDecimalIntType, ObDecimalIntTC),\ + (ObCollectionSQLType, ObCollectionSQLTC) #define SELECT_SECOND(x, y) y #define SELECT_TC(arg) SELECT_SECOND arg @@ -349,6 +350,7 @@ const ObObjType OBJ_DEFAULT_TYPE[ObActualMaxTC] = ObGeometryType, // geometry ObUserDefinedSQLType, // user defined type in sql ObDecimalIntType, // decimal int + ObCollectionSQLType, // collection type in sql ObMaxType, // maxtype ObUInt64Type, // int&uint ObMaxType, // lefttype @@ -385,6 +387,7 @@ static ObObjTypeClass OBJ_O_TYPE_TO_CLASS[ObOMaxType + 1] = ObJsonTC, // ObOJsonType ObGeometryTC, // ObOGeometryType ObUserDefinedSQLTC, // ObOUDTSqlType + ObCollectionSQLTC, // ObCollectionSqlType ObMaxTC }; @@ -1085,6 +1088,7 @@ enum ObExtObjType T_EXT_SQL_END = 200 }; +// systemd defined udt type (fixed udt id) enum ObUDTType { T_OBJ_NOT_SUPPORTED = 0, @@ -1283,7 +1287,7 @@ OB_INLINE bool ob_is_castable_type_class(ObObjTypeClass tc) || ObBitTC == tc || ObEnumSetTC == tc || ObEnumSetInnerTC == tc || ObTextTC == tc || ObOTimestampTC == tc || ObRawTC == tc || ObIntervalTC == tc || ObRowIDTC == tc || ObLobTC == tc || ObJsonTC == tc || ObGeometryTC == tc - || ObUserDefinedSQLTC == tc || ObDecimalIntTC == tc; + || ObUserDefinedSQLTC == tc || ObDecimalIntTC == tc || ObCollectionSQLTC == tc; } //used for arithmetic @@ -1546,7 +1550,11 @@ inline bool ob_is_var_len_type(const ObObjType type) { || ob_is_rowid_tc(type) || ob_is_lob_locator(type); } -inline bool is_lob_storage(const ObObjType type) { return ob_is_large_text(type) || ob_is_json_tc(type) || ob_is_geometry_tc(type); } +inline bool ob_is_collection_sql_type(const ObObjType type) { return ObCollectionSQLType == type; } +inline bool is_lob_storage(const ObObjType type) { return ob_is_large_text(type) + || ob_is_json_tc(type) + || ob_is_geometry_tc(type) + || ob_is_collection_sql_type(type); } inline bool ob_is_geometry(const ObObjType type) { return ObGeometryType == type; } inline bool ob_is_lob_group(const ObObjType type) { return ob_is_json(type) || ob_is_geometry(type) || ob_is_large_text(type); } inline bool ob_is_decimal_int(const ObObjType type) { return ObDecimalIntType == type; } diff --git a/deps/oblib/src/common/object/ob_object.cpp b/deps/oblib/src/common/object/ob_object.cpp index a57dcecebd..4a15e4c0f8 100644 --- a/deps/oblib/src/common/object/ob_object.cpp +++ b/deps/oblib/src/common/object/ob_object.cpp @@ -1311,7 +1311,8 @@ int ObObj::deep_copy(const ObObj &src, char *buf, const int64_t size, int64_t &p this->set_lob_locator(*res); pos += src.get_val_len(); } - } else if (ob_is_user_defined_sql_type(src.get_type())) { + } else if (ob_is_user_defined_sql_type(src.get_type()) + || ob_is_collection_sql_type(src.get_type())) { ObString src_str = src.get_string(); if (OB_UNLIKELY(size < (pos + src_str.length()))) { ret = OB_BUF_NOT_ENOUGH; @@ -1340,8 +1341,11 @@ int ObObj::deep_copy(const ObObj &src, char *buf, const int64_t size, int64_t &p void* ObObj::get_deep_copy_obj_ptr() { void * ptr = NULL; - if (ob_is_string_type(this->get_type()) || ob_is_json(this->get_type()) - || ob_is_geometry(this->get_type()) || ob_is_user_defined_sql_type(this->get_type())) { + if (ob_is_string_type(this->get_type()) + || ob_is_json(this->get_type()) + || ob_is_geometry(this->get_type()) + || ob_is_user_defined_sql_type(this->get_type()) + || ob_is_collection_sql_type(this->get_type())) { // val_len_ == 0 is empty string, and it may point to unexpected address // Therefore, reset it to NULL if (val_len_ != 0) { @@ -1769,7 +1773,8 @@ ObObjTypeFuncs OBJ_FUNCS[ObMaxType] = DEF_FUNC_ENTRY(ObJsonType), // 47, json DEF_FUNC_ENTRY(ObGeometryType), // 48, geometry TODO!!!!! DEF_FUNC_ENTRY(ObUserDefinedSQLType),// 49, udt - DEF_FUNC_ENTRY(ObDecimalIntType) // 50, decimal int + DEF_FUNC_ENTRY(ObDecimalIntType), // 50, decimal int + DEF_FUNC_ENTRY(ObCollectionSQLType), // 51, collection }; ob_obj_hash ObObjUtil::get_murmurhash_v3(ObObjType type) @@ -2488,3 +2493,36 @@ DEFINE_GET_SERIALIZE_SIZE(ObSqlArrayObj) OB_UNIS_ADD_LEN_ARRAY(data_, count_); return len; } +int ObObjUDTUtil::ob_udt_obj_value_serialize(const ObObj &obj, char* buf, const int64_t buf_len, int64_t& pos) +{ + int ret = OB_SUCCESS; + if (obj.get_meta().is_invalid()) { + ret = OB_ERR_UNEXPECTED; + } else { + ret = OBJ_FUNCS[obj.get_meta().get_type()].serialize(obj, buf, buf_len, pos); + } + return ret; +} + +int ObObjUDTUtil::ob_udt_obj_value_deserialize(ObObj &obj, const char* buf, const int64_t data_len, int64_t& pos) +{ + int ret = OB_SUCCESS; + // set meta before deserialize! + if (obj.get_meta().is_invalid()) { + ret = OB_ERR_UNEXPECTED; + } else { + ret = OBJ_FUNCS[obj.get_meta().get_type()].deserialize(obj, buf, data_len, pos); + } + return ret; +} + +int ObObjUDTUtil::ob_udt_obj_value_get_serialize_size(const ObObj &obj, int64_t &value_len) +{ + int ret = OB_SUCCESS; + if (obj.get_meta().is_invalid()) { + ret = OB_ERR_UNEXPECTED; + } else { + value_len = OBJ_FUNCS[obj.get_meta().get_type()].get_serialize_size(obj); + } + return ret; +} diff --git a/deps/oblib/src/common/object/ob_object.h b/deps/oblib/src/common/object/ob_object.h index 5f33ebd9f4..ef230552ab 100644 --- a/deps/oblib/src/common/object/ob_object.h +++ b/deps/oblib/src/common/object/ob_object.h @@ -141,7 +141,8 @@ public: && !ob_is_geometry(static_cast(type_))) { set_collation_level(CS_LEVEL_NUMERIC); set_collation_type(CS_TYPE_BINARY); - } else if (ObUserDefinedSQLType == type_) { + } else if (ObUserDefinedSQLType == type_ || + ObCollectionSQLType == type_) { set_subschema_id(UINT_MAX16); } } @@ -345,7 +346,11 @@ public: { return (ob_is_text_tc(get_type()) && CS_TYPE_BINARY == cs_type_); } - OB_INLINE bool is_lob_storage() const { return ob_is_large_text(get_type()) || ob_is_json_tc(get_type()) || ob_is_geometry_tc(get_type()); } + OB_INLINE bool is_lob_storage() const + { return ob_is_large_text(get_type()) + || ob_is_json_tc(get_type()) + || ob_is_geometry_tc(get_type()) + || ob_is_collection_sql_type(get_type()); } OB_INLINE bool is_lob() const { return ob_is_text_tc(get_type()); } OB_INLINE bool is_inrow() const { return is_lob() && lob_scale_.is_in_row(); } OB_INLINE bool is_outrow() const { return is_lob() && lob_scale_.is_out_row(); } @@ -411,7 +416,7 @@ public: OB_INLINE ObCollationLevel get_collation_level() const { return static_cast(cs_level_); } OB_INLINE ObCollationType get_collation_type() const { // ObUserDefinedSQLType reused cs_type as part of sub schema id, therefore always return CS_TYPE_BINARY - return is_user_defined_sql_type() ? CS_TYPE_BINARY : static_cast(cs_type_); + return (is_user_defined_sql_type() || is_collection_sql_type()) ? CS_TYPE_BINARY : static_cast(cs_type_); } OB_INLINE ObCharsetType get_charset_type() const { return ObCharset::charset_type_by_coll(get_collation_type()); @@ -479,6 +484,14 @@ public: } } + OB_INLINE bool is_expectd_udt_type(const uint16_t subschema_id) const { return (ObUserDefinedSQLType == type_ && get_subschema_id() == subschema_id); } + OB_INLINE bool is_collection_sql_type() const { return ObCollectionSQLType == type_; } + OB_INLINE void set_collection(const uint16_t subschema_id) + { + type_ = static_cast(ObCollectionSQLType); + lob_scale_.set_in_row(); + set_subschema_id(subschema_id); + } protected: uint8_t type_; union @@ -1264,7 +1277,7 @@ public: } if (meta.has_lob_header() && oceanbase::is_lob_storage(get_type())) { set_has_lob_header(); - } else if (meta.is_user_defined_sql_type()) { + } else if (meta.is_user_defined_sql_type()) { // Notice: collection type is lob storage type meta_.set_udt_flags(meta.get_udt_flags()); } } @@ -1440,6 +1453,8 @@ public: inline void set_inrow() { meta_.set_inrow(); } inline void set_outrow() { meta_.set_outrow(); } inline void set_has_lob_header() { meta_.set_has_lob_header(); } + + inline void set_subschema_id(uint16_t subschema_id) { meta_.set_subschema_id(subschema_id); } void set_otimestamp_value(const ObObjType type, const ObOTimestampData &value); void set_otimestamp_value(const ObObjType type, const int64_t time_us, const uint32_t time_ctx_desc); void set_otimestamp_value(const ObObjType type, const int64_t time_us, const uint16_t time_desc); @@ -1492,6 +1507,7 @@ public: } inline void set_sql_udt(const char* ptr, int32_t size, uint16_t subschema_id = 0, uint8_t udt_flags = 0); + inline void set_sql_collection(const char* ptr, int32_t size, uint16_t subschema_id = 0, uint8_t udt_flags = 0); inline void set_udt_value(const char* ptr, int32_t size); //@} @@ -1810,7 +1826,10 @@ public: OB_INLINE bool is_geometry_inrow() const { return meta_.is_geometry_inrow(); } OB_INLINE bool is_geometry_outrow() const { return meta_.is_geometry_outrow(); } OB_INLINE bool is_user_defined_sql_type() const { return meta_.is_user_defined_sql_type(); } - OB_INLINE bool is_xml_sql_type() const { return meta_.is_user_defined_sql_type(); } + OB_INLINE bool is_xml_sql_type() const { + return meta_.is_user_defined_sql_type() && meta_.get_subschema_id() == ObXMLSqlType; + } + OB_INLINE bool is_collection_sql_type() const { return meta_.is_collection_sql_type(); } OB_INLINE bool is_timestamp_tz() const { return meta_.is_timestamp_tz(); } OB_INLINE bool is_timestamp_ltz() const { return meta_.is_timestamp_ltz(); } @@ -2695,7 +2714,9 @@ inline void ObObj::set_lob_value(const ObObjType type, const ObLobCommon *value, { meta_.set_type(type); meta_.set_inrow(); - meta_.set_collation_level(CS_LEVEL_IMPLICIT); + if (type != ObCollectionSQLType) { + meta_.set_collation_level(CS_LEVEL_IMPLICIT); + } v_.lob_ = value; val_len_ = length; } @@ -2704,7 +2725,9 @@ inline void ObObj::set_lob_value(const ObObjType type, const char *ptr, const in { meta_.set_type(type); meta_.set_inrow(); - meta_.set_collation_level(CS_LEVEL_IMPLICIT); + if (type != ObCollectionSQLType) { + meta_.set_collation_level(CS_LEVEL_IMPLICIT); + } v_.string_ = ptr; val_len_ = length; } @@ -2897,6 +2920,14 @@ inline void ObObj::set_sql_udt(const char* ptr, int32_t size, uint16_t subschema val_len_ = size; } +inline void ObObj::set_sql_collection(const char* ptr, int32_t size, uint16_t subschema_id, uint8_t udt_flags) +{ + meta_.set_collection(subschema_id); + // meta_.set_udt_flags(udt_flags); + v_.string_ = ptr; + val_len_ = size; +} + inline void ObObj::set_udt_value(const char* ptr, int32_t size) { v_.string_ = ptr; @@ -2936,6 +2967,7 @@ inline bool ObObj::need_deep_copy()const || ob_is_geometry(meta_.get_type()) || ob_is_raw(meta_.get_type()) || ob_is_user_defined_sql_type(meta_.get_type()) + || ob_is_collection_sql_type(meta_.get_type()) || ob_is_rowid_tc(meta_.get_type())) && 0 != val_len_ && NULL != get_string_ptr()) || (ob_is_number_tc(meta_.get_type()) && 0 != nmb_desc_.len_ && NULL != get_number_digits()) @@ -3566,7 +3598,7 @@ inline const void *ObObj::get_data_ptr() const { const void *ret = NULL; if (ob_is_string_type(get_type()) || ob_is_raw(get_type()) || ob_is_rowid_tc(get_type()) || ob_is_json(get_type()) - || ob_is_geometry(get_type()) || ob_is_user_defined_sql_type(get_type())) { + || ob_is_geometry(get_type()) || ob_is_user_defined_sql_type(get_type()) || ob_is_collection_sql_type(get_type())) { ret = const_cast(v_.string_); } else if (ob_is_number_tc(get_type())) { ret = const_cast(v_.nmb_digits_); @@ -3583,7 +3615,7 @@ inline const void *ObObj::get_data_ptr() const inline void ObObj::set_data_ptr(void *data_ptr) { if (ob_is_string_type(get_type()) || ob_is_raw(get_type()) || ob_is_rowid_tc(get_type()) || ob_is_json(get_type()) - || ob_is_geometry(get_type()) || ob_is_user_defined_sql_type(get_type())) { + || ob_is_geometry(get_type()) || ob_is_user_defined_sql_type(get_type()) || ob_is_collection_sql_type(get_type())) { v_.string_ = static_cast(data_ptr); } else if (ob_is_number_tc(get_type())) { v_.nmb_digits_ = static_cast(data_ptr); @@ -3643,7 +3675,8 @@ inline int64_t ObObj::get_data_length() const ob_is_lob_locator(get_type()) || ob_is_json(get_type()) || ob_is_geometry(get_type()) || - ob_is_user_defined_sql_type(get_type())) { + ob_is_user_defined_sql_type(get_type()) || + ob_is_collection_sql_type(get_type())) { ret = val_len_; } else if (ob_is_number_tc(get_type())) { ret = nmb_desc_.len_ * sizeof(uint32_t); @@ -4194,7 +4227,7 @@ OB_INLINE int64_t ObObj::get_deep_copy_size() const { int64_t ret = 0; if (is_string_type() || is_raw() || ob_is_rowid_tc(get_type()) || is_lob_locator() || is_json() - || is_geometry() || is_user_defined_sql_type() || ob_is_decimal_int(get_type())) { + || is_geometry() || is_user_defined_sql_type() || ob_is_decimal_int(get_type())|| is_collection_sql_type()) { ret += val_len_; } else if (ob_is_number_tc(get_type())) { ret += (sizeof(uint32_t) * nmb_desc_.len_); @@ -4247,6 +4280,27 @@ typedef Ob2DArray > ParamStore; + +class ObObjUDTUtil +{ +// Utils for convert pl udt baisc attributes(obobjs) to sql udt format +// basically, obj meta is store in subschema map +// only value needs serialize into a continuous sql udt buffer +public: + static int ob_udt_obj_value_serialize(const ObObj &obj, char* buf, const int64_t buf_len, int64_t& pos); + static int ob_udt_obj_value_deserialize(ObObj &obj, const char* buf, const int64_t data_len, int64_t& pos); + static int ob_udt_obj_value_get_serialize_size(const ObObj &obj, int64_t &value_len); + + static bool ob_is_supported_sql_udt(const uint64_t udt_id) + { // only oracle gis related udt is supported currently + return udt_id == T_OBJ_XML + || udt_id == T_OBJ_SDO_POINT + || udt_id == T_OBJ_SDO_GEOMETRY + || udt_id == T_OBJ_SDO_ELEMINFO_ARRAY + || udt_id == T_OBJ_SDO_ORDINATE_ARRAY; + } +}; + } } diff --git a/deps/oblib/src/lib/CMakeLists.txt b/deps/oblib/src/lib/CMakeLists.txt index 98535f801b..5e69c66ac9 100644 --- a/deps/oblib/src/lib/CMakeLists.txt +++ b/deps/oblib/src/lib/CMakeLists.txt @@ -79,6 +79,30 @@ ob_set_subtarget(oblib_lib geo geo/ob_geo_func_distance.cpp geo/ob_geo_func_isvalid.cpp geo/ob_geometry_cast.cpp + geo/ob_sdo_geo_func_to_wkb.cpp + geo/ob_wkb_to_sdo_geo_visitor.cpp + geo/ob_wkb_to_json_visitor.cpp + geo/ob_wkb_byte_order_visitor.cpp + geo/ob_geo_3d.cpp + geo/ob_sdo_geo_object.cpp + geo/ob_geo_func_equals.cpp + geo/ob_geo_func_touches.cpp + geo/ob_geo_func_centroid.cpp + geo/ob_geo_interior_point_visitor.cpp + geo/ob_geo_box_clip_visitor.cpp + geo/ob_geo_func_crosses.cpp + geo/ob_geo_func_overlaps.cpp + geo/ob_geo_elevation_visitor.cpp + geo/ob_geo_func_length.cpp + geo/ob_geo_mvt_encode_visitor.cpp + geo/ob_geo_mvt.cpp + geo/ob_vector_tile.pb-c.c + geo/ob_geo_func_symdifference.cpp + geo/ob_geo_affine_visitor.cpp + geo/ob_geo_grid_visitor.cpp + geo/ob_geo_simplify_visitor.cpp + geo/ob_geo_box_clip_visitor.cpp + geo/ob_geo_func_dissolve_polygon.cpp ) ob_set_subtarget(oblib_lib encode diff --git a/deps/oblib/src/lib/geo/ob_geo_3d.cpp b/deps/oblib/src/lib/geo/ob_geo_3d.cpp new file mode 100644 index 0000000000..5216fb0c57 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_3d.cpp @@ -0,0 +1,1617 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "ob_geo_3d.h" +#include "common/ob_smart_call.h" +#include "ob_geo_to_wkt_visitor.h" +#include "lib/utility/ob_fast_convert.h" +#include "lib/geo/ob_geo_latlong_check_visitor.h" +namespace oceanbase +{ +namespace common +{ + +ObGeoWkbByteOrder ObGeometry3D::byteorder() const +{ + return byteorder(0); +} + +ObGeoWkbByteOrder ObGeometry3D::byteorder(uint64_t pos) const +{ + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::INVALID; + const char* ptr = val(); + if (OB_NOT_NULL(ptr) && pos + WKB_GEO_BO_SIZE <= length()) { + uint8_t *p = reinterpret_cast(const_cast(ptr + pos)); + if (*p == 0 || *p == 1) { + bo = static_cast(*p); + } + } + return bo; +} + +ObGeoType ObGeometry3D::type() const +{ + return type(0); +} + +ObGeoType ObGeometry3D::type(uint64_t pos) const +{ + ObGeoType geo_type = ObGeoType::GEO3DTYPEMAX; + const char* ptr = val(); + if (OB_NOT_NULL(ptr) && (pos + WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE <= length())) { + ObGeoWkbByteOrder bo = byteorder(pos); + geo_type = static_cast(ObGeoWkbByteOrderUtil::read(ptr + pos + WKB_GEO_BO_SIZE, bo)); + } + return geo_type; +} + +int ObGeometry3D::to_2d_geo(ObIAllocator &allocator, ObGeometry *&res) +{ + int ret = OB_SUCCESS; + ObString wkb_2d; + ObGeoType geo_type = type(); + if (geo_type > ObGeoType::GEOMETRYCOLLECTION && geo_type < ObGeoType::GEO3DTYPEMAX) { + ObGeo3DTo2DVisitor visitor; + ObGeoWkbByteOrder bo = byteorder(); + ObWkbBuffer *wkb_buf = NULL; + set_pos(0); + if (OB_ISNULL(wkb_buf = OB_NEWx(ObWkbBuffer, &allocator, allocator, bo))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create wkb buffer", K(ret)); + } else if (FALSE_IT(visitor.set_wkb_buf(wkb_buf))) { + } else if (OB_FAIL(visit_wkb_inner(visitor))) { + LOG_WARN("fail to convert to 2d wkb", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra byte unparse", K(ret), K(cur_pos_), K(length())); + } else { + wkb_2d.assign_ptr(wkb_buf->ptr(), wkb_buf->length()); + geo_type = static_cast(static_cast(geo_type) - ObGeoTypeUtil::WKB_3D_TYPE_OFFSET); + } + } else { + wkb_2d = data_; + } + if (OB_SUCC(ret)) { + bool is_geog = (crs_ == ObGeoCRS::Geographic) ? true : false; + if (OB_FAIL(ObGeoTypeUtil::create_geo_by_type(*allocator_, geo_type, is_geog, true, res))) { + LOG_WARN("fail to create 2d geo obj", K(ret), K(geo_type), K(is_geog)); + } else { + res->set_data(wkb_2d); + } + } + + return ret; +} + +int ObGeometry3D::read_header(ObGeoWkbByteOrder &bo, ObGeoType &geo_type) +{ + int ret = OB_SUCCESS; + const char *ptr = val(); + uint64_t header_len = EWKB_COMMON_WKB_HEADER_LEN; + if (OB_ISNULL(ptr) || (cur_pos_ + header_len > length())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("pointer or position is wrong", K(ret), K(ptr)); + } else { + bo = byteorder(cur_pos_); + const char *geo_type_ptr = ptr + cur_pos_ + WKB_GEO_BO_SIZE; + geo_type = static_cast(ObGeoWkbByteOrderUtil::read(geo_type_ptr, bo)); + cur_pos_ += header_len; + } + return ret; +} + +int ObGeometry3D::read_nums_value(ObGeoWkbByteOrder bo, uint32_t &nums) +{ + int ret = OB_SUCCESS; + const char *ptr = val(); + if (OB_ISNULL(ptr) || (cur_pos_ + WKB_GEO_ELEMENT_NUM_SIZE > length())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("unexpect ptr or pos to read nums value"); + } else { + nums = ObGeoWkbByteOrderUtil::read(ptr + cur_pos_, bo); + cur_pos_ += WKB_GEO_ELEMENT_NUM_SIZE; + } + return ret; +} + +int ObGeometry3D::to_wkt(ObIAllocator &allocator, ObString &wkt, uint32_t srid/* = 0*/, int64_t maxdecimaldigits/* = -1*/) +{ + int ret = OB_SUCCESS; + ObStringBuffer *buf = NULL; + ObGeo3DToWktVisitor visitor(maxdecimaldigits); + set_pos(0); + if (OB_ISNULL(buf = OB_NEWx(ObStringBuffer, &allocator, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", K(ret)); + } else if (srid != 0) { + ObFastFormatInt ffi(srid); + uint64_t reserve_len = strlen("srid") + 1 + ffi.length() + 1; + // [srid][=][1][2][3][4][;] + if (OB_FAIL(buf->reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (OB_FAIL(buf->append("SRID="))) { + LOG_WARN("fail to append buffer", K(ret)); + } else if (OB_FAIL(buf->append(ffi.ptr(), ffi.length()))) { + LOG_WARN("fail to append buffer", K(ret), K(ffi.length())); + } else if (OB_FAIL(buf->append(";"))) { + LOG_WARN("fail to append buffer", K(ret)); + } + } + + if (OB_FAIL(ret)) { + } else if (FALSE_IT(visitor.set_wkt_buf(buf))) { + } else if (OB_FAIL(visit_wkb_inner(visitor))) { + LOG_WARN("fail to convert to wkt", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } else { + wkt.assign_ptr(buf->ptr(), buf->length()); + } + return ret; +} + +int ObGeometry3D::check_wkb_valid() +{ + int ret = OB_SUCCESS; + ObGeo3DChecker checker; + set_pos(0); + if (OB_FAIL(visit_wkb_inner(checker))) { + LOG_WARN("fail to check wkb valid", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } + return ret; +} + +int ObGeometry3D::check_3d_coordinate_range(const ObSrsItem *srs, const bool is_normalized, ObGeoCoordRangeResult &result) +{ + int ret = OB_SUCCESS; + ObGeo3DCoordinateRangeVisitor range_visitor(srs, is_normalized); + set_pos(0); + if (OB_ISNULL(srs)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("srs is NULL", K(ret)); + } else if (OB_FAIL(visit_wkb_inner(range_visitor))) { + LOG_WARN("fail to check wkb valid", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } else { + range_visitor.get_coord_range_result(result); + } + return ret; +} + + +int ObGeometry3D::reverse_coordinate() +{ + int ret = OB_SUCCESS; + ObGeo3DReserverCoordinate visitor; + set_pos(0); + if (OB_FAIL(visit_wkb_inner(visitor))) { + LOG_WARN("fail to check wkb valid", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } + return ret; +} + +int ObGeometry3D::visit_wkb_inner(ObGeo3DVisitor &visitor) +{ + int ret = OB_SUCCESS; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::INVALID; + ObGeoType geo_type = ObGeoType::GEOTYPEMAX; + if (OB_FAIL(read_header(bo, geo_type))) { + LOG_WARN("fail to read header", K(ret)); + } else if (OB_FAIL(visitor.visit_header(bo, geo_type))) { + LOG_WARN("bo or geo type is invalid", K(ret), K(bo), K(geo_type)); + } else { + switch (geo_type) { + case ObGeoType::POINTZ: { + if (OB_FAIL(visit_pointz(bo, visitor, false))) { + LOG_WARN("fail to visit pointz", K(ret)); + } + break; + } + case ObGeoType::LINESTRINGZ: { + if (OB_FAIL(visit_linestringz(bo, visitor))) { + LOG_WARN("fail to visit linestringz", K(ret)); + } + break; + } + case ObGeoType::POLYGONZ: { + if (OB_FAIL(visit_polygonz(bo, visitor))) { + LOG_WARN("fail to visit polygonz", K(ret)); + } + break; + } + case ObGeoType::MULTIPOINTZ: + case ObGeoType::MULTILINESTRINGZ: + case ObGeoType::MULTIPOLYGONZ: { + if (OB_FAIL(visit_multi_geomz(bo, geo_type, visitor))) { + LOG_WARN("fail to visit multi geo", K(ret)); + } + break; + } + case ObGeoType::GEOMETRYCOLLECTIONZ: { + if (OB_FAIL(visit_collectionz(bo, visitor))) { + LOG_WARN("fail to visit collection", K(ret)); + } + break; + } + default: { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid geo type", K(ret), K(geo_type)); + break; + } + } + } + return ret; +} + +int ObGeometry3D::visit_pointz_inner(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor) +{ + int ret = OB_SUCCESS; + const char *ptr = val(); + uint64_t pointz_len = WKB_POINT_DATA_SIZE + WKB_GEO_DOUBLE_STORED_SIZE; + if (OB_ISNULL(ptr) || (cur_pos_ + pointz_len > length())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("copy pointer or position is wrong", K(ret), K(ptr)); + } else { + double x = ObGeoWkbByteOrderUtil::read(ptr + cur_pos_, bo); + double y = ObGeoWkbByteOrderUtil::read(ptr + cur_pos_ + WKB_GEO_DOUBLE_STORED_SIZE, bo); + double z = ObGeoWkbByteOrderUtil::read(ptr + cur_pos_ + 2 * WKB_GEO_DOUBLE_STORED_SIZE, bo); + if (OB_FAIL(visitor.visit_pointz_inner(x, y, z))) { + LOG_WARN("fail to visit pointz", K(ret)); + } else { + cur_pos_ += 3 * WKB_GEO_DOUBLE_STORED_SIZE; + } + } + return ret; +} + +int ObGeometry3D::visit_pointz(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor, bool is_inner /* =false*/) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(visitor.visit_pointz_start(this, is_inner))) { + LOG_WARN("fail to visit pointz start", K(ret)); + } else if (OB_FAIL(visit_pointz_inner(bo, visitor))) { + LOG_WARN("fail to visit point", K(ret)); + } else if (OB_FAIL(visitor.visit_pointz_end(this, is_inner))) { + LOG_WARN("fail to visit pointz end", K(ret)); + } + return ret; +} + +int ObGeometry3D::visit_linestringz(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor, ObLineType line_type /* =false */) +{ + int ret = OB_SUCCESS; + uint32_t nums = 0; + if (OB_FAIL(read_nums_value(bo, nums))) { + LOG_WARN("fail to read nums value", K(ret)); + } else if (OB_FAIL(visitor.visit_linestringz_start(this, nums, line_type))) { + LOG_WARN("fail to visit linestring start", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < nums; i++) { + if (OB_FAIL(visit_pointz(bo, visitor, true))) { + LOG_WARN("fail to visit inner point", K(ret)); + } else if (OB_FAIL(visitor.visit_linestringz_item_after(this, i, line_type))) { + LOG_WARN("fail to visit linestring inner", K(ret), K(i)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(visitor.visit_linestringz_end(this, nums, line_type))) { + LOG_WARN("fail to visit linestring end", K(ret)); + } + return ret; +} + +int ObGeometry3D::visit_polygonz(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor) +{ + int ret = OB_SUCCESS; + uint32_t ring_nums = 0; + if (OB_FAIL(read_nums_value(bo, ring_nums))) { + LOG_WARN("fail to read ring nums", K(ret)); + } else if (OB_FAIL(visitor.visit_polygonz_start(this, ring_nums))) { + LOG_WARN("fail to visit polygonz start", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < ring_nums; i++) { + if (OB_FAIL(visit_linestringz(bo, visitor, i == 0 ? ObLineType::ExterRing : ObLineType::InnerRing))) { + LOG_WARN("fail to visit linestring", K(ret)); + } else if (OB_FAIL(visitor.visit_polygonz_item_after(this, i))) { + LOG_WARN("fail to visit polygonz innert", K(ret), K(i)); + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(visitor.visit_polygonz_end(this, ring_nums))) { + LOG_WARN("fail to visit polygonz end", K(ret)); + } + return ret; +} + +int ObGeometry3D::visit_multi_geomz(ObGeoWkbByteOrder bo, ObGeoType geo_type, ObGeo3DVisitor &visitor) +{ + int ret = OB_SUCCESS; + ObFunction visit_func; + uint32_t geo_nums = 0; + ObGeoWkbByteOrder sub_bo = ObGeoWkbByteOrder::INVALID; + ObGeoType sub_geo_type = ObGeoType::GEO3DTYPEMAX; + if (geo_type == ObGeoType::MULTIPOINTZ) { + visit_func = std::bind(&ObGeometry3D::visit_pointz, this, std::placeholders::_1, std::placeholders::_2, true); + } else if (geo_type == ObGeoType::MULTILINESTRINGZ) { + visit_func = std::bind(&ObGeometry3D::visit_linestringz, this, std::placeholders::_1, std::placeholders::_2, ObLineType::Line); + } else if (geo_type == ObGeoType::MULTIPOLYGONZ) { + visit_func = std::bind(&ObGeometry3D::visit_polygonz, this, std::placeholders::_1, std::placeholders::_2); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected geo type", K(ret), K(geo_type)); + } + + visitor.set_is_multi(true); + if (OB_FAIL(ret)) { + } else if (OB_FAIL(read_nums_value(bo, geo_nums))) { + LOG_WARN("fail to read nums", K(ret), K(geo_type)); + } else if (OB_FAIL(visitor.visit_multi_geom_start(geo_type, this, geo_nums))) { + LOG_WARN("fail to visit multi geom", K(ret)); + } + for (uint32_t i = 0; i < geo_nums && OB_SUCC(ret); i++) { + if (OB_FAIL(read_header(sub_bo, sub_geo_type))) { + LOG_WARN("fail to read header", K(ret)); + } else if (OB_FAIL(visitor.visit_header(sub_bo, sub_geo_type, true))) { + LOG_WARN("fail to visit header", K(ret), K(sub_bo), K(sub_geo_type)); + } else if (OB_FAIL(visit_func(bo, visitor))) { + LOG_WARN("fail to visit geom", K(ret)); + } else if (OB_FAIL(visitor.visit_multi_geom_item_after(geo_type, this, i))) { + LOG_WARN("fail to visit multi geom inner", K(ret), K(i)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(visitor.visit_multi_geom_end(geo_type, this, geo_nums))) { + LOG_WARN("fail to visit multi geom", K(ret)); + } else { + visitor.set_is_multi(false); + } + return ret; +} + +int ObGeometry3D::visit_collectionz(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor) +{ + int ret = OB_SUCCESS; + uint32_t geo_nums = 0; + if (OB_FAIL(read_nums_value(bo, geo_nums))) { + LOG_WARN("fail to read nums", K(ret)); + } else if (OB_FAIL(visitor.visit_collectionz_start(this, geo_nums))) { + LOG_WARN("fail to visit geometrycollection start", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < geo_nums; i++) { + if (OB_FAIL(SMART_CALL(visit_wkb_inner(visitor)))) { + LOG_WARN("fail to convert geoms in collection", K(ret), K(i)); + } else if (OB_FAIL(visitor.visit_collectionz_item_after(this, i))) { + LOG_WARN("fail to visit collection innert", K(ret), K(i)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(visitor.visit_collectionz_end(this, geo_nums))) { + LOG_WARN("fail to visit geometrycollection end", K(ret)); + } + return ret; +} + +int ObGeometry3D::to_sdo_geometry(ObSdoGeoObject &sdo_geo) +{ + int ret = OB_SUCCESS; + ObGeo3DWkbToSdoGeoVisitor visitor; + set_pos(0); + if (OB_FAIL(visitor.init(&sdo_geo))) { + LOG_WARN("fail to init geo3d wkb to sdo geo visitor", K(ret)); + } else if (OB_FAIL(visit_wkb_inner(visitor))) { + LOG_WARN("fail to check wkb valid", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } + return ret; +} + +int ObGeometry3D::create_elevation_extent(ObGeoElevationExtent &extent) +{ + int ret = OB_SUCCESS; + ObGeo3DElevationVisitor visitor(extent); + set_pos(0); + if (OB_FAIL(visit_wkb_inner(visitor))) { + LOG_WARN("fail to check wkb valid", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } + return ret; +} + +int ObGeometry3D::normalize(const ObSrsItem *srs, uint32_t &zoom_in_value) +{ + int ret = OB_SUCCESS; + ObGeo3DNormalizeVisitor visitor(srs); + set_pos(0); + if (OB_FAIL(visit_wkb_inner(visitor))) { + LOG_WARN("fail to check wkb valid", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } else { + zoom_in_value = visitor.get_zoom_in_value(); + } + return ret; +} + +bool ObGeometry3D::is_empty() const +{ + bool bret = false; + ObGeoType type = this->type(); + if (type >= ObGeoType::GEO3DTYPEMAX || type <= ObGeoType::GEOTYPEMAX) { + bret = true; + } else if (type == ObGeoType::POINTZ) { + uint32_t bo_type = WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE; + uint32_t lng = bo_type + 3 * WKB_GEO_DOUBLE_STORED_SIZE; + if (lng > this->length()) { + bret = true; + } else { + const char *ptr = this->val(); + ObGeoWkbByteOrder bo = this->byteorder(); + double x = ObGeoWkbByteOrderUtil::read(ptr + bo_type, bo); + double y = ObGeoWkbByteOrderUtil::read(ptr + bo_type + WKB_GEO_DOUBLE_STORED_SIZE, bo); + double z = ObGeoWkbByteOrderUtil::read(ptr + bo_type + 2 * WKB_GEO_DOUBLE_STORED_SIZE, bo); + bret = std::isnan(x) || std::isnan(y) || std::isnan(z); + } + } else { + uint32_t bo_type = WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE; + if (WKB_COMMON_WKB_HEADER_LEN > this->length()) { + bret = true; + } else { + const char *ptr = this->val(); + ObGeoWkbByteOrder bo = this->byteorder(); + uint32_t size = ObGeoWkbByteOrderUtil::read(ptr + bo_type, bo); + bret = size <= 0; + } + } + return bret; +} + +int ObGeometry3D::check_empty(bool &is_empty) +{ + int ret = OB_SUCCESS; + ObGeo3DEmptyVisitor visitor; + set_pos(0); + if (OB_FAIL(visit_wkb_inner(visitor))) { + LOG_WARN("fail to check wkb valid", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } else { + is_empty = visitor.is_empty(); + } + return ret; +} + +/**************************************ObGeo3DVisitor**************************************/ + +int ObGeo3DVisitor::visit_header(ObGeoWkbByteOrder bo, ObGeoType geo_type, bool is_sub_type /* = false */) +{ + UNUSED(bo); + UNUSED(geo_type); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_pointz_inner(double x, double y, double z) +{ + UNUSED(x); + UNUSED(y); + UNUSED(z); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_pointz_end(ObGeometry3D *geo, bool is_inner) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + UNUSED(geo); + UNUSED(line_type); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_linestringz_item_after(ObGeometry3D *geo, uint32_t idx, ObLineType line_type) +{ + UNUSED(geo); + UNUSED(idx); + UNUSED(line_type); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_linestringz_end(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + UNUSED(geo); + UNUSED(line_type); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_polygonz_start(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_polygonz_item_after(ObGeometry3D *geo, uint32_t idx) +{ + UNUSED(geo); + UNUSED(idx); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_polygonz_end(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_multi_geom_item_after(ObGeoType geo_type, ObGeometry3D *geo, uint32_t idx) +{ + UNUSED(geo); + UNUSED(idx); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_multi_geom_end(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_collectionz_start(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_collectionz_item_after(ObGeometry3D *geo, uint32_t idx) +{ + UNUSED(geo); + UNUSED(idx); + return OB_SUCCESS; +} + +int ObGeo3DVisitor::visit_collectionz_end(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObGeometry3D::correct_lon_lat(const ObSrsItem *srs) +{ + int ret = OB_SUCCESS; + ObGeo3DLonLatChecker checker(srs); + set_pos(0); + if (OB_FAIL(visit_wkb_inner(checker))) { + LOG_WARN("fail to check wkb valid", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } + return ret; +} + +/**************************************ObGeo3DChecker**************************************/ + +int ObGeo3DChecker::visit_header(ObGeoWkbByteOrder bo, ObGeoType geo_type, bool is_sub_type) +{ + UNUSED(is_sub_type); + int ret = OB_SUCCESS; + if (bo == ObGeoWkbByteOrder::INVALID || !ObGeoTypeUtil::is_3d_geo_type(geo_type)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("bo or geo type is invalid", K(ret), K(bo), K(geo_type)); + } + return ret; +} + +int ObGeo3DChecker::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + UNUSED(is_inner); + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else { + const char *ptr = geo->val(); + uint64_t cur_pos = geo->get_pos(); + if (cur_pos + 3 * WKB_GEO_DOUBLE_STORED_SIZE > geo->length()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid wkb point", K(ret)); + } + } + return ret; +} + +int ObGeo3DChecker::visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else { + const char *ptr = geo->val(); + uint64_t cur_pos = geo->get_pos(); + if (OB_ISNULL(ptr) || (cur_pos + WKB_GEO_ELEMENT_NUM_SIZE > geo->length())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("unexpect ptr or pos to read nums value"); + } else { + ObGeoWkbByteOrder bo = geo->byteorder(); + if (line_type != ObLineType::Line && nums < 4) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid nums point for ring", K(ret), K(nums)); + } else if (line_type == ObLineType::Line && nums < 2) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid nums point for linestring", K(ret), K(nums)); + } else if (cur_pos + nums * 3 * WKB_GEO_DOUBLE_STORED_SIZE > geo->length()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("points nums is not match", K(ret), K(line_type), K(nums)); + } + } + } + return ret; +} + +/**************************************ObGeo3DTo2DVisitor**************************************/ + +int ObGeo3DTo2DVisitor::visit_header(ObGeoWkbByteOrder bo, ObGeoType geo_type, bool is_sub_type) +{ + int ret = OB_SUCCESS; + uint64_t header_len = EWKB_COMMON_WKB_HEADER_LEN; + if (bo == ObGeoWkbByteOrder::INVALID || !ObGeoTypeUtil::is_3d_geo_type(geo_type)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("bo or geo type is invalid", K(ret), K(bo), K(geo_type)); + } else if (OB_ISNULL(wkb_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkb_buf_ is NULL", K(ret)); + } else if (OB_FAIL(wkb_buf_->reserve(header_len))) { + LOG_WARN("fail to resverse buffer", K(ret)); + } else if (OB_FAIL(wkb_buf_->append(static_cast(bo)))) { + LOG_WARN("fail to append byte order", K(ret)); + } else if (OB_FAIL(wkb_buf_->append(static_cast(geo_type) - ObGeoTypeUtil::WKB_3D_TYPE_OFFSET))) { + LOG_WARN("fail to append type", K(ret)); + } + return ret; +} + +int ObGeo3DTo2DVisitor::append_nums(uint32_t nums) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(wkb_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkb_buf_ is NULL", K(ret)); + } else if (OB_FAIL(wkb_buf_->append(nums))) { + LOG_WARN("fail to append nums value", K(ret)); + } + return ret; +} + +int ObGeo3DTo2DVisitor::visit_pointz_inner(double x, double y, double z) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(wkb_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkb_buf_ is NULL", K(ret)); + } else if (OB_FAIL(wkb_buf_->append(x))) { + LOG_WARN("fail to append x", K(ret), K(x)); + } else if (OB_FAIL(wkb_buf_->append(y))) { + LOG_WARN("fail to append y", K(ret), K(y)); + } + return ret; +} + +int ObGeo3DTo2DVisitor::visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + UNUSED(geo); + UNUSED(line_type); + return append_nums(nums); +} + +int ObGeo3DTo2DVisitor::visit_polygonz_start(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + return append_nums(nums); +} + +int ObGeo3DTo2DVisitor::visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo_type); + UNUSED(geo); + return append_nums(nums); +} + +int ObGeo3DTo2DVisitor::visit_collectionz_start(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + return append_nums(nums); +} + +/**************************************ObGeo3DToWktVisitor**************************************/ + +ObGeo3DToWktVisitor::ObGeo3DToWktVisitor(int64_t maxdecimaldigits/* = -1*/) + : wkt_buf_(NULL), is_oracle_mode_(lib::is_oracle_mode()), is_mpt_visit_(false) +{ + if (maxdecimaldigits >= 0 && maxdecimaldigits < ObGeoToWktVisitor::MAX_DIGITS_IN_DOUBLE) { + scale_ = maxdecimaldigits; + has_scale_ = true; + } else { + scale_ = ObGeoToWktVisitor::MAX_DIGITS_IN_DOUBLE; + has_scale_ = false; + } +} + +int ObGeo3DToWktVisitor::visit_header(ObGeoWkbByteOrder bo, ObGeoType geo_type, bool is_sub_type) +{ + int ret = OB_SUCCESS; + if (!is_sub_type) { + if (OB_ISNULL(wkt_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkt_buf_ is NULL", K(ret)); + } else if (!is_oracle_mode_ && OB_FAIL(wkt_buf_->append(ObGeoTypeUtil::get_geo_name_by_type(geo_type)))) { + LOG_WARN("fail to append type name", K(ret), K(geo_type)); + } else if (is_oracle_mode_ && OB_FAIL(wkt_buf_->append(ObGeoTypeUtil::get_geo_name_by_type_oracle(geo_type)))) { + LOG_WARN("fail to append type name", K(ret), K(geo_type)); + } else if (OB_FAIL(wkt_buf_->append(" "))) { + LOG_WARN("fail to append comma", K(ret)); + } + } + return ret; +} + +int ObGeo3DToWktVisitor::append_paren(bool is_left) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(wkt_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkt_buf_ is NULL", K(ret)); + } else if (is_left && OB_FAIL(wkt_buf_->append("("))) { + LOG_WARN("fail to append left paren", K(ret)); + } else if (!is_left && OB_FAIL(wkt_buf_->append(")"))) { + LOG_WARN("fail to append right paren", K(ret)); + } + return ret; +} + +int ObGeo3DToWktVisitor::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + bool ret = OB_SUCCESS; + if (is_mpt_visit_ || (!is_multi() && !is_inner)) { + ret = append_paren(true); + } + return ret; +} + +int ObGeo3DToWktVisitor::visit_pointz_end(ObGeometry3D *geo, bool is_inner) +{ + bool ret = OB_SUCCESS; + if (is_mpt_visit_ || (!is_multi() && !is_inner)) { + ret = append_paren(false); + } + return ret; +} + +int ObGeo3DToWktVisitor::visit_pointz_inner(double x, double y, double z) +{ + int ret = OB_SUCCESS; + uint64_t double_buff_size = ObGeoToWktVisitor::MAX_DIGITS_IN_DOUBLE; + if (OB_ISNULL(wkt_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkt_buf_ is NULL", K(ret)); + } else { + uint64_t len_x = 0; + uint64_t len_y = 0; + uint64_t len_z = 0; + char *buff_ptr = NULL; + if (OB_FAIL(wkt_buf_->reserve(3 * double_buff_size + 2))) { + LOG_WARN("fail to reserve buffer", K(ret)); + } else if (FALSE_IT(buff_ptr = wkt_buf_->ptr() + wkt_buf_->length())) { + } else if (OB_FAIL(ObGeoToWktVisitor::convert_double_to_str(buff_ptr, double_buff_size, x, has_scale_, scale_, is_oracle_mode_, len_x))) { + LOG_WARN("fail to append x val to buffer", K(ret)); + } else if (OB_FAIL(wkt_buf_->set_length(wkt_buf_->length() + len_x))) { + LOG_WARN("fail to set buffer x len", K(ret), K(len_x)); + } else if (OB_FAIL(wkt_buf_->append(" "))) { + LOG_WARN("fail to append space", K(ret)); + } else if (FALSE_IT(buff_ptr = wkt_buf_->ptr() + wkt_buf_->length())) { + } else if (OB_FAIL(ObGeoToWktVisitor::convert_double_to_str(buff_ptr, double_buff_size, y, has_scale_, scale_, is_oracle_mode_, len_y))) { + LOG_WARN("fail to append y val to buffer", K(ret)); + } else if (OB_FAIL(wkt_buf_->set_length(wkt_buf_->length() + len_y))) { + LOG_WARN("fail to set buffer y len", K(ret), K(len_y)); + } else if (OB_FAIL(wkt_buf_->append(" "))) { + LOG_WARN("fail to append space", K(ret)); + } else if (FALSE_IT(buff_ptr = wkt_buf_->ptr() + wkt_buf_->length())) { + } else if (OB_FAIL(ObGeoToWktVisitor::convert_double_to_str(buff_ptr, double_buff_size, z, has_scale_, scale_, is_oracle_mode_, len_z))) { + LOG_WARN("fail to append z val to buffer", K(ret)); + } else if (OB_FAIL(wkt_buf_->set_length(wkt_buf_->length() + len_z))) { + LOG_WARN("fail to set buffer x len", K(ret), K(len_z)); + } + } + return ret; +} + +int ObGeo3DToWktVisitor::remove_comma() +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(wkt_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkt_buf_ is NULL", K(ret)); + } else if (is_oracle_mode_) { + if (wkt_buf_->length() > 1 && wkt_buf_->ptr()[wkt_buf_->length() - 1] == ' ' + && wkt_buf_->ptr()[wkt_buf_->length() - 2] == ',') { + if (OB_FAIL(wkt_buf_->set_length(wkt_buf_->length() - 2))) { + LOG_WARN("fail to set length", K(ret)); + } + } + } else { + if (wkt_buf_->length() > 0 && wkt_buf_->ptr()[wkt_buf_->length() - 1] == ',') { + if (OB_FAIL(wkt_buf_->set_length(wkt_buf_->length() - 1))) { + LOG_WARN("fail to set length", K(ret)); + } + } + } + return ret; +} + +int ObGeo3DToWktVisitor::append_comma() +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(wkt_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkt_buf_ is NULL", K(ret)); + } else if (OB_FAIL(wkt_buf_->append(","))) { + LOG_WARN("fail to append left paren", K(ret)); + } else if (is_oracle_mode_) { + if (OB_FAIL(wkt_buf_->append(" "))) { + LOG_WARN("fail to append comma", K(ret)); + } + } + return ret; +} + +int ObGeo3DToWktVisitor::visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + UNUSED(geo); + UNUSED(line_type); + return append_paren(true); +} + +int ObGeo3DToWktVisitor::visit_linestringz_item_after(ObGeometry3D *geo, uint32_t idx, ObLineType line_type) +{ + UNUSED(geo); + UNUSED(idx); + UNUSED(line_type); + return append_comma(); +} + +int ObGeo3DToWktVisitor::visit_linestringz_end(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + UNUSED(geo); + UNUSED(line_type); + int ret = OB_SUCCESS; + if (OB_FAIL(remove_comma())) { + LOG_WARN("fail to remove comma", K(ret)); + } else if (OB_FAIL(append_paren(false))) { + LOG_WARN("fail to append paren", K(ret)); + } + return ret; +} + +int ObGeo3DToWktVisitor::visit_polygonz_start(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + return append_paren(true); +} + +int ObGeo3DToWktVisitor::visit_polygonz_item_after(ObGeometry3D *geo, uint32_t idx) +{ + UNUSED(geo); + UNUSED(idx); + return append_comma(); +} + +int ObGeo3DToWktVisitor::visit_polygonz_end(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + int ret = OB_SUCCESS; + if (OB_FAIL(remove_comma())) { + LOG_WARN("fail to remove comma", K(ret)); + } else if (OB_FAIL(append_paren(false))) { + LOG_WARN("fail to append paren", K(ret)); + } + return ret; +} + +int ObGeo3DToWktVisitor::visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + if (geo_type == ObGeoType::MULTIPOINTZ) { + is_mpt_visit_ = true; + } + return append_paren(true); +} + +int ObGeo3DToWktVisitor::visit_multi_geom_item_after(ObGeoType geo_type, ObGeometry3D *geo, uint32_t idx) +{ + UNUSED(geo); + UNUSED(idx); + UNUSED(geo_type); + return append_comma(); +} + +int ObGeo3DToWktVisitor::visit_multi_geom_end(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + int ret = OB_SUCCESS; + if (geo_type == ObGeoType::MULTIPOINTZ) { + is_mpt_visit_ = false; + } + if (OB_FAIL(remove_comma())) { + LOG_WARN("fail to remove comma", K(ret)); + } else if (OB_FAIL(append_paren(false))) { + LOG_WARN("fail to append paren", K(ret)); + } + return ret; +} + +int ObGeo3DToWktVisitor::visit_collectionz_start(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + int ret = OB_SUCCESS; + if (OB_ISNULL(wkt_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkt_buf_ is NULL", K(ret)); + } else if (nums == 0 && OB_FAIL(wkt_buf_->append("EMPTY"))) { + LOG_WARN("fail to append empty", K(ret)); + } else if (nums > 0 && OB_FAIL(append_paren(true))) { + LOG_WARN("fail to append left paren", K(ret)); + } + return ret; +} + +int ObGeo3DToWktVisitor::visit_collectionz_item_after(ObGeometry3D *geo, uint32_t idx) +{ + UNUSED(geo); + UNUSED(idx); + return append_comma(); +} + +int ObGeo3DToWktVisitor::visit_collectionz_end(ObGeometry3D *geo, uint32_t nums) +{ + UNUSED(geo); + int ret = OB_SUCCESS; + if (OB_ISNULL(wkt_buf_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("wkt_buf_ is NULL", K(ret)); + } else if (nums == 0) { + } else if (nums > 0) { + if (OB_FAIL(remove_comma())) { + LOG_WARN("fail to remove comma", K(ret)); + } else if (OB_FAIL(append_paren(false))) { + LOG_WARN("fail to append paren", K(ret)); + } + } + return ret; +} + +/**************************************ObGeo3DReserverCoordinate**************************************/ + +int ObGeo3DReserverCoordinate::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + UNUSED(is_inner); + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else { + char *ptr = const_cast(geo->val()); + uint32_t cur_pos = geo->get_pos(); + ObGeoWkbByteOrder bo = geo->byteorder(); + double x = ObGeoWkbByteOrderUtil::read(ptr + cur_pos, bo); + double y = ObGeoWkbByteOrderUtil::read(ptr + cur_pos + WKB_GEO_DOUBLE_STORED_SIZE, bo); + ObGeoWkbByteOrderUtil::write(ptr + cur_pos, y, bo); + ObGeoWkbByteOrderUtil::write(ptr + cur_pos + WKB_GEO_DOUBLE_STORED_SIZE, x, bo); + } + return ret; +} + +/**************************************ObGeo3DCoordinateRangeVisitor**************************************/ + +void ObGeo3DCoordinateRangeVisitor::get_coord_range_result(ObGeoCoordRangeResult &result) +{ + result.is_lati_out_range_ = is_lati_out_range_; + result.is_long_out_range_ = is_long_out_range_; + result.value_out_range_ = value_out_range_; +} + +int ObGeo3DCoordinateRangeVisitor::visit_pointz_inner(double x, double y, double z) +{ + int ret = OB_SUCCESS; + ObGeoCoordRangeResult result; + if (OB_ISNULL(srs_)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret)); + } else if (srs_->srs_type() == ObSrsType::PROJECTED_SRS) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("srs is projected type", K(srs_)); + } else if (OB_FAIL(ObGeoCoordinateRangeVisitor::calculate_point_range(srs_, x, y, + is_normalized_, result))){ + LOG_WARN("failed to calculate point range", K(ret), K(x), K(y)); + } else { + is_lati_out_range_ = result.is_lati_out_range_; + is_long_out_range_ = result.is_long_out_range_; + value_out_range_ = result.value_out_range_; + } + return ret; +} + +/**************************************ObGeo3DWkbToSdoGeoVisitor**************************************/ + +int ObGeo3DWkbToSdoGeoVisitor::init(ObSdoGeoObject *geo, uint32_t srid) +{ + INIT_SUCC(ret); + sdo_geo_ = geo; + if (OB_ISNULL(sdo_geo_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("ObSdoGeoObject ptr is null", K(ret)); + } else { + sdo_geo_->set_srid(srid); + } + return ret; +} + +int ObGeo3DWkbToSdoGeoVisitor::append_elem_info(uint64_t offset, uint64_t etype, uint64_t interpretation) +{ + INIT_SUCC(ret); + if (OB_FAIL(sdo_geo_->append_elem(offset))) { + LOG_WARN("fail to append offset to sdo_elem_info", K(ret), K(offset)); + } else if (OB_FAIL(sdo_geo_->append_elem(etype))) { + LOG_WARN("fail to append etype to sdo_elem_info", K(ret), K(etype)); + } else if (OB_FAIL(sdo_geo_->append_elem(interpretation))) { + LOG_WARN("fail to append interpretation to sdo_elem_info", K(ret), K(interpretation)); + } + return ret; +} + +int ObGeo3DWkbToSdoGeoVisitor::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + INIT_SUCC(ret); + if (OB_ISNULL(sdo_geo_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("ObSdoGeoObject ptr is null", K(ret)); + } else if (!is_multi_visit_ && !is_collection_visit_) { + sdo_geo_->set_gtype(geo->type()); + } + return ret; +} + +int ObGeo3DWkbToSdoGeoVisitor::visit_pointz_inner(double x, double y, double z) +{ + INIT_SUCC(ret); + if (OB_ISNULL(sdo_geo_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("ObSdoGeoObject ptr is null", K(ret)); + } else if (is_multi_visit_ || is_collection_visit_ || is_inner_element_) { + // elem_info = (start_idx, 1, 1) + if (!is_multi_visit_ && !is_inner_element_ && OB_FAIL(append_elem_info(sdo_geo_->get_ordinates().size() + 1, 1, 1))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(sdo_geo_->get_ordinates().size())); + } else if (OB_FAIL(sdo_geo_->append_ori(x))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(x)); + } else if (OB_FAIL(sdo_geo_->append_ori(y))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(y)); + } else if (OB_FAIL(sdo_geo_->append_ori(z))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(z)); + } + } else { + sdo_geo_->get_point().set_x(x); + sdo_geo_->get_point().set_y(y); + sdo_geo_->get_point().set_z(z); + } + return ret; +} + +int ObGeo3DWkbToSdoGeoVisitor::visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + INIT_SUCC(ret); + if (!is_multi_visit_ && !is_collection_visit_ && !is_inner_element_ && line_type == ObLineType::Line) { + sdo_geo_->set_gtype(geo->type()); + } + + uint64_t etype = line_type == ObLineType::Line ? 2 : (line_type == ObLineType::ExterRing ? 1003 : 2003); + if (OB_FAIL(append_elem_info(sdo_geo_->get_ordinates().size() + 1, etype, 1))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(sdo_geo_->get_ordinates().size())); + } else { + is_inner_element_ = true; + } + return ret; +} + +int ObGeo3DWkbToSdoGeoVisitor::visit_linestringz_end(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + UNUSED(geo); + UNUSED(line_type); + is_inner_element_ = false; + return OB_SUCCESS; +} + +int ObGeo3DWkbToSdoGeoVisitor::visit_polygonz_start(ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + if (!is_multi_visit_ && !is_collection_visit_ && !is_inner_element_) { + sdo_geo_->set_gtype(geo->type()); + } + return ret; +} + +int ObGeo3DWkbToSdoGeoVisitor::visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + sdo_geo_->set_gtype(geo->type()); + if (geo_type == ObGeoType::MULTIPOINTZ) { + if (OB_FAIL(append_elem_info(sdo_geo_->get_ordinates().size() + 1, 1, nums))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(sdo_geo_->get_ordinates().size())); + } else { + is_multi_visit_ = true; + } + } else if (geo_type == ObGeoType::MULTILINESTRINGZ) { + // do nothing + } else if (geo_type == ObGeoType::MULTIPOLYGONZ) { + // do nothing + } else { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid geo type", K(ret), K(geo_type)); + } + return ret; +} + +int ObGeo3DWkbToSdoGeoVisitor::visit_multi_geom_end(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + UNUSED(geo); + UNUSED(geo_type); + UNUSED(nums); + + is_multi_visit_ = false; + return ret; +} + +int ObGeo3DWkbToSdoGeoVisitor::visit_collectionz_start(ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + sdo_geo_->set_gtype(geo->type()); + is_collection_visit_ = true; + return ret; +} + +int ObGeo3DWkbToSdoGeoVisitor::visit_collectionz_end(ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + UNUSED(geo); + UNUSED(nums); + is_collection_visit_ = false; + return ret; +} + +int ObGeometry3D::to_geo_json(ObIAllocator *allocator, common::ObString &geo_json) +{ + int ret = OB_SUCCESS; + ObGeo3DWkbToJsonVisitor visitor(allocator); + set_pos(0); + if (OB_FAIL(visit_wkb_inner(visitor))) { + LOG_WARN("fail to check wkb valid", K(ret)); + } else if (!is_end()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("has extra buffer in wkb", K(ret), K(cur_pos_), K(length())); + } else { + geo_json.assign(visitor.get_result().ptr(), static_cast(visitor.get_result().length())); + } + return ret; +} + + // pointz +int ObGeo3DWkbToJsonVisitor::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + INIT_SUCC(ret); + const char *type_name = "Point"; + // { "type": "Point", "coordinates": [x, y, z] } + if (!in_multi_visit_ && inner_element_level_ <= 0 && OB_FAIL(appendJsonFields(ObGeoType::POINTZ, type_name))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } + return ret; +} + +int ObGeo3DWkbToJsonVisitor::visit_pointz_inner(double x, double y, double z) +{ + INIT_SUCC(ret); + // [x, y, Z] + if (OB_FAIL(buffer_.append("["))) { + LOG_WARN("fail to append to buffer_", K(ret)); + } else if (OB_FAIL(appendDouble(x))) { + LOG_WARN("fail to append x", K(ret), K(x)); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append to buffer_", K(ret)); + } else if (OB_FAIL(appendDouble(y))) { + LOG_WARN("fail to append y", K(ret), K(y)); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append to buffer_", K(ret)); + } else if (OB_FAIL(appendDouble(z))) { + LOG_WARN("fail to append z", K(ret), K(z)); + } else if (OB_FAIL(buffer_.append("]"))) { + LOG_WARN("fail to append to buffer_", K(ret)); + } + return ret; +} + +int ObGeo3DWkbToJsonVisitor::visit_pointz_end(ObGeometry3D *geo, bool is_inner) +{ + INIT_SUCC(ret); + if (!in_multi_visit_ && inner_element_level_ <= 0 && OB_FAIL(buffer_.append(" }"))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_)); + } else if ((in_multi_visit_ || in_colloction_visit() || inner_element_level_ > 0) && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + // linestringz +int ObGeo3DWkbToJsonVisitor::visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + INIT_SUCC(ret); + const char *type_name = "LineString"; + if ((inner_element_level_ <= 0) && OB_FAIL(appendJsonFields(ObGeoType::LINESTRINGZ, type_name))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append("[ "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else { + inner_element_level_++; + } + return ret; +} +int ObGeo3DWkbToJsonVisitor::visit_linestringz_end(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) +{ + INIT_SUCC(ret); + inner_element_level_--; + if (OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if (OB_FAIL(buffer_.append(" ]"))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if ((inner_element_level_ <= 0 || (in_colloction_visit() && line_type == ObLineType::Line)) && + OB_FAIL(buffer_.append(" }"))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_)); + } else if ((inner_element_level_ > 0 || in_colloction_visit()) && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + // polygonz +int ObGeo3DWkbToJsonVisitor::visit_polygonz_start(ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + const char *type_name = "Polygon"; + if ((inner_element_level_ <= 0) && OB_FAIL(appendJsonFields(ObGeoType::POLYGONZ, type_name))) { + LOG_WARN("fail to append buffer_", K(ret), K(inner_element_level_), K(type_name)); + } else if (OB_FAIL(buffer_.append("[ "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else { + inner_element_level_++; + } + return ret; +} + +int ObGeo3DWkbToJsonVisitor::visit_polygonz_end(ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + inner_element_level_--; + if (OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if (OB_FAIL(buffer_.append(" ]"))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if ((inner_element_level_ <= 0 || in_colloction_visit()) && OB_FAIL(buffer_.append(" }"))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if ((inner_element_level_ > 0 || in_colloction_visit()) && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + // multi geomz +int ObGeo3DWkbToJsonVisitor::visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + const char *type_name = "MultiPoint"; + if (ObGeoType::MULTILINESTRINGZ == geo_type) { + type_name = "MultiLineString"; + } else if (ObGeoType::MULTIPOLYGONZ == geo_type) { + type_name = "MultiPolygon"; + } + if (OB_FAIL(appendJsonFields(geo_type, type_name))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append("[ "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else { + inner_element_level_++; + } + return ret; +} +int ObGeo3DWkbToJsonVisitor::visit_multi_geom_end(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + inner_element_level_--; + if (OB_FAIL(appendMultiSuffix(geo_type))) { + LOG_WARN("fail to append multi suffix", K(ret)); + } + return ret; +} + // geometrycollection +int ObGeo3DWkbToJsonVisitor::visit_collectionz_start(ObGeometry3D *geo, uint32_t nums) +{ + INIT_SUCC(ret); + const char *type_name = "GeometryCollection"; + if (OB_FAIL(appendJsonFields(geo->type(), type_name))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append("[ "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else { + in_collection_level_++; + } + return ret; +} +int ObGeo3DWkbToJsonVisitor::visit_collectionz_end(ObGeometry3D *geo, uint32_t nums) +{ + return appendCollectionSuffix(); +} + +int ObGeo3DWkbToJsonVisitor::appendDouble(double x) +{ + INIT_SUCC(ret); + int16_t scale = ObGeoToWktVisitor::MAX_DIGITS_IN_DOUBLE; + uint64_t double_buff_size = ObGeoToWktVisitor::MAX_DIGITS_IN_DOUBLE; + uint64_t len_x = 0; + char *buff_ptr = NULL; + if (OB_FAIL(buffer_.reserve(double_buff_size))) { + LOG_WARN("fail to reserve buffer", K(ret)); + } else if (FALSE_IT(buff_ptr = buffer_.ptr() + buffer_.length())) { + } else if (OB_FAIL(ObGeoToWktVisitor::convert_double_to_str(buff_ptr, double_buff_size, x, false, scale, true, len_x))) { + LOG_WARN("fail to append x val to buffer", K(ret)); + } else if (OB_FAIL(buffer_.set_length(buffer_.length() + len_x))) { + LOG_WARN("fail to set buffer x len", K(ret), K(len_x)); + } + return ret; +} + +int ObGeo3DWkbToJsonVisitor::appendJsonFields(ObGeoType type, const char *type_name) +{ + int ret = OB_SUCCESS; + if (type < ObGeoType::POINTZ || type > ObGeoType::GEOMETRYCOLLECTIONZ) { + LOG_WARN("invalid geo type", K(ret), K(type)); + } else if (OB_FAIL(buffer_.append("{ \"type\": \""))) { + LOG_WARN("fail to append type field", K(ret)); + } else if (OB_FAIL(buffer_.append(type_name))) { + LOG_WARN("fail to append type value", K(ret), K(type_name)); + } else if (type != ObGeoType::GEOMETRYCOLLECTIONZ && + OB_FAIL(buffer_.append("\", \"coordinates\": "))) { + LOG_WARN("fail to append coordinates field", K(ret)); + } else if (type == ObGeoType::GEOMETRYCOLLECTIONZ && + OB_FAIL(buffer_.append("\", \"geometries\": "))) { + LOG_WARN("fail to append geometries field", K(ret)); + } + return ret; +} + +int ObGeo3DWkbToJsonVisitor::appendMultiSuffix(ObGeoType geo_type) +{ + INIT_SUCC(ret); + if (OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if ((geo_type == ObGeoType::MULTIPOINTZ || !in_colloction_visit()) && OB_FAIL(buffer_.append(" ] }"))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if ((in_colloction_visit() || inner_element_level_ > 0) && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + +int ObGeo3DWkbToJsonVisitor::appendCollectionSuffix() +{ + INIT_SUCC(ret); + ObString comma(2, buffer_.ptr() + buffer_.length() - 2); + if ((comma.compare(", ") == 0) && OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if (OB_FAIL(buffer_.append(" ] }"))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + + in_collection_level_--; + if (OB_FAIL(ret)) { + } else if (in_colloction_visit() && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + +int ObGeo3DElevationVisitor::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + UNUSED(is_inner); + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else { + uint32_t cur_pos = geo->get_pos(); + uint64_t pointz_len = WKB_POINT_DATA_SIZE + WKB_GEO_DOUBLE_STORED_SIZE; + char *ptr = const_cast(geo->val()); + if (OB_ISNULL(ptr) || (cur_pos + pointz_len > geo->length())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("3D geometry position is wrong", K(ret)); + } else { + ObGeoWkbByteOrder bo = geo->byteorder(); + double x = ObGeoWkbByteOrderUtil::read(ptr + cur_pos, bo); + double y = ObGeoWkbByteOrderUtil::read(ptr + cur_pos + WKB_GEO_DOUBLE_STORED_SIZE, bo); + double z = ObGeoWkbByteOrderUtil::read(ptr + cur_pos + 2 * WKB_GEO_DOUBLE_STORED_SIZE, bo); + if (OB_FAIL(extent_->add_point(x, y, z))) { + LOG_WARN("fail to add point into extent", K(ret)); + } + } + } + return ret; +} + +int ObGeo3DNormalizeVisitor::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + UNUSED(is_inner); + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else { + uint32_t cur_pos = geo->get_pos(); + uint64_t pointz_len = WKB_POINT_DATA_SIZE + WKB_GEO_DOUBLE_STORED_SIZE; + char *ptr = const_cast(geo->val()); + if (OB_ISNULL(ptr) || (cur_pos + pointz_len > geo->length())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("3D geometry position is wrong", K(ret)); + } else { + ObGeoWkbByteOrder bo = geo->byteorder(); + double x = ObGeoWkbByteOrderUtil::read(ptr + cur_pos, bo); + double y = ObGeoWkbByteOrderUtil::read(ptr + cur_pos + WKB_GEO_DOUBLE_STORED_SIZE, bo); + double z = ObGeoWkbByteOrderUtil::read(ptr + cur_pos + 2 * WKB_GEO_DOUBLE_STORED_SIZE, bo); + double nx = 1.0; + double ny = 1.0; + double nz = 1.0; + if (no_srs_) { + nx = x * M_PI / 180.0; + ny = y * M_PI / 180.0; + nz = z * M_PI / 180.0; + } else { + if (OB_FAIL(srs_->latitude_convert_to_radians(y, ny))) { + LOG_WARN("normalize y failed", K(ret)); + } else if (OB_FAIL(srs_->longtitude_convert_to_radians(x, nx))) { + LOG_WARN("normalize x failed", K(ret)); + } else { + uint32_t count = 0; + double nx_tmp = nx; + double ny_tmp = ny; + double nz_tmp = nz; + while (nx_tmp != 0.0 && std::fabs(nx_tmp) < ZOOM_IN_THRESHOLD) { + nx_tmp *= 10; + count++; + } + zoom_in_value_ = count > zoom_in_value_ ? count : zoom_in_value_; + count = 0; + while (ny_tmp != 0.0 && std::fabs(ny_tmp) < ZOOM_IN_THRESHOLD) { + ny_tmp *= 10; + count++; + } + zoom_in_value_ = count > zoom_in_value_ ? count : zoom_in_value_; + count = 0; + while (nz_tmp != 0.0 && std::fabs(nz_tmp) < ZOOM_IN_THRESHOLD) { + nz_tmp *= 10; + count++; + } + zoom_in_value_ = count > zoom_in_value_ ? count : zoom_in_value_; + } + } + if (OB_SUCC(ret)) { + ObGeoWkbByteOrderUtil::write(ptr + cur_pos, nx, bo); + ObGeoWkbByteOrderUtil::write(ptr + cur_pos + WKB_GEO_DOUBLE_STORED_SIZE, ny, bo); + ObGeoWkbByteOrderUtil::write(ptr + cur_pos + WKB_GEO_DOUBLE_STORED_SIZE * 2, nz, bo); + } + } + } + return ret; +} + +int ObGeo3DEmptyVisitor::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + UNUSED(is_inner); + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else { + uint32_t cur_pos = geo->get_pos(); + uint64_t pointz_len = WKB_POINT_DATA_SIZE + WKB_GEO_DOUBLE_STORED_SIZE; + char *ptr = const_cast(geo->val()); + if (OB_ISNULL(ptr) || (cur_pos + pointz_len > geo->length())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("3D geometry position is wrong", K(ret)); + } else { + ObGeoWkbByteOrder bo = geo->byteorder(); + double x = ObGeoWkbByteOrderUtil::read(ptr + cur_pos, bo); + double y = ObGeoWkbByteOrderUtil::read(ptr + cur_pos + WKB_GEO_DOUBLE_STORED_SIZE, bo); + double z = ObGeoWkbByteOrderUtil::read(ptr + cur_pos + 2 * WKB_GEO_DOUBLE_STORED_SIZE, bo); + is_empty_ = std::isnan(x) || std::isnan(y) || std::isnan(z); + } + } + return ret; +} + +int ObGeo3DLonLatChecker::visit_pointz_start(ObGeometry3D *geo, bool is_inner) +{ + UNUSED(is_inner); + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_ISNULL(srs_)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret)); + } else if (srs_->srs_type() == ObSrsType::PROJECTED_SRS) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("srs is projected type", K(srs_)); + } else { + uint32_t cur_pos = geo->get_pos(); + uint64_t pointz_len = WKB_POINT_DATA_SIZE + WKB_GEO_DOUBLE_STORED_SIZE; + char *ptr = const_cast(geo->val()); + if (OB_ISNULL(ptr) || (cur_pos + pointz_len > geo->length())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("3D geometry position is wrong", K(ret)); + } else { + ObGeoWkbByteOrder bo = geo->byteorder(); + double lon = ObGeoWkbByteOrderUtil::read(ptr + cur_pos, bo); + lon = ObGeoLatlongCheckVisitor::ob_normalize_longitude(lon); + double lat = ObGeoWkbByteOrderUtil::read(ptr + cur_pos + WKB_GEO_DOUBLE_STORED_SIZE, bo); + lat = ObGeoLatlongCheckVisitor::ob_normalize_latitude(lat); + if (OB_SUCC(ret)) { + ObGeoWkbByteOrderUtil::write(ptr + cur_pos, lon, bo); + ObGeoWkbByteOrderUtil::write(ptr + cur_pos + WKB_GEO_DOUBLE_STORED_SIZE, lat, bo); + } + } + } + return ret; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_3d.h b/deps/oblib/src/lib/geo/ob_geo_3d.h new file mode 100644 index 0000000000..2dad48ba87 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_3d.h @@ -0,0 +1,324 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_GEO_3D_ +#define OCEANBASE_LIB_GEO_OB_GEO_3D_ +#include "lib/string/ob_string.h" +#include "ob_geo_ibin.h" +#include "ob_geo_common.h" +#include "ob_geo_utils.h" +#include "lib/function/ob_function.h" +#include "ob_geo_coordinate_range_visitor.h" +#include "ob_sdo_geo_object.h" +#include "lib/geo/ob_geo_elevation_visitor.h" + +namespace oceanbase { +namespace common { +class ObGeo3DVisitor; + +enum ObLineType { + Line = 0, + ExterRing = 1, + InnerRing = 2 +}; +class ObGeometry3D: public ObGeometry +{ +public: + ObGeometry3D(uint32_t srid = 0, ObIAllocator *allocator = NULL) + : ObGeometry(srid, allocator), cur_pos_(0) {} + virtual ~ObGeometry3D() = default; + ObGeometry3D(const ObGeometry3D& g) = default; + ObGeometry3D& operator=(const ObGeometry3D& g) = default; + // interface + virtual void set_data(const ObString& data) { data_ = data; } + virtual ObString to_wkb() const override { return data_; } + virtual int do_visit(ObIGeoVisitor &visitor) { UNUSED(visitor); return OB_NOT_SUPPORTED; }; + virtual uint64_t length() const override { return data_.length(); } + virtual const char* val() const override { return data_.ptr(); } + virtual ObGeoType type() const override; + virtual ObGeoCRS crs() const override { return crs_; }; + virtual bool is_tree() const override { return false; }; + virtual bool is_empty() const override; + // new interface + void set_pos(uint64_t pos) { cur_pos_ = pos; } + uint64_t get_pos() { return cur_pos_; } + ObGeoWkbByteOrder byteorder() const; + ObGeoWkbByteOrder byteorder(uint64_t pos) const; + ObGeoType type(uint64_t pos) const; + void set_crs(ObGeoCRS crs) { crs_ = crs; } + int to_2d_geo(ObIAllocator &allocator, ObGeometry *&res); + int to_wkt(ObIAllocator &allocator, ObString &wkt, uint32_t srid = 0, int64_t maxdecimaldigits = -1); + int reverse_coordinate(); + int check_wkb_valid(); + int check_3d_coordinate_range(const ObSrsItem *srs, const bool is_normalized, ObGeoCoordRangeResult &result); + int to_sdo_geometry(ObSdoGeoObject &sdo_geo); + int to_geo_json(ObIAllocator *allocator, common::ObString &geo_json); + int create_elevation_extent(ObGeoElevationExtent &extent); + int normalize(const ObSrsItem *srs, uint32_t &zoom_in_value); + int check_empty(bool &is_empty); + int correct_lon_lat(const ObSrsItem *srs); +private: + int visit_wkb_inner(ObGeo3DVisitor &visitor); + bool is_end() { return cur_pos_ >= data_.length(); } + int read_header(ObGeoWkbByteOrder &bo, ObGeoType &geo_type); + int read_nums_value(ObGeoWkbByteOrder bo, uint32_t &nums); + // visit wkb + int visit_pointz_inner(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor); + int visit_pointz(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor, bool is_inner = false); + int visit_linestringz(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor, ObLineType line_type = ObLineType::Line); + int visit_polygonz(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor); + int visit_multi_geomz(ObGeoWkbByteOrder bo, ObGeoType geo_type, ObGeo3DVisitor &visitor); + int visit_collectionz(ObGeoWkbByteOrder bo, ObGeo3DVisitor &visitor); + +protected: + ObGeoCRS crs_; + ObString data_; // wkb without srid +private: + uint64_t cur_pos_; +}; + +class ObGeo3DVisitor +{ +public: + ObGeo3DVisitor() : is_multi_(false) {} + virtual int visit_header(ObGeoWkbByteOrder bo, ObGeoType geo_type, bool is_sub_type = false); + // pointz + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner = false); + virtual int visit_pointz_inner(double x, double y, double z); + virtual int visit_pointz_end(ObGeometry3D *geo, bool is_inner = false); + // linestringz + virtual int visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type); + virtual int visit_linestringz_item_after(ObGeometry3D *geo, uint32_t idx, ObLineType line_type); + virtual int visit_linestringz_end(ObGeometry3D *geo, uint32_t nums, ObLineType line_type); + // polygonz + virtual int visit_polygonz_start(ObGeometry3D *geo, uint32_t nums); + virtual int visit_polygonz_item_after(ObGeometry3D *geo, uint32_t idx); + virtual int visit_polygonz_end(ObGeometry3D *geo, uint32_t nums); + // multi geomz + virtual int visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums); + virtual int visit_multi_geom_item_after(ObGeoType geo_type, ObGeometry3D *geo, uint32_t idx); + virtual int visit_multi_geom_end(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums); + // geometrycollection + virtual int visit_collectionz_start(ObGeometry3D *geo, uint32_t nums); + virtual int visit_collectionz_item_after(ObGeometry3D *geo, uint32_t idx); + virtual int visit_collectionz_end(ObGeometry3D *geo, uint32_t nums); + bool is_multi() { return is_multi_; } + void set_is_multi(bool is_multi) { is_multi_ = is_multi; } +private: + bool is_multi_; +}; + +class ObGeo3DChecker : public ObGeo3DVisitor +{ +public: + virtual int visit_header(ObGeoWkbByteOrder bo, ObGeoType geo_type, bool is_sub_type = false) override; + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner = false); + virtual int visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type) override; +}; + +class ObGeo3DTo2DVisitor : public ObGeo3DVisitor +{ +public: + ObGeo3DTo2DVisitor(): wkb_buf_(NULL) {} + void set_wkb_buf(ObWkbBuffer *wkb_buf) { wkb_buf_ = wkb_buf; } + virtual int visit_header(ObGeoWkbByteOrder bo, ObGeoType geo_type, bool is_sub_type = false) override; + virtual int visit_pointz_inner(double x, double y, double z); + virtual int visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type); + virtual int visit_polygonz_start(ObGeometry3D *geo, uint32_t nums); + virtual int visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums); + virtual int visit_collectionz_start(ObGeometry3D *geo, uint32_t nums); +private: + int append_nums(uint32_t nums); +private: + ObWkbBuffer *wkb_buf_; +}; + +class ObGeo3DToWktVisitor : public ObGeo3DVisitor +{ +public: + ObGeo3DToWktVisitor(int64_t maxdecimaldigits = -1); + void set_wkt_buf(ObStringBuffer *wkt_buf) { wkt_buf_ = wkt_buf; } + virtual int visit_header(ObGeoWkbByteOrder bo, ObGeoType geo_type, bool is_sub_type = false); + // pointz + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner); + virtual int visit_pointz_inner(double x, double y, double z); + virtual int visit_pointz_end(ObGeometry3D *geo, bool is_inner); + // linestringz + virtual int visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type); + virtual int visit_linestringz_item_after(ObGeometry3D *geo, uint32_t idx, ObLineType line_type); + virtual int visit_linestringz_end(ObGeometry3D *geo, uint32_t nums, ObLineType line_type); + // polygonz + virtual int visit_polygonz_start(ObGeometry3D *geo, uint32_t nums); + virtual int visit_polygonz_item_after(ObGeometry3D *geo, uint32_t idx); + virtual int visit_polygonz_end(ObGeometry3D *geo, uint32_t nums); + // multi geomz + virtual int visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums); + virtual int visit_multi_geom_item_after(ObGeoType geo_type, ObGeometry3D *geo, uint32_t idx); + virtual int visit_multi_geom_end(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums); + // geometrycollection + virtual int visit_collectionz_start(ObGeometry3D *geo, uint32_t nums); + virtual int visit_collectionz_item_after(ObGeometry3D *geo, uint32_t idx); + virtual int visit_collectionz_end(ObGeometry3D *geo, uint32_t nums); +private: + int remove_comma(); + int append_comma(); + int append_paren(bool is_left); +private: + ObStringBuffer *wkt_buf_; + bool is_oracle_mode_; + bool is_mpt_visit_; + bool has_scale_; + int64_t scale_; +}; + +class ObGeo3DReserverCoordinate : public ObGeo3DVisitor +{ +public: + ObGeo3DReserverCoordinate() {} + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner = false); +}; + +class ObGeo3DCoordinateRangeVisitor : public ObGeo3DVisitor +{ +public: + ObGeo3DCoordinateRangeVisitor(const ObSrsItem *srs, bool is_normalized = true) + : srs_(srs), is_lati_out_range_(false), is_long_out_range_(false), + value_out_range_(NAN), is_normalized_(is_normalized) {} + virtual int visit_pointz_inner(double x, double y, double z); + void get_coord_range_result(ObGeoCoordRangeResult& result); +private: + const ObSrsItem *srs_; + bool is_lati_out_range_; + bool is_long_out_range_; + double value_out_range_; + bool is_normalized_; + DISALLOW_COPY_AND_ASSIGN(ObGeo3DCoordinateRangeVisitor); +}; + +class ObGeo3DWkbToSdoGeoVisitor : public ObGeo3DVisitor +{ +public: + ObGeo3DWkbToSdoGeoVisitor() + : is_multi_visit_(false), is_collection_visit_(false), + is_inner_element_(false), sdo_geo_(nullptr) {} + ~ObGeo3DWkbToSdoGeoVisitor() {} + int init(ObSdoGeoObject *geo, uint32_t srid = UINT32_MAX); + // pointz + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner = false); + virtual int visit_pointz_inner(double x, double y, double z); + // linestringz + virtual int visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type); + virtual int visit_linestringz_end(ObGeometry3D *geo, uint32_t nums, ObLineType line_type); + // polygonz + virtual int visit_polygonz_start(ObGeometry3D *geo, uint32_t nums); + // multi geomz + virtual int visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums); + virtual int visit_multi_geom_end(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums); + // geometrycollection + virtual int visit_collectionz_start(ObGeometry3D *geo, uint32_t nums); + virtual int visit_collectionz_end(ObGeometry3D *geo, uint32_t nums); + +private: + int append_elem_info(uint64_t offset, uint64_t etype, uint64_t interpretation); + bool is_multi_visit_; + bool is_collection_visit_; + bool is_inner_element_; + ObSdoGeoObject *sdo_geo_; +}; + +class ObGeo3DWkbToJsonVisitor : public ObGeo3DVisitor +{ +public: + ObGeo3DWkbToJsonVisitor(ObIAllocator *allocator) + : in_multi_visit_(false), in_collection_level_(0), + inner_element_level_(0), buffer_(allocator) {} + ~ObGeo3DWkbToJsonVisitor() {} + // pointz + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner = false); + virtual int visit_pointz_inner(double x, double y, double z); + virtual int visit_pointz_end(ObGeometry3D *geo, bool is_inner = false); + // linestringz + virtual int visit_linestringz_start(ObGeometry3D *geo, uint32_t nums, ObLineType line_type); + virtual int visit_linestringz_end(ObGeometry3D *geo, uint32_t nums, ObLineType line_type); + // polygonz + virtual int visit_polygonz_start(ObGeometry3D *geo, uint32_t nums); + virtual int visit_polygonz_end(ObGeometry3D *geo, uint32_t nums); + // multi geomz + virtual int visit_multi_geom_start(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums); + virtual int visit_multi_geom_end(ObGeoType geo_type, ObGeometry3D *geo, uint32_t nums); + // geometrycollection + virtual int visit_collectionz_start(ObGeometry3D *geo, uint32_t nums); + virtual int visit_collectionz_end(ObGeometry3D *geo, uint32_t nums); + ObGeoStringBuffer &get_result() { return buffer_; } + +private: + static const int MAX_DIGITS_IN_DOUBLE = 25; + int appendDouble(double x); + int appendJsonFields(ObGeoType type, const char *type_name); + int appendMultiSuffix(ObGeoType geo_type); + int appendCollectionSuffix(); + inline bool in_colloction_visit() { return in_collection_level_ > 0; } + bool in_multi_visit_; + int in_collection_level_; + int inner_element_level_; + ObGeoStringBuffer buffer_; +}; + +class ObGeo3DElevationVisitor : public ObGeo3DVisitor +{ +public: + explicit ObGeo3DElevationVisitor(ObGeoElevationExtent &extent) : extent_(&extent) {} + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner = false); +private: + ObGeoElevationExtent *extent_; + DISALLOW_COPY_AND_ASSIGN(ObGeo3DElevationVisitor); +}; + +class ObGeo3DNormalizeVisitor : public ObGeo3DVisitor +{ +public: + explicit ObGeo3DNormalizeVisitor(const ObSrsItem *srs, bool no_srs = false) + : srs_(srs), no_srs_(no_srs), zoom_in_value_(0) {} + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner = false); + uint32_t get_zoom_in_value() { return zoom_in_value_; } +private: + static constexpr double ZOOM_IN_THRESHOLD = 0.00000001; + const ObSrsItem *srs_; + bool no_srs_; // for st_transform, only proj4text is given + uint32_t zoom_in_value_; + DISALLOW_COPY_AND_ASSIGN(ObGeo3DNormalizeVisitor); +}; + +class ObGeo3DEmptyVisitor : public ObGeo3DVisitor +{ +public: + explicit ObGeo3DEmptyVisitor() : is_empty_(true) {} + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner = false); + bool is_empty() { return is_empty_; } +private: + bool is_empty_; + DISALLOW_COPY_AND_ASSIGN(ObGeo3DEmptyVisitor); +}; + +class ObGeo3DLonLatChecker : public ObGeo3DVisitor +{ +public: + explicit ObGeo3DLonLatChecker(const ObSrsItem *srs) : srs_(srs) {} + virtual int visit_pointz_start(ObGeometry3D *geo, bool is_inner = false); +private: + const ObSrsItem *srs_; + DISALLOW_COPY_AND_ASSIGN(ObGeo3DLonLatChecker); +}; + +} // namespace common +} // namespace oceanbase +#endif // OCEANBASE_LIB_GEO_OB_GEO_3D_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_affine_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_affine_visitor.cpp new file mode 100644 index 0000000000..f944c61311 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_affine_visitor.cpp @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "ob_geo_affine_visitor.h" + +namespace oceanbase +{ +namespace common +{ + +bool ObGeoAffineVisitor::prepare(ObGeometry *geo) +{ + bool bret = true; + if ((OB_ISNULL(geo) || OB_ISNULL(affine_))) { + bret = false; + } + return bret; +} + +template +void ObGeoAffineVisitor::affine(PtType *point) +{ + double x = point->x(); + double y = point->y(); + point->x(affine_->x_fac1 * x + affine_->y_fac1 * y + affine_->x_off); + point->y(affine_->x_fac2 * x + affine_->y_fac2 * y + affine_->y_off); +} + +int ObGeoAffineVisitor::visit(ObGeographPoint *geo) +{ + affine(geo); + return OB_SUCCESS; +} + +// for st_transform +int ObGeoAffineVisitor::visit(ObCartesianPoint *geo) +{ + affine(geo); + return OB_SUCCESS; +} +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_affine_visitor.h b/deps/oblib/src/lib/geo/ob_geo_affine_visitor.h new file mode 100644 index 0000000000..2358eca3c8 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_affine_visitor.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ +#ifndef OCEANBASE_LIB_GEO_OB_GEO_AFFINE_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_GEO_AFFINE_VISITOR_ +#include "lib/geo/ob_geo_visitor.h" +#include "lib/geo/ob_geo_utils.h" +namespace oceanbase +{ +namespace common +{ + +class ObGeoAffineVisitor : public ObEmptyGeoVisitor +{ +public: + explicit ObGeoAffineVisitor(const ObAffineMatrix *affine) : affine_(affine) + {} + virtual ~ObGeoAffineVisitor() + {} + bool prepare(ObGeometry *geo); + int visit(ObCartesianPoint *geo); + int visit(ObGeographPoint *geo); + int visit(ObGeometry *geo) + { + UNUSED(geo); + return OB_SUCCESS; + } + template + void affine(PtType *point); + +private: + const ObAffineMatrix *affine_; + DISALLOW_COPY_AND_ASSIGN(ObGeoAffineVisitor); +}; + +} // namespace common +} // namespace oceanbase + +#endif // OCEANBASE_LIB_GEO_OB_GEO_AFFINE_VISITOR_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_bin.cpp b/deps/oblib/src/lib/geo/ob_geo_bin.cpp index 93fb245f18..aec0f947c1 100644 --- a/deps/oblib/src/lib/geo/ob_geo_bin.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_bin.cpp @@ -105,17 +105,15 @@ uint64_t ObWkbGeomInnerPoint::length() const { } template<> -double ObWkbGeomInnerPoint::get<0>() const +double ObWkbGeomInnerPoint::get<0>(ObGeoWkbByteOrder bo/* = ObGeoWkbByteOrder::LittleEndian */) const { - ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian; char* ptr = reinterpret_cast(const_cast(this)); return ObGeoWkbByteOrderUtil::read(ptr, bo); } template<> -double ObWkbGeomInnerPoint::get<1>() const +double ObWkbGeomInnerPoint::get<1>(ObGeoWkbByteOrder bo/* = ObGeoWkbByteOrder::LittleEndian */) const { - ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian; char* ptr = reinterpret_cast(const_cast(this)); ptr = ptr + sizeof(double); return ObGeoWkbByteOrderUtil::read(ptr, bo); @@ -151,6 +149,16 @@ ObWkbGeomInnerPoint::ObWkbGeomInnerPoint(const ObWkbGeomInnerPoint& p) set<1>(p.get<1>()); } +bool ObWkbGeomInnerPoint::equals(const ObWkbGeomInnerPoint& p) const +{ + bool bret = false; + if ((fabs(this->get<0>() - p.get<0>()) <= 1e-12) && + (fabs(this->get<1>() - p.get<1>()) <= 1e-12)) { + bret = true; + } + return bret; +} + // Cartesian linestring uint32_t ObWkbGeomLineString::size() const { @@ -181,16 +189,16 @@ void ObWkbGeomLineString::get_sub_addr(const_pointer last_addr, index_type last_ } // Cartesian linearring -uint32_t ObWkbGeomLinearRing::size() const +uint32_t ObWkbGeomLinearRing::size(ObGeoWkbByteOrder bo /*= ObGeoWkbByteOrder::LittleEndian*/) const { char *ptr = reinterpret_cast(const_cast(this)); - return ObGeoWkbByteOrderUtil::read(ptr, ObGeoWkbByteOrder::LittleEndian); + return ObGeoWkbByteOrderUtil::read(ptr, bo); } -ObWkbGeomLinearRing::size_type ObWkbGeomLinearRing::length() const +ObWkbGeomLinearRing::size_type ObWkbGeomLinearRing::length(ObGeoWkbByteOrder bo /*= ObGeoWkbByteOrder::LittleEndian*/) const { size_type s = sizeof(uint32_t); - s += size() * (sizeof(double) * 2); + s += size(bo) * (sizeof(double) * 2); return s; } @@ -244,7 +252,7 @@ uint32_t ObWkbGeomPolygon::size() const uint64_t ObWkbGeomPolygon::length() const { uint64_t s = WKB_COMMON_WKB_HEADER_LEN; - s += exterior_ring().length() + inner_rings().length(); + s += exterior_ring().length(static_cast(bo_)) + inner_rings().length(); return s; } @@ -519,34 +527,30 @@ uint64_t ObWkbGeogInnerPoint::length() const { } template<> -double ObWkbGeogInnerPoint::get<0>() const +double ObWkbGeogInnerPoint::get<0>(ObGeoWkbByteOrder bo/* = ObGeoWkbByteOrder::LittleEndian */) const { - ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian; char* ptr = reinterpret_cast(const_cast(this)); return ObGeoWkbByteOrderUtil::read(ptr, bo); } template<> -double ObWkbGeogInnerPoint::get<1>() const +double ObWkbGeogInnerPoint::get<1>(ObGeoWkbByteOrder bo/* = ObGeoWkbByteOrder::LittleEndian */) const { - ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian; char* ptr = reinterpret_cast(const_cast(this)); ptr = ptr + sizeof(double); return ObGeoWkbByteOrderUtil::read(ptr, bo); } template<> -void ObWkbGeogInnerPoint::set<0>(double d) +void ObWkbGeogInnerPoint::set<0>(double d, ObGeoWkbByteOrder bo /*= ObGeoWkbByteOrder::LittleEndian*/) { - ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian; char* ptr = reinterpret_cast(const_cast(this)); ObGeoWkbByteOrderUtil::write(ptr, d, bo); } template<> -void ObWkbGeogInnerPoint::set<1>(double d) +void ObWkbGeogInnerPoint::set<1>(double d, ObGeoWkbByteOrder bo /*= ObGeoWkbByteOrder::LittleEndian*/) { - ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian; char* ptr = reinterpret_cast(const_cast(this)); ptr = ptr + sizeof(double); ObGeoWkbByteOrderUtil::write(ptr, d, bo); @@ -595,16 +599,16 @@ void ObWkbGeogLineString::get_sub_addr(const_pointer last_addr, index_type last_ } // Geograph linearring -uint32_t ObWkbGeogLinearRing::size() const +uint32_t ObWkbGeogLinearRing::size(ObGeoWkbByteOrder bo /*= ObGeoWkbByteOrder::LittleEndian*/) const { char *ptr = reinterpret_cast(const_cast(this)); - return ObGeoWkbByteOrderUtil::read(ptr, ObGeoWkbByteOrder::LittleEndian); + return ObGeoWkbByteOrderUtil::read(ptr, bo); } -ObWkbGeogLinearRing::size_type ObWkbGeogLinearRing::length() const +ObWkbGeogLinearRing::size_type ObWkbGeogLinearRing::length(ObGeoWkbByteOrder bo /*= ObGeoWkbByteOrder::LittleEndian*/) const { size_type s = sizeof(uint32_t); - s += size() * (sizeof(double) * 2); + s += size(bo) * (sizeof(double) * 2); return s; } @@ -658,7 +662,7 @@ uint32_t ObWkbGeogPolygon::size() const uint64_t ObWkbGeogPolygon::length() const { uint64_t s = WKB_COMMON_WKB_HEADER_LEN; - s += exterior_ring().length() + inner_rings().length(); + s += exterior_ring().length(static_cast(bo_)) + inner_rings().length(); return s; } diff --git a/deps/oblib/src/lib/geo/ob_geo_bin.h b/deps/oblib/src/lib/geo/ob_geo_bin.h index c4b5457bf5..f0af0adca9 100644 --- a/deps/oblib/src/lib/geo/ob_geo_bin.h +++ b/deps/oblib/src/lib/geo/ob_geo_bin.h @@ -21,7 +21,6 @@ namespace oceanbase { namespace common { - // [srid] static const uint32_t WKB_GEO_SRID_SIZE = sizeof(uint32_t); // [version] @@ -87,12 +86,13 @@ public: ~ObWkbGeomInnerPoint() {} uint64_t length() const; template - double get() const; + double get(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const; template void set(double d); // candidate function not viable: 'this' argument has type 'point_type' (aka 'const oceanbase::common::ObWkbGeomInnerPoint'), but method is not marked const ObWkbGeomInnerPoint& operator=(const ObWkbGeomInnerPoint& p); ObWkbGeomInnerPoint& operator=(const ObWkbGeomInnerPoint& p) const; + bool equals(const ObWkbGeomInnerPoint& p) const; // TODO int64_t to_string(char *buffer, const int64_t length) const{ UNUSED(buffer); @@ -136,6 +136,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeomLineString); }; @@ -158,18 +160,18 @@ public: public: ObWkbGeomLinearRing() {} ~ObWkbGeomLinearRing() {} - uint32_t size() const; - size_type length() const; + uint32_t size(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const; + size_type length(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const; // iter adaptor - index_type iter_idx_max() const { return size(); } + index_type iter_idx_max(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const { return size(bo); } index_type iter_idx_min() const { return 0; } void get_sub_addr(const_pointer last_addr, index_type last_idx, index_type cur_idx, ObWkbIterOffsetArray* offsets, pointer& data); // iter adapt iterator begin() { return iterator(iter_idx_min(), this); } const_iterator begin() const { return const_iterator(iter_idx_min(), this); } - iterator end() { return iterator(iter_idx_max(), this); } - const_iterator end() const { return const_iterator(iter_idx_max(), this); } + iterator end(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { return iterator(iter_idx_max(bo), this); } + const_iterator end(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const { return const_iterator(iter_idx_max(bo), this); } bool empty() const {return false;} bool empty() {return false;} @@ -217,11 +219,13 @@ public: index_type et(index_type curidx) const { return curidx; } void get_sub_addr(const_pointer last_addr, index_type last_idx, index_type cur_idx, ObWkbIterOffsetArray* offsets, pointer& data); - size_type get_sub_size(const_pointer data) const { return data->length(); }; + size_type get_sub_size(const_pointer data) const { return data->length(static_cast(bo_)); }; iterator begin() { return iterator(iter_idx_min(), this); } // for move over exterior const_iterator begin() const { return const_iterator(iter_idx_min(), this); } // for move over exterior iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeomPolygonInnerRings); }; @@ -239,6 +243,9 @@ public: const ObWkbGeomLinearRing& exterior_ring() const; ObWkbGeomPolygonInnerRings& inner_rings(); const ObWkbGeomPolygonInnerRings& inner_rings() const; + uint8_t get_bo() const {return bo_;} +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeomPolygon); }; @@ -273,6 +280,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeomMultiPoint); }; @@ -312,6 +321,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeomMultiLineString); }; @@ -351,6 +362,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeomMultiPolygon); }; @@ -396,6 +409,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeomCollection); }; @@ -441,9 +456,9 @@ public: ~ObWkbGeogInnerPoint() {} uint64_t length() const; template - double get() const; + double get(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const; template - void set(double d); + void set(double d, ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian); ObWkbGeogInnerPoint& operator=(const ObWkbGeogInnerPoint& p); // TODO int64_t to_string(char *buffer, const int64_t length) const{ @@ -488,6 +503,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeogLineString); }; @@ -510,18 +527,18 @@ public: public: ObWkbGeogLinearRing() {} ~ObWkbGeogLinearRing() {} - uint32_t size() const; - size_type length() const; + uint32_t size(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const; + size_type length(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const; // iter adaptor - index_type iter_idx_max() const { return size(); } + index_type iter_idx_max(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const { return size(bo); } index_type iter_idx_min() const { return 0; } void get_sub_addr(const_pointer last_addr, index_type last_idx, index_type cur_idx, ObWkbIterOffsetArray* offsets, pointer& data); // iter adapt iterator begin() { return iterator(iter_idx_min(), this); } const_iterator begin() const { return const_iterator(iter_idx_min(), this); } - iterator end() { return iterator(iter_idx_max(), this); } - const_iterator end() const { return const_iterator(iter_idx_max(), this); } + iterator end(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { return iterator(iter_idx_max(bo), this); } + const_iterator end(ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) const { return const_iterator(iter_idx_max(bo), this); } // for bg::correct void push_back(const ObWkbGeogInnerPoint &pt) { UNUSED(pt); @@ -566,12 +583,14 @@ public: index_type et(index_type curidx) const { return curidx; } void get_sub_addr(const_pointer last_addr, index_type last_idx, index_type cur_idx, ObWkbIterOffsetArray* offsets, pointer& data); - size_type get_sub_size(const_pointer data) const { return data->length(); }; + size_type get_sub_size(const_pointer data) const { return data->length(static_cast(bo_)); }; // iter interface iterator begin() { return iterator(iter_idx_min(), this); } const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeogPolygonInnerRings); }; @@ -589,6 +608,9 @@ public: const ObWkbGeogLinearRing& exterior_ring() const; ObWkbGeogPolygonInnerRings& inner_rings(); const ObWkbGeogPolygonInnerRings& inner_rings() const; + uint8_t get_bo() const {return bo_;} +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeogPolygon); }; @@ -624,6 +646,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeogMultiPoint); }; @@ -663,6 +687,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeogMultiLineString); }; @@ -702,6 +728,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeogMultiPolygon); }; @@ -746,6 +774,8 @@ public: const_iterator begin() const { return const_iterator(iter_idx_min(), this); } iterator end() { return iterator(iter_idx_max(), this); } const_iterator end() const { return const_iterator(iter_idx_max(), this); } +private: + uint8_t bo_; DISABLE_COPY_ASSIGN(ObWkbGeogCollection); }; diff --git a/deps/oblib/src/lib/geo/ob_geo_bin_iter.ipp b/deps/oblib/src/lib/geo/ob_geo_bin_iter.ipp index 50b2b09e68..9175c3c75e 100644 --- a/deps/oblib/src/lib/geo/ob_geo_bin_iter.ipp +++ b/deps/oblib/src/lib/geo/ob_geo_bin_iter.ipp @@ -353,6 +353,8 @@ void ObWkbUtils::get_sub_addr_common(const T& obj, // TODO: prealloc whole array? if (enable_offset_info && OB_FAIL(offsets->prepare_allocate(obj.iter_idx_max()))) { COMMON_LOG(WARN, "failed to reserve for offsets!", K(ret), K(obj.iter_idx_max())); + // allocate memory failed, can't maintain ObWkbIterOffsetArray + enable_offset_info = false; } // assum offsets -> prepare_allocate will do memset 0 uint64_t base_offset = (enable_offset_info) ? offsets->operator[](st) : 0; diff --git a/deps/oblib/src/lib/geo/ob_geo_box_clip_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_box_clip_visitor.cpp new file mode 100644 index 0000000000..901456a9d9 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_box_clip_visitor.cpp @@ -0,0 +1,1020 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "ob_geo_box_clip_visitor.h" +#include "lib/geo/ob_geo_func_register.h" + +namespace oceanbase +{ +namespace common +{ +ObBoxPosition ObGeoBoxClipVisitor::get_position(double x, double y) +{ + ObBoxPosition position = ObBoxPosition::INVALID; + if (x > xmin_ && x < xmax_ && y > ymin_ && y < ymax_) { + position = ObBoxPosition::INSIDE; + } else if (x < xmin_ || x > xmax_ || y < ymin_ || y > ymax_) { + position = ObBoxPosition::OUTSIDE; + } else { + uint8_t pos = 0; + if (x == xmin_) { + pos |= ObBoxPosition::LEFT_EDGE; + } else if (x == xmax_) { + pos |= ObBoxPosition::RIGHT_EDGE; + } + if (y == ymax_) { + pos |= ObBoxPosition::TOP_EDGE; + } else if (y == ymin_) { + pos |= ObBoxPosition::BOTTOM_EDGE; + } + position = ObBoxPosition(pos); + } + return position; +} + +ObGeoType ObGeoBoxClipVisitor::get_result_basic_type() +{ + ObGeoType type = ObGeoType::GEOMETRY; + if (res_geo_->empty()) { + type = ObGeoType::GEOMETRYCOLLECTION; + } else { + type = res_geo_->front().type(); + for (uint32_t i = 1; i < res_geo_->size() && type != ObGeoType::GEOMETRYCOLLECTION; ++i) { + if (type != (*res_geo_)[i].type()) { + type = ObGeoType::GEOMETRYCOLLECTION; + } + } + } + return type; +} + +int ObGeoBoxClipVisitor::get_geometry(ObGeometry *&geo) +{ + int ret = OB_SUCCESS; + ObGeoType type = get_result_basic_type(); + geo = nullptr; + if (res_geo_->size() == 1) { + // Point/Polygon/Linestring + geo = &(res_geo_->front()); + } else if (type == ObGeoType::GEOMETRYCOLLECTION) { + geo = res_geo_; + } else { + // MultiPoint/MultiPolygon/MultiLinestring + if (type == ObGeoType::POINT) { + ObCartesianMultipoint *mpt = + OB_NEWx(ObCartesianMultipoint, allocator_, res_geo_->get_srid(), *allocator_); + if (OB_ISNULL(mpt)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < res_geo_->size(); ++i) { + if (OB_FAIL(mpt->push_back( + *reinterpret_cast((*res_geo_)[i].val())))) { + LOG_WARN("failed to add point to multipoint", K(ret)); + } + } + if (OB_SUCC(ret)) { + geo = mpt; + } + } else if (type == ObGeoType::POLYGON) { + ObCartesianMultipolygon *mpy = + OB_NEWx(ObCartesianMultipolygon, allocator_, res_geo_->get_srid(), *allocator_); + if (OB_ISNULL(mpy)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < res_geo_->size(); ++i) { + if (OB_FAIL( + mpy->push_back(*reinterpret_cast(&(*res_geo_)[i])))) { + LOG_WARN("failed to add point to multipoint", K(ret)); + } + } + if (OB_SUCC(ret)) { + geo = mpy; + } + } else if (type == ObGeoType::LINESTRING) { + ObCartesianMultilinestring *mls = + OB_NEWx(ObCartesianMultilinestring, allocator_, res_geo_->get_srid(), *allocator_); + if (OB_ISNULL(mls)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < res_geo_->size(); ++i) { + if (OB_FAIL(mls->push_back( + *reinterpret_cast(&(*res_geo_)[i])))) { + LOG_WARN("failed to add point to multipoint", K(ret)); + } + } + if (OB_SUCC(ret)) { + geo = mls; + } + } + } + return ret; +} + +bool ObGeoBoxClipVisitor::prepare(ObGeometry *geo) +{ + bool bret = true; + if (OB_ISNULL(geo)) { + bret = false; + } else if (OB_ISNULL(res_geo_)) { + // Prevents a new res_geo_ from being created twice when accessing multi geometry + res_geo_ = OB_NEWx(ObCartesianGeometrycollection, allocator_, geo->get_srid(), *allocator_); + if (OB_ISNULL(res_geo_)) { + bret = false; + } + } + return bret; +} + +int ObGeoBoxClipVisitor::visit(ObCartesianPoint *geo) +{ + int ret = OB_SUCCESS; + if (geo->is_empty()) { + // do nothing + } else if (get_position(geo->x(), geo->y()) == ObBoxPosition::INSIDE) { + if (OB_FAIL(res_geo_->push_back(*geo))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + return ret; +} + +int ObGeoBoxClipVisitor::visit(ObCartesianMultipoint *geo) +{ + int ret = OB_SUCCESS; + if (!geo->is_empty()) { + ObCartesianMultipoint mpt(geo->get_srid(), *allocator_); + for (uint32_t i = 0; i < geo->size() && OB_SUCC(ret); ++i) { + const ObWkbGeomInnerPoint &pt = (*geo)[i]; + if (get_position(pt.get<0>(), pt.get<1>()) == ObBoxPosition::INSIDE) { + if (OB_FAIL(mpt.push_back(pt))) { + LOG_WARN("fail to push geometry", K(ret), K(geo->size()), K(i)); + } + } + } + if (OB_SUCC(ret) && !mpt.empty()) { + // only push basic type (point/polygon/linestring) into res_geo_ + for (uint32_t i = 0; OB_SUCC(ret) && i < mpt.size(); ++i) { + ObCartesianPoint *pt = OB_NEWx(ObCartesianPoint, + allocator_, + mpt[i].get<0>(), + mpt[i].get<1>(), + geo->get_srid(), + allocator_); + if (OB_ISNULL(pt)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for geometry", K(ret)); + } else if (OB_FAIL(res_geo_->push_back(*pt))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + } + return ret; +} + +void ObGeoBoxClipVisitor::clip_point_to_single_edge( + ObWkbGeomInnerPoint &out_pt, const ObWkbGeomInnerPoint &in_pt, double edge, bool is_x_edge) +{ + if (is_x_edge) { + if (in_pt.get<0>() == edge) { + out_pt.set<0>(in_pt.get<0>()); + out_pt.set<1>(in_pt.get<1>()); + } else if (in_pt.get<0>() != out_pt.get<0>()) { + double out_y = out_pt.get<1>(); + double out_x = out_pt.get<0>(); + double in_y = in_pt.get<1>(); + double in_x = in_pt.get<0>(); + out_pt.set<1>(out_y + (in_y - out_y) * (edge - out_x) / (in_x - out_x)); + out_pt.set<0>(edge); + } + } else { + if (in_pt.get<1>() == edge) { + out_pt.set<0>(in_pt.get<0>()); + out_pt.set<1>(in_pt.get<1>()); + } else if (in_pt.get<1>() != out_pt.get<1>()) { + double out_x = out_pt.get<0>(); + double out_y = out_pt.get<1>(); + double in_x = in_pt.get<0>(); + double in_y = in_pt.get<1>(); + out_pt.set<0>(out_x + (in_x - out_x) * (edge - out_y) / (in_y - out_y)); + out_pt.set<1>(edge); + } + } +} + +/** + * @brief Get the intersection point of the line that intersects the box + * @param out_pt the point where the line is outside the Box + * @param in_pt the point where the line is inside the Box + * @param pt intersection point + */ +void ObGeoBoxClipVisitor::clip_point_to_edges( + const ObWkbGeomInnerPoint &out_pt, const ObWkbGeomInnerPoint &in_pt, ObWkbGeomInnerPoint &pt) +{ + pt = out_pt; + if (pt.get<0>() < xmin_) { + clip_point_to_single_edge(pt, in_pt, xmin_, true); + } else if (pt.get<0>() > xmax_) { + clip_point_to_single_edge(pt, in_pt, xmax_, true); + } + + if (pt.get<1>() < ymin_) { + clip_point_to_single_edge(pt, in_pt, ymin_, false); + } else if (pt.get<1>() > ymax_) { + clip_point_to_single_edge(pt, in_pt, ymax_, false); + } +} + +bool ObGeoBoxClipVisitor::same_edge_positions(ObBoxPosition pos1, ObBoxPosition pos2) +{ + return ObBoxPosition(pos1 & pos2) > ObBoxPosition::OUTSIDE; +} + +int ObGeoBoxClipVisitor::construct_intersect_line(const ObCartesianLineString &line, + int32_t first_inside_idx, int32_t last_idx, ObCartesianLineString &intersect_line) +{ + int ret = OB_SUCCESS; + for (int32_t j = first_inside_idx; OB_SUCC(ret) && j < last_idx; ++j) { + if (OB_FAIL(intersect_line.push_back(line[j]))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + return ret; +} + +int ObGeoBoxClipVisitor::line_visit_inside_or_edge(const ObCartesianLineString &line, int &idx, + ObCartesianMultilinestring *mls, ObBoxPosition pos, ObCartesianLineString &new_line, + bool &completely_inside) +{ + int ret = OB_SUCCESS; + int32_t first_inside_idx = idx; + ObBoxPosition prev_pos = ObBoxPosition::INVALID; + int64_t sz = line.size(); + for (++idx; OB_SUCC(ret) && pos != ObBoxPosition::OUTSIDE && idx < sz; ++idx) { + prev_pos = pos; + pos = get_position(line[idx].get<0>(), line[idx].get<1>()); + if (pos == ObBoxPosition::INSIDE) { + // do nothing + } else if (pos == ObBoxPosition::OUTSIDE) { + ObWkbGeomInnerPoint cur_pt_edge; + clip_point_to_edges(line[idx], line[idx - 1], cur_pt_edge); + ObBoxPosition clip_pos = get_position(cur_pt_edge.get<0>(), cur_pt_edge.get<1>()); + bool clip_box = !cur_pt_edge.equals(line[idx]) && !same_edge_positions(clip_pos, prev_pos); + if (first_inside_idx < idx - 1 || !new_line.empty() || clip_box) { + if (OB_FAIL(construct_intersect_line(line, first_inside_idx, idx, new_line))) { + LOG_WARN("fail to construct intersect line", K(ret), K(first_inside_idx), K(idx)); + } else if (clip_box && OB_FAIL(new_line.push_back(cur_pt_edge))) { + LOG_WARN("fail to push back geometry", K(ret)); + } else if (OB_FAIL(mls->push_back(new_line))) { + LOG_WARN("fail to push back geometry", K(ret)); + } else { + new_line.clear(); + } + } + } else { // on edge + if (same_edge_positions(prev_pos, pos)) { + if (first_inside_idx < idx - 1 || !new_line.empty()) { + if (OB_FAIL(construct_intersect_line(line, first_inside_idx, idx, new_line))) { + LOG_WARN("fail to construct intersect line", K(ret), K(first_inside_idx), K(idx)); + } else if (OB_FAIL(mls->push_back(new_line))) { + LOG_WARN("fail to push back geometry", K(ret)); + } else { + new_line.clear(); + } + } + first_inside_idx = idx; + } + } + } + if (pos == ObBoxPosition::OUTSIDE) { + --idx; // keep idx = last inside/on edge point + } + if (OB_FAIL(ret)) { + // do nothing + } else if (first_inside_idx == 0 && idx >= sz) { + // all points are inside + completely_inside = true; + if (OB_FAIL(mls->push_back(line))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } else if (pos != ObBoxPosition::OUTSIDE + && (first_inside_idx < idx - 1 || !new_line.empty())) { + if (OB_FAIL(construct_intersect_line(line, first_inside_idx, idx, new_line))) { + LOG_WARN("fail to construct intersect line", K(ret), K(first_inside_idx), K(idx)); + } else if (OB_FAIL(mls->push_back(new_line))) { + LOG_WARN("fail to push back geometry", K(ret)); + } else { + new_line.clear(); + } + } + return ret; +} + +int ObGeoBoxClipVisitor::line_visit_outside(const ObCartesianLineString &line, int &idx, + ObCartesianMultilinestring *mls, ObBoxPosition pos, ObCartesianLineString &new_line) +{ + int ret = OB_SUCCESS; + int64_t sz = line.size(); + double x = line[idx].get<0>(); + double y = line[idx].get<1>(); + ++idx; + // find point inside/on edge + if (x < xmin_) { + while (idx < sz && line[idx].get<0>() < xmin_) { + ++idx; + } + } else if (x > xmax_) { + while (idx < sz && line[idx].get<0>() > xmax_) { + ++idx; + } + } else if (y < ymin_) { + while (idx < sz && line[idx].get<1>() < ymin_) { + ++idx; + } + } else if (y > ymax_) { + while (idx < sz && line[idx].get<1>() > ymax_) { + ++idx; + } + } + if (idx < sz) { + x = line[idx].get<0>(); + y = line[idx].get<1>(); + pos = get_position(x, y); + ObWkbGeomInnerPoint pt; + clip_point_to_edges(line[idx - 1], line[idx], pt); + if (pos == ObBoxPosition::INSIDE) { + // first inside point + if (OB_FAIL(new_line.push_back(pt))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } else if (pos == ObBoxPosition::OUTSIDE) { + // Two outside points line[idx] and line[idx - 1] may connected through the box + // need to clip two side + ObWkbGeomInnerPoint to_pt; + clip_point_to_edges(line[idx], pt, to_pt); + ObBoxPosition prev_pos = get_position(pt.get<0>(), pt.get<1>()); + pos = get_position(to_pt.get<0>(), to_pt.get<1>()); + if (!pt.equals(to_pt) // not in same pos + && prev_pos > ObBoxPosition::OUTSIDE + && pos > ObBoxPosition::OUTSIDE // intersects with box + && !same_edge_positions(prev_pos, pos)) { // not in same edge + if (OB_FAIL(new_line.push_back(pt))) { + LOG_WARN("fail to push back geometry", K(ret)); + } else if (OB_FAIL(new_line.push_back(to_pt))) { + LOG_WARN("fail to push back geometry", K(ret)); + } else if (OB_FAIL(mls->push_back(new_line))) { + LOG_WARN("fail to push back geometry", K(ret)); + } else { + new_line.clear(); + } + } + } else { // EDGE + ObBoxPosition prev_pos = get_position(pt.get<0>(), pt.get<1>()); + if (!same_edge_positions(prev_pos, pos)) { + if (OB_FAIL(new_line.push_back(pt))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + } + return ret; +} + +int ObGeoBoxClipVisitor::line_visit( + const ObCartesianLineString &line, ObCartesianMultilinestring *&mls, bool &completely_inside) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(mls)) { + mls = OB_NEWx(ObCartesianMultilinestring, allocator_); + if (OB_ISNULL(mls)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for geometry", K(ret)); + } + } + if (OB_SUCC(ret)) { + int64_t sz = line.size(); + int32_t idx = 0; + ObCartesianLineString new_line(line.get_srid(), *allocator_); + completely_inside = false; + while (OB_SUCC(ret) && idx < sz) { + ObBoxPosition pos = get_position(line[idx].get<0>(), line[idx].get<1>()); + if (pos == ObBoxPosition::OUTSIDE) { + if (OB_FAIL(line_visit_outside(line, idx, mls, pos, new_line))) { + LOG_WARN("fail to do line visit outside", K(ret), K(pos), K(idx)); + } + } else { // edge or inside + if (OB_FAIL(line_visit_inside_or_edge(line, idx, mls, pos, new_line, completely_inside))) { + LOG_WARN("fail to do line visit inside or edge", K(ret), K(pos), K(idx)); + } + } + } + } + return ret; +} + +int ObGeoBoxClipVisitor::visit(ObCartesianLineString *geo) +{ + int ret = OB_SUCCESS; + ObCartesianMultilinestring *mls = nullptr; + bool inside = false; // unused + if (geo->is_empty()) { + // do nothing + } else if (OB_FAIL(line_visit(*geo, mls, inside))) { + LOG_WARN("fail to do line visit", K(ret)); + } else if (!mls->empty()) { + for (uint32_t i = 0; OB_SUCC(ret) && i < mls->size(); ++i) { + if (OB_FAIL(res_geo_->push_back((*mls)[i]))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + return ret; +} + +int ObGeoBoxClipVisitor::visit(ObCartesianMultilinestring *geo) +{ + int ret = OB_SUCCESS; + ObCartesianMultilinestring *mls = nullptr; + bool inside = false; // unused + if (!geo->is_empty()) { + for (uint32_t i = 0; OB_SUCC(ret) && i < geo->size(); ++i) { + if (OB_FAIL(line_visit((*geo)[i], mls, inside))) { + LOG_WARN("fail to do line visit", K(ret)); + } + } + if (OB_SUCC(ret) && !mls->empty()) { + for (uint32_t i = 0; OB_SUCC(ret) && i < mls->size(); ++i) { + if (OB_FAIL(res_geo_->push_back((*mls)[i]))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + } + return ret; +} + +// After cutting the ring in the POLYGON as a line, we may get a MULTILINESTRING. +// Try to connect the first and last lines of the MULTILINESTRING +// e.g. POLYGON ((5 10,0 0,10 0,5 10)) --visit_line--> MULTILINESTRING ((5 10,0 0),(10 0,5 10)) +// MULTILINESTRING ((5 10,0 0),(10 0,5 10)) --reconnect--> LINESTRING (10 0,5 10,0 0) +int ObGeoBoxClipVisitor::reconnect_multi_line(ObCartesianMultilinestring &mls) +{ + int ret = OB_SUCCESS; + if (mls.size() < 2) { + // do nothing + } else { + ObCartesianLineString &first = mls.front(); + ObCartesianLineString &last = mls[mls.size() - 1]; + ObWkbGeomInnerPoint prev_pt = last[last.size() - 1]; + if (!first.empty() && !last.empty() && first[0].equals(last.back())) { + for (uint32_t i = 0; OB_SUCC(ret) && i < first.size(); ++i) { + if (!first[i].equals(prev_pt)) { + prev_pt = first[i]; + if (OB_FAIL(last.push_back(prev_pt))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + if (OB_SUCC(ret)) { + mls[0] = last; + mls.resize(mls.size() - 1); + } + } + } + return ret; +} + +int ObGeoBoxClipVisitor::box_to_linearring(ObCartesianLinearring &ring) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ring.push_back(ObWkbGeomInnerPoint(xmin_, ymin_)))) { + LOG_WARN("failt to push back geometry", K(ret)); + } else if (OB_FAIL(ring.push_back(ObWkbGeomInnerPoint(xmin_, ymax_)))) { + LOG_WARN("failt to push back geometry", K(ret)); + } else if (OB_FAIL(ring.push_back(ObWkbGeomInnerPoint(xmax_, ymax_)))) { + LOG_WARN("failt to push back geometry", K(ret)); + } else if (OB_FAIL(ring.push_back(ObWkbGeomInnerPoint(xmax_, ymin_)))) { + LOG_WARN("failt to push back geometry", K(ret)); + } else if (OB_FAIL(ring.push_back(ObWkbGeomInnerPoint(xmin_, ymin_)))) { + LOG_WARN("failt to push back geometry", K(ret)); + } + return ret; +} + +void ObGeoBoxClipVisitor::to_next_edge(ObBoxPosition &pos) +{ + switch (pos) { + case ObBoxPosition::LEFT_EDGE: + case ObBoxPosition::BOTTOMLEFT_CORNER: { + pos = ObBoxPosition::TOP_EDGE; + break; + } + case ObBoxPosition::TOP_EDGE: + case ObBoxPosition::TOPLEFT_CORNER: { + pos = ObBoxPosition::RIGHT_EDGE; + break; + } + case ObBoxPosition::RIGHT_EDGE: + case ObBoxPosition::TOPRIGHT_CORNER: { + pos = ObBoxPosition::BOTTOM_EDGE; + break; + } + case ObBoxPosition::BOTTOM_EDGE: + case ObBoxPosition::BOTTOMRIGHT_CORNER: { + pos = ObBoxPosition::LEFT_EDGE; + break; + } + default: { + // do nothing + } + } +} + +/** + * @brief Close the line in the Box into a ring by adding points + * @param ring line to close + * @param x1 The x-coordinate of the starting point of the ring + * @param y1 The y-coordinate of the starting point of the ring + * @param x2 The x-coordinate of the ending point of the ring + * @param y2 The y-coordinate of the ending point of the ring + * @return int ret code + */ +int ObGeoBoxClipVisitor::close_ring( + ObCartesianLinearring &ring, double x1, double y1, double x2, double y2) +{ + int ret = OB_SUCCESS; + ObBoxPosition pos = get_position(x1, y1); + ObBoxPosition end_pos = get_position(x2, y2); + bool is_closed = false; + while (OB_SUCC(ret) && !is_closed) { + // closed when starting point and ending point on the same edge + // and points are in correct clockwise order + is_closed = (pos & end_pos) + && ((x1 == xmin_ && y2 >= y1) || (y1 == ymax_ && x2 >= x1) + || (x1 == xmax_ && y2 <= y1) || (y1 == ymin_ && x2 <= x1)); + if (is_closed) { + if (x1 != x2 || y1 != y2) { + if (OB_FAIL(ring.push_back(ObWkbGeomInnerPoint(x2, y2)))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } else if (pos & ObBoxPosition::OUTSIDE || end_pos & ObBoxPosition::OUTSIDE + || pos & ObBoxPosition::INSIDE || end_pos & ObBoxPosition::INSIDE) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("point should be on boundary", K(ret)); + } else { + to_next_edge(pos); + if (pos & ObBoxPosition::LEFT_EDGE) { + x1 = xmin_; + } else if (pos & ObBoxPosition::TOP_EDGE) { + y1 = ymax_; + } else if (pos & ObBoxPosition::RIGHT_EDGE) { + x1 = xmax_; + } else { + y1 = ymin_; + } + if (OB_FAIL(ring.push_back(ObWkbGeomInnerPoint(x1, y1)))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + return ret; +} + +/** + * @brief Distance of first point of linestring to last point of ring along rectangle edges + * @param x1 x-coordinate of last point of ring + * @param y1 y-coordinate of last point of ring + * @param x2 x-coordinate of first point of linestring + * @param y2 y-coordinate of first point of linestring + * @param dist distance + * @return int ret code + */ +int ObGeoBoxClipVisitor::distance(double x1, double y1, double x2, double y2, double &dist) +{ + int ret = OB_SUCCESS; + ObBoxPosition pos = get_position(x1, y1); + ObBoxPosition end_pos = get_position(x2, y2); + bool is_end = false; + while (OB_SUCC(ret) && !is_end) { + is_end = (pos & end_pos) + && ((x1 == xmin_ && y2 >= y1) || (y1 == ymax_ && x2 >= x1) || (x1 == xmax_ && y2 <= y1) + || (y1 == ymin_ && x2 <= x1)); + if (is_end) { + dist += fabs(x1 - x2) + fabs(y1 - y2); + } else if (pos & ObBoxPosition::OUTSIDE || end_pos & ObBoxPosition::OUTSIDE + || pos & ObBoxPosition::INSIDE || end_pos & ObBoxPosition::INSIDE) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("point should be on boundary", K(ret)); + } else { + to_next_edge(pos); + if (pos & ObBoxPosition::LEFT_EDGE) { + dist += x1 - xmin_; + x1 = xmin_; + } else if (pos & ObBoxPosition::TOP_EDGE) { + dist += ymax_ - y1; + y1 = ymax_; + } else if (pos & ObBoxPosition::RIGHT_EDGE) { + dist += xmax_ - x1; + x1 = xmax_; + } else { + dist += y1 - ymin_; + y1 = ymin_; + } + } + } + return ret; +} + +void ObGeoBoxClipVisitor::reverse_ring(ObCartesianLineString &ring, uint32_t start, uint32_t end) +{ + for (uint32_t i = start, j = end; i < j; ++i, --j) { + ObWkbGeomInnerPoint tmp_pt = ring[i]; + ring[i] = ring[j]; + ring[j] = tmp_pt; + } +} + +void ObGeoBoxClipVisitor::reorder_ring(ObCartesianLinearring &ring) +{ + int32_t min_pos = 0; + // find the point closest to the bottom left + for (uint32_t i = 1; i < ring.size(); ++i) { + if (ring[i].get<0>() < ring[min_pos].get<0>()) { + min_pos = i; + } else if (ring[i].get<0>() == ring[min_pos].get<0>() + && ring[i].get<1>() < ring[min_pos].get<1>()) { + min_pos = i; + } + } + if (min_pos != 0) { + // reorder ring, let the min_pos point be the starting point + reverse_ring(ring, 0, min_pos - 1); + reverse_ring(ring, min_pos, ring.size() - 2); + reverse_ring(ring, 0, ring.size() - 2); + // make sure that the first point and end point are same (closed ring) + ring.back() = ring.front(); + } +} + +int ObGeoBoxClipVisitor::make_polygon_ext_ring(ObCartesianMultilinestring &mls, ObCartesianMultipolygon &new_mpy) +{ + int ret = OB_SUCCESS; + if (mls.empty()) { + ObCartesianPolygon poly; + if (OB_FAIL(box_to_linearring(poly.exterior_ring()))) { + LOG_WARN("fail to convert box to ring", K(ret)); + } else if (OB_FAIL(new_mpy.push_back(poly))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } else { + ObCartesianLinearring ring; + while (OB_SUCC(ret) && (!mls.empty() || !ring.empty())) { + double dist = 0.0; + if (ring.empty()) { + for (int i = 0; i < mls[0].size() && OB_SUCC(ret); ++i) { + if (OB_FAIL(ring.push_back(mls[0][i]))) { + LOG_WARN("failt to push back geometry", K(ret), K(i)); + } + } + if (OB_SUCC(ret)) { + mls.pop_front(); + } + } + if (OB_SUCC(ret) + && OB_FAIL(distance(ring.back().get<0>(), ring.back().get<1>(), ring.front().get<0>(), + ring.front().get<1>(), dist))) { + LOG_WARN("fail to get distance", K(ret)); + } + double min_dist = -1; + int32_t min_pos = 0; + for (int i = 0; OB_SUCC(ret) && i < mls.size(); ++i) { + double cur_dist = 0.0; + if (OB_FAIL(distance(ring.back().get<0>(), ring.back().get<1>(), + mls[i][0].get<0>(), mls[i][0].get<1>(), cur_dist))) { + LOG_WARN("fail to get distance", K(ret), K(i), K(mls.size())); + } else if (min_dist < 0 || cur_dist < min_dist) { + min_dist = cur_dist; + min_pos = i; + } + } + if (OB_FAIL(ret)) { + } else if (min_dist < 0 || dist < min_dist) { + if (OB_FAIL(close_ring(ring, ring.back().get<0>(), ring.back().get<1>(), + ring.front().get<0>(), ring.front().get<1>()))) { + LOG_WARN("fail to close ring", K(ret)); + } else if (FALSE_IT(reorder_ring(ring))) { + } else if (ring.size() < 4) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("Invalid number of ring", K(ret), K(ring.size())); + } else { + ObCartesianPolygon poly; + poly.exterior_ring() = ring; + if (OB_FAIL(new_mpy.push_back(poly))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + ring.clear(); + } + } else { + ObCartesianLineString &min_line = mls[min_pos]; + if (OB_FAIL(close_ring(ring, ring.back().get<0>(), ring.back().get<1>(), + min_line.front().get<0>(), min_line.front().get<1>()))) { + LOG_WARN("fail to close ring", K(ret)); + } + for (uint32_t i = 1; OB_SUCC(ret) && i < min_line.size(); ++i) { + if (OB_FAIL(ring.push_back(min_line[i]))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + if (OB_SUCC(ret) && OB_FAIL(mls.remove(min_pos))) { + LOG_WARN("fail to remove linestring", K(ret)); + } + } + } + } + return ret; +} + +// mls -> ext rings +// mpy -> inner rings +int ObGeoBoxClipVisitor::make_polygons( + ObCartesianMultilinestring &mls, ObCartesianMultipolygon &mpy, ObCartesianMultipolygon &new_mpy) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(make_polygon_ext_ring(mls, new_mpy))) { + LOG_WARN("fail to make polygon exterior ring", K(ret)); + } + // merge mpy (inner rings) to new_mpy + for (uint32_t i = 0; OB_SUCC(ret) && i < mpy.size(); ++i) { + ObCartesianPolygon &poly = mpy[i]; + ObCartesianLinearring &ext_ring = poly.exterior_ring(); + if (new_mpy.size() == 1) { + if (OB_FAIL(new_mpy[0].interior_rings().push_back(ext_ring))) { + LOG_WARN("fail to push back linearring", K(ret)); + } + } else { + for (uint32_t j = 0; OB_SUCC(ret) && j < new_mpy.size(); ++j) { + bool is_covered_by = false; + ObGeoEvalCtx gis_context(allocator_); + ObCartesianLineString *tmp_line = reinterpret_cast(&ext_ring); + if (OB_FAIL(gis_context.append_geo_arg(tmp_line)) + || OB_FAIL(gis_context.append_geo_arg(&new_mpy[j]))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval( + gis_context, is_covered_by))) { + LOG_WARN("eval Within functor failed", K(ret)); + } else if (is_covered_by && OB_FAIL(new_mpy[j].interior_rings().push_back(ext_ring))) { + LOG_WARN("fail to push back linearring", K(ret)); + } + } + } + } + return ret; +} + +void ObGeoBoxClipVisitor::reverse_mls(ObCartesianMultilinestring &mls) +{ + for (uint32_t i = 0; i < mls.size(); ++i) { + ObCartesianLineString &ls = mls[i]; + reverse_ring(mls[i], 0, mls[i].size() - 1); + } + + for (uint32_t i = 0, j = mls.size() - 1; i < j; ++i, --j) { + ObCartesianLineString ls = mls[i]; + mls[i] = mls[j]; + mls[j] = ls; + } +} + +// check is ring in counter-clock-wise +bool ObGeoBoxClipVisitor::is_ring_ccw(ObCartesianLineString &ring) +{ + bool bret = false; + int64_t sz = ring.size(); + // a ring at least has 4 points, including close point + if (sz >= 4) { + const ObWkbGeomInnerPoint *up_high_pt = &ring[0]; + const ObWkbGeomInnerPoint *up_low_pt = nullptr; + double prev_y = up_high_pt->get<1>(); + uint32_t up_high_idx = 0; + for (uint32_t i = 1; i < sz; ++i) { + double cur_y = ring[i].get<1>(); + if (cur_y > prev_y && cur_y >= up_high_pt->get<1>()) { + up_high_idx = i; + up_high_pt = &ring[i]; + up_low_pt = &ring[i - 1]; + } + prev_y = cur_y; + } + if (up_high_idx != 0) { + --sz; + uint32_t down_low_idx = (up_high_idx + 1) % sz; + while (down_low_idx != up_high_idx && ring[down_low_idx].get<1>() == up_high_pt->get<1>()) { + down_low_idx = (down_low_idx + 1) % sz; + } + const ObWkbGeomInnerPoint *down_low_pt = &ring[down_low_idx]; + uint32_t down_high_idx = down_low_idx > 0 ? down_low_idx - 1 : sz - 1; + const ObWkbGeomInnerPoint *down_high_pt = &ring[down_high_idx]; + if (up_high_pt->equals(*down_high_pt)) { + if (!up_low_pt->equals(*up_high_pt) && !down_low_pt->equals(*up_high_pt) + && !up_low_pt->equals(*down_low_pt)) { + double diff_x1 = up_high_pt->get<0>() - up_low_pt->get<0>(); + double diff_x2 = down_low_pt->get<0>() - up_high_pt->get<0>(); + double diff_y1 = up_high_pt->get<1>() - up_low_pt->get<1>(); + double diff_y2 = down_low_pt->get<1>() - up_high_pt->get<1>(); + bret = (diff_x1 * diff_y2 - diff_x2 * diff_y1) > 0; + } + } else { + bret = (down_high_pt->get<0>() - up_high_pt->get<0>()) < 0; + } + } + } + return bret; +} + +int ObGeoBoxClipVisitor::visit_polygon_inner_ring( + const ObCartesianLinearring &inner_ring, ObCartesianMultipolygon &ext_mpy, ObCartesianMultilinestring &ext_mls, bool &is_within) +{ + int ret = OB_SUCCESS; + ObCartesianMultilinestring *inner_mls = nullptr; + bool is_inside = false; + ObCartesianPolygon tmp_py; + tmp_py.exterior_ring() = inner_ring; + if (OB_FAIL(line_visit(inner_ring, inner_mls, is_inside))) { + LOG_WARN("fail to do line visit", K(ret)); + } else if (is_inside) { + // becomes exterior ring + if (OB_FAIL(ext_mpy.push_back(tmp_py))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } else { + if (inner_mls->empty()) { + double xmid = xmin_ + (xmax_ - xmin_) / 2; + double ymid = ymin_ + (ymax_ - ymin_) / 2; + ObCartesianPoint pt(xmid, ymid); + ObGeoEvalCtx gis_context(allocator_); + if (OB_FAIL(gis_context.append_geo_arg(&pt)) + || OB_FAIL(gis_context.append_geo_arg(&tmp_py))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL( + ObGeoFunc::gis_func::eval(gis_context, is_within))) { + LOG_WARN("eval Within functor failed", K(ret)); + } + } else { + if (!is_ring_ccw(tmp_py.exterior_ring())) { + reverse_mls(*inner_mls); + } + if (OB_FAIL(reconnect_multi_line(*inner_mls))) { + LOG_WARN("fail to reconnect multi line", K(ret)); + } + // merge inner_mls into ext_mls + for (int i = 0; OB_SUCC(ret) && i < inner_mls->size(); ++i) { + if (OB_FAIL(ext_mls.push_back((*inner_mls)[i]))) { + LOG_WARN("failt to push back geometry", K(ret)); + } + } + if (OB_SUCC(ret)) { + allocator_->free(inner_mls); + inner_mls = nullptr; + } + } + } + return ret; +} + +int ObGeoBoxClipVisitor::visit_polygon_ext_ring(const ObCartesianLinearring &ext_ring, + bool &is_inner_inside, bool &is_ext_inside, ObCartesianMultilinestring *&ext_mls) +{ + int ret = OB_SUCCESS; + ObCartesianPolygon tmp_py; + tmp_py.exterior_ring() = ext_ring; + if (OB_FAIL(line_visit(tmp_py.exterior_ring(), ext_mls, is_ext_inside))) { + LOG_WARN("fail to do line visit", K(ret)); + } else if (ext_mls->empty()) { + // ext ring completely outside, but maybe inner ring is inside/on edge + double xmid = xmin_ + (xmax_ - xmin_) / 2; + double ymid = ymin_ + (ymax_ - ymin_) / 2; + ObCartesianPoint pt(xmid, ymid); + ObGeoEvalCtx gis_context(allocator_); + if (OB_FAIL(gis_context.append_geo_arg(&pt)) || OB_FAIL(gis_context.append_geo_arg(&tmp_py))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::gis_func::eval( + gis_context, is_inner_inside))) { + LOG_WARN("eval Within functor failed", K(ret)); + } + } else { + if (is_ring_ccw(tmp_py.exterior_ring())) { + reverse_mls(*ext_mls); + } + } + return ret; +} + +int ObGeoBoxClipVisitor::visit_polygon(ObCartesianPolygon &poly, ObCartesianMultipolygon *&mpy) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(mpy)) { + mpy = OB_NEWx(ObCartesianMultipolygon, allocator_, poly.get_srid(), *allocator_); + if (OB_ISNULL(mpy)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for geometry", K(ret)); + } + } + if (OB_SUCC(ret)) { + ObCartesianMultilinestring *ext_mls = nullptr; + bool is_inner_inside = true; + bool is_ext_inside = false; + if (OB_FAIL(visit_polygon_ext_ring(poly.exterior_ring(), is_inner_inside, is_ext_inside, ext_mls))) { + LOG_WARN("fail to visit polygon exterior ring", K(ret), K(is_inner_inside), K(is_ext_inside)); + } else if (!is_inner_inside) { + // do nothing + } else if (is_ext_inside) { + // completely inside + if (OB_FAIL(mpy->push_back(poly))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } else if (OB_FAIL(reconnect_multi_line(*ext_mls))) { + LOG_WARN("fail to reconnect multi line", K(ret)); + } else { + ObGeomVector &inner_rings = poly.interior_rings(); + ObCartesianMultipolygon tmp_mpy; + bool is_within = false; + for (uint32_t i = 0; OB_SUCC(ret) && i < inner_rings.size() && !is_within; ++i) { + if (OB_FAIL(visit_polygon_inner_ring(inner_rings[i], tmp_mpy, *ext_mls, is_within))) { + LOG_WARN("fail to visit polygon inner ring", + K(ret), + K(i), + K(inner_rings.size()), + K(is_within)); + } + } + if (OB_SUCC(ret) && !is_within) { + ObCartesianMultipolygon new_mpy; + if (OB_FAIL(make_polygons(*ext_mls, tmp_mpy, new_mpy))) { + LOG_WARN("fail to make polygons", K(ret)); + } + for (int i = 0; OB_SUCC(ret) && i < new_mpy.size(); ++i) { + if (OB_FAIL(mpy->push_back(new_mpy[i]))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + } + } + return ret; +} + +int ObGeoBoxClipVisitor::visit(ObCartesianPolygon *geo) +{ + int ret = OB_SUCCESS; + ObCartesianMultipolygon *mpy = nullptr; + if (geo->is_empty()) { + // do nothing + } else if (OB_FAIL(visit_polygon(*geo, mpy))) { + LOG_WARN("fail to visit polygon", K(ret)); + } else if (!mpy->empty()) { + for (uint32_t i = 0; OB_SUCC(ret) && i < mpy->size(); ++i) { + if (OB_FAIL(res_geo_->push_back((*mpy)[i]))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + return ret; +} + +int ObGeoBoxClipVisitor::visit(ObCartesianMultipolygon *geo) +{ + int ret = OB_SUCCESS; + if (!geo->is_empty()) { + ObCartesianMultipolygon *mpy = nullptr; + for (uint32_t i = 0; OB_SUCC(ret) && i < geo->size(); ++i) { + if (OB_FAIL(visit_polygon((*geo)[i], mpy))) { + LOG_WARN("fail to do line visit", K(ret)); + } else { + } + } + if (OB_SUCC(ret) && !mpy->empty()) { + for (uint32_t i = 0; OB_SUCC(ret) && i < mpy->size(); ++i) { + if (OB_FAIL(res_geo_->push_back((*mpy)[i]))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + } + return ret; +} +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_box_clip_visitor.h b/deps/oblib/src/lib/geo/ob_geo_box_clip_visitor.h new file mode 100644 index 0000000000..23eae3ca98 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_box_clip_visitor.h @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_GEO_BOX_CLIP_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_GEO_BOX_CLIP_VISITOR_ + +#include "lib/geo/ob_geo_visitor.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_common.h" + +namespace oceanbase +{ +namespace common +{ +enum ObBoxPosition { + INVALID = 0, + INSIDE = 1, + OUTSIDE = 2, + LEFT_EDGE = 4, + RIGHT_EDGE = 8, + TOP_EDGE = 16, + BOTTOM_EDGE = 32, + TOPLEFT_CORNER = TOP_EDGE | LEFT_EDGE, + TOPRIGHT_CORNER = TOP_EDGE | RIGHT_EDGE, + BOTTOMLEFT_CORNER = BOTTOM_EDGE | LEFT_EDGE, + BOTTOMRIGHT_CORNER = BOTTOM_EDGE | RIGHT_EDGE, +}; + +class ObGeoBoxClipVisitor : public ObEmptyGeoVisitor +{ +public: + explicit ObGeoBoxClipVisitor(const ObGeogBox &box, ObIAllocator &allocator) + : xmin_(box.xmin), + ymin_(box.ymin), + xmax_(box.xmax), + ymax_(box.ymax), + res_geo_(nullptr), + allocator_(&allocator) + {} + virtual ~ObGeoBoxClipVisitor() + {} + + bool prepare(ObGeometry *geo) override; + + int visit(ObCartesianPoint *geo) override; + int visit(ObCartesianLineString *geo) override; + int visit(ObCartesianPolygon *geo) override; + int visit(ObCartesianMultipoint *geo) override; + int visit(ObCartesianMultilinestring *geo) override; + int visit(ObCartesianMultipolygon *geo) override; + int visit(ObCartesianGeometrycollection *geo) + { + UNUSED(geo); + return OB_SUCCESS; + } + + bool is_end(ObCartesianLineString *geo) override + { + UNUSED(geo); + return true; + } + bool is_end(ObCartesianPolygon *geo) override + { + UNUSED(geo); + return true; + } + bool is_end(ObCartesianMultipoint *geo) override + { + UNUSED(geo); + return true; + } + bool is_end(ObCartesianMultilinestring *geo) override + { + UNUSED(geo); + return true; + } + bool is_end(ObCartesianMultipolygon *geo) override + { + UNUSED(geo); + return true; + } + + int finish(ObGeometry *geo) override + { + UNUSED(geo); + return OB_SUCCESS; + } + + int get_geometry(ObGeometry *&geo); + +private: + bool same_edge_positions(ObBoxPosition pos1, ObBoxPosition pos2); + ObBoxPosition get_position(double x, double y); + bool is_point_inside(double x, double y); + void clip_point_to_single_edge( + ObWkbGeomInnerPoint &out_pt, const ObWkbGeomInnerPoint &in_pt, double edge, bool is_x_edge); + void clip_point_to_edges( + const ObWkbGeomInnerPoint &out_pt, const ObWkbGeomInnerPoint &in_pt, ObWkbGeomInnerPoint &pt); + int line_visit( + const ObCartesianLineString &line, ObCartesianMultilinestring *&mls, bool &completely_inside); + int line_visit_outside(const ObCartesianLineString &line, int &idx, ObCartesianMultilinestring *mls, + ObBoxPosition pos, ObCartesianLineString &new_line); + int line_visit_inside_or_edge(const ObCartesianLineString &line, int &idx, + ObCartesianMultilinestring *mls, ObBoxPosition pos, ObCartesianLineString &new_line, + bool &completely_inside); + + int visit_polygon(ObCartesianPolygon &poly, ObCartesianMultipolygon *&mpy); + int reconnect_multi_line(ObCartesianMultilinestring &mls); + int box_to_linearring(ObCartesianLinearring &ring); + int make_polygons(ObCartesianMultilinestring &mls, ObCartesianMultipolygon &mpy, + ObCartesianMultipolygon &new_mpy); + int distance(double x1, double y1, double x2, double y2, double &dist); + void to_next_edge(ObBoxPosition &pos); + int close_ring(ObCartesianLinearring &ring, double x1, double y1, double x2, double y2); + void reverse_ring(ObCartesianLineString &ring, uint32_t start, uint32_t end); + void reorder_ring(ObCartesianLinearring &ring); + void reverse_mls(ObCartesianMultilinestring &mls); + ObGeoType get_result_basic_type(); + bool is_ring_ccw(ObCartesianLineString &ring); + int construct_intersect_line(const ObCartesianLineString &line, int32_t first_inside_idx, + int32_t last_idx, ObCartesianLineString &intersect_line); + int visit_polygon_ext_ring(const ObCartesianLinearring &ext_ring, bool &is_inner_inside, + bool &is_ext_inside, ObCartesianMultilinestring *&ext_mls); + int visit_polygon_inner_ring( + const ObCartesianLinearring &inner_ring, ObCartesianMultipolygon &ext_mpy, ObCartesianMultilinestring &ext_mls, bool &is_within); + int make_polygon_ext_ring(ObCartesianMultilinestring &mls, ObCartesianMultipolygon &new_mpy); + + double xmin_; + double ymin_; + double xmax_; + double ymax_; + ObCartesianGeometrycollection *res_geo_; + ObIAllocator *allocator_; + bool keep_polygon_; + DISALLOW_COPY_AND_ASSIGN(ObGeoBoxClipVisitor); +}; + +} // namespace common +} // namespace oceanbase +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_common.cpp b/deps/oblib/src/lib/geo/ob_geo_common.cpp index d142bef5ea..136bb85ad7 100644 --- a/deps/oblib/src/lib/geo/ob_geo_common.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_common.cpp @@ -135,6 +135,18 @@ int ObWkbBuffer::write(uint64_t pos, uint32_t val) return ret; } +int ObWkbBuffer::read(uint64_t pos, uint32_t &val) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(buf_.ptr()) || pos + sizeof(uint32_t) > buf_.length()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("read is not safe", K(ret), K(pos)); + } else { + val = ObGeoWkbByteOrderUtil::read(buf_.ptr() + pos, bo_); + } + return ret; +} + const ObString ObWkbBuffer::string() const { return buf_.string(); diff --git a/deps/oblib/src/lib/geo/ob_geo_common.h b/deps/oblib/src/lib/geo/ob_geo_common.h index 921980e727..e4860e271e 100644 --- a/deps/oblib/src/lib/geo/ob_geo_common.h +++ b/deps/oblib/src/lib/geo/ob_geo_common.h @@ -93,6 +93,7 @@ public: int append(const char *str, const uint64_t len); int append(const ObString &str); int write(uint64_t pos, uint32_t val); + int read(uint64_t pos, uint32_t &val); const ObString string() const; uint64_t length() const; int append_zero(const uint64_t len); diff --git a/deps/oblib/src/lib/geo/ob_geo_coordinate_range_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_coordinate_range_visitor.cpp index 9828abc34c..bff03f422b 100644 --- a/deps/oblib/src/lib/geo/ob_geo_coordinate_range_visitor.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_coordinate_range_visitor.cpp @@ -30,56 +30,70 @@ check whether the longitude or latitude of a geographical point is out of range @param[in] Geometry object pointer @return Returns OB_SUCCESS on success, error code otherwise. */ -template -int ObGeoCoordinateRangeVisitor::calculate_point_range(Geo_type *geo) +int ObGeoCoordinateRangeVisitor::calculate_point_range(const ObSrsItem *srs, + double longti, + double lati, + bool is_normalized, + ObGeoCoordRangeResult &result) { int ret = OB_SUCCESS; - double longti = geo->x(); // convert to radian in srs defined direction and meridian - if (is_normalized_) { - longti -= srs_->prime_meridian() * srs_->angular_unit(); - if (!srs_->is_longtitude_east()) { + if (is_normalized) { + longti -= srs->prime_meridian() * srs->angular_unit(); + if (!srs->is_longtitude_east()) { longti *= -1.0; } } else { - longti *= srs_->angular_unit(); + longti *= srs->angular_unit(); } if (longti <= -M_PI || longti > M_PI) { - is_long_out_range_ = true; - if (OB_FAIL(srs_->from_radians_to_srs_unit(longti, value_out_range_))) { - LOG_WARN("failed to convert radians to srs unit", K(ret), K(longti), K(srs_)); + result.is_long_out_range_ = true; + if (OB_FAIL(srs->from_radians_to_srs_unit(longti, result.value_out_range_))) { + LOG_WARN("failed to convert radians to srs unit", K(ret), K(longti), K(srs)); } } else { - double lati = geo->y(); // convert to radian in srs defined direction and meridian - if (is_normalized_) { - if (!srs_->is_latitude_north()) { + if (is_normalized) { + if (!srs->is_latitude_north()) { lati *= -1.0; } } else { - lati *= srs_->angular_unit(); + lati *= srs->angular_unit(); } if (lati < -M_PI_2 || lati > M_PI_2) { - is_lati_out_range_ = true; - if (OB_FAIL(srs_->from_radians_to_srs_unit(lati, value_out_range_))) { - LOG_WARN("failed to convert radians to srs unit", K(ret), K(lati), K(srs_)); + result.is_lati_out_range_ = true; + if (OB_FAIL(srs->from_radians_to_srs_unit(lati, result.value_out_range_))) { + LOG_WARN("failed to convert radians to srs unit", K(ret), K(lati), K(srs)); } } } return ret; } +void ObGeoCoordinateRangeVisitor::get_coord_range_result(ObGeoCoordRangeResult &result) +{ + result.is_lati_out_range_ = is_lati_out_range_; + result.is_long_out_range_ = is_long_out_range_; + result.value_out_range_ = value_out_range_; +} + + int ObGeoCoordinateRangeVisitor::visit(ObIWkbGeogPoint *geo) { int ret = OB_SUCCESS; - if (OB_ISNULL(srs_)) { + ObGeoCoordRangeResult result; + if (OB_ISNULL(srs_) || OB_ISNULL(geo)) { ret = OB_ERR_NULL_VALUE; - LOG_WARN("srs is null", K(ret)); + LOG_WARN("srs or geo is null", K(ret)); } else if (srs_->srs_type() == ObSrsType::PROJECTED_SRS) { ret = OB_INVALID_ARGUMENT; LOG_WARN("srs is projected type", K(srs_)); - } else if (OB_FAIL(calculate_point_range(geo))){ + } else if (OB_FAIL(calculate_point_range(srs_, geo->x(), geo->y(), is_normalized_, result))){ LOG_WARN("failed to calculate point range", K(ret)); + } else { + is_lati_out_range_ = result.is_lati_out_range_; + is_long_out_range_ = result.is_long_out_range_; + value_out_range_ = result.value_out_range_; } return ret; } @@ -87,14 +101,19 @@ int ObGeoCoordinateRangeVisitor::visit(ObIWkbGeogPoint *geo) int ObGeoCoordinateRangeVisitor::visit(ObGeographPoint *geo) { int ret = OB_SUCCESS; - if (OB_ISNULL(srs_)) { + ObGeoCoordRangeResult result; + if (OB_ISNULL(srs_) || OB_ISNULL(geo)) { ret = OB_ERR_NULL_VALUE; - LOG_WARN("srs is null", K(ret)); + LOG_WARN("srs or geo is null", K(ret)); } else if (srs_->srs_type() == ObSrsType::PROJECTED_SRS) { ret = OB_INVALID_ARGUMENT; LOG_WARN("srs is projected type", K(srs_)); - } else if (OB_FAIL(calculate_point_range(geo))) { + } else if (OB_FAIL(calculate_point_range(srs_, geo->x(), geo->y(), is_normalized_, result))) { LOG_WARN("failed to calculate point range", K(ret)); + } else { + is_lati_out_range_ = result.is_lati_out_range_; + is_long_out_range_ = result.is_long_out_range_; + value_out_range_ = result.value_out_range_; } return ret; } diff --git a/deps/oblib/src/lib/geo/ob_geo_coordinate_range_visitor.h b/deps/oblib/src/lib/geo/ob_geo_coordinate_range_visitor.h index c07eb6b081..7ac765f9c6 100644 --- a/deps/oblib/src/lib/geo/ob_geo_coordinate_range_visitor.h +++ b/deps/oblib/src/lib/geo/ob_geo_coordinate_range_visitor.h @@ -19,6 +19,12 @@ namespace oceanbase { namespace common { +struct ObGeoCoordRangeResult +{ + bool is_lati_out_range_ = false; + bool is_long_out_range_ = false; + double value_out_range_ = NAN; +}; class ObGeoCoordinateRangeVisitor : public ObEmptyGeoVisitor { @@ -37,9 +43,12 @@ public: void reset(); int visit(ObGeographPoint *geo) override; - - template - int calculate_point_range(Geo_type *geo); + void get_coord_range_result(ObGeoCoordRangeResult& result); + static int calculate_point_range(const ObSrsItem *srs, + double longti, + double lati, + bool is_normalized, + ObGeoCoordRangeResult &result); private: const ObSrsItem *srs_; diff --git a/deps/oblib/src/lib/geo/ob_geo_elevation_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_elevation_visitor.cpp new file mode 100644 index 0000000000..f063d71d2a --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_elevation_visitor.cpp @@ -0,0 +1,522 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "ob_geo_elevation_visitor.h" +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_3d.h" + +namespace oceanbase +{ +namespace common +{ +void ObGeoElevationCell::add_z(double z) +{ + ++z_num_; + z_sum_ += z; +} + +double ObGeoElevationCell::get_avg_z() +{ + if (z_num_ > 0) { + z_avg_ = z_sum_ / z_num_; + } + return z_avg_; +} + +ObGeoElevationExtent::ObGeoElevationExtent( + const ObGeogBox *extent, int32_t cell_num_x /* = 3*/, int32_t cell_num_y /* = 3*/) + : extent_(extent), + cell_num_x_(cell_num_x), + cell_num_y_(cell_num_y), + is_z_calculated_(false), + extent_z_avg_(NAN) +{ + if (OB_ISNULL(extent_)) { + cell_size_x_ = 0; + cell_size_y_ = 0; + } else { + cell_size_x_ = (extent_->xmax - extent_->xmin) / cell_num_x_; + cell_size_y_ = (extent_->ymax - extent_->ymin) / cell_num_y_; + } + cell_num_x_ = cell_size_x_ <= 0.0 ? 1 : cell_num_x_; + cell_num_y_ = cell_size_y_ <= 0.0 ? 1 : cell_num_y_; +} + +int ObGeoElevationExtent::add_geometry(const ObGeometry &g) +{ + int ret = OB_SUCCESS; + if (!ObGeoTypeUtil::is_3d_geo_type(g.type())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("geometry should be 3D type", K(ret), K(g.type())); + } else { + ObGeometry3D *geo3d = const_cast(reinterpret_cast(&g)); + if (OB_FAIL(geo3d->create_elevation_extent(*this))) { + LOG_WARN("fail to create elevation extent", K(ret)); + } + } + return ret; +} + +int64_t ObGeoElevationExtent::get_cell_idx(double x, double y) +{ + int64_t x_idx = 0; + int64_t y_idx = 0; + if (OB_NOT_NULL(extent_)) { + x_idx = static_cast((x - extent_->xmin) / cell_size_x_); + if (x_idx < 0) { + x_idx = 0; + } else if (x_idx >= cell_num_x_) { + x_idx = cell_num_x_ - 1; + } + y_idx = static_cast((y - extent_->ymin) / cell_size_y_); + if (y_idx < 0) { + y_idx = 0; + } else if (y_idx >= cell_num_y_) { + y_idx = cell_num_y_ - 1; + } + } + return cell_num_x_ * y_idx + x_idx; +} + +int ObGeoElevationExtent::add_point(double x, double y, double z) +{ + int ret = OB_SUCCESS; + if (cells_.empty() && OB_FAIL(cells_.prepare_allocate(cell_num_x_ * cell_num_y_))) { + LOG_WARN("fail to reserve cells", K(ret), K(cell_num_x_), K(cell_num_y_)); + } else { + int64_t cell_idx = get_cell_idx(x, y); + ObGeoElevationCell &cell = cells_[cell_idx]; + cell.add_z(z); + } + return ret; +} + +double ObGeoElevationExtent::get_z(double x, double y) +{ + if (!is_z_calculated_) { + calculate_z(); + } + int64_t cell_idx = get_cell_idx(x, y); + ObGeoElevationCell &cell = cells_[cell_idx]; + return cell.is_empty() ? extent_z_avg_ : cell.get_avg_z(); +} + +void ObGeoElevationExtent::calculate_z() +{ + int64_t not_empty_cell = 0; + double z_sum = 0.0; + for (int64_t i = 0; i < cells_.size(); ++i) { + if (!cells_[i].is_empty()) { + ++not_empty_cell; + z_sum += cells_[i].get_avg_z(); + } + } + extent_z_avg_ = not_empty_cell > 0 ? (z_sum / not_empty_cell) : NAN; + is_z_calculated_ = true; +} + +ObGeoElevationVisitor::ObGeoElevationVisitor(ObIAllocator &allocator, const common::ObSrsItem *srs) + : extent_(nullptr), + is_inited_(false), + allocator_(&allocator), + buffer_(allocator), + srs_(srs), + type_3D_(ObGeoType::GEO3DTYPEMAX), + crs_(ObGeoCRS::Cartesian), + srid_(0) +{ + if (OB_NOT_NULL(srs_)) { + crs_ = (srs_->srs_type() == ObSrsType::PROJECTED_SRS) ? ObGeoCRS::Cartesian + : ObGeoCRS::Geographic; + srid_ = srs_->get_srid(); + } +} + +int ObGeoElevationVisitor::add_geometry( + const ObGeometry &geo, ObGeogBox *&extent, bool &is_geo_empty) +{ + int ret = OB_SUCCESS; + ObArenaAllocator tmp_allocator; + if (!ObGeoTypeUtil::is_3d_geo_type(geo.type())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("geometry should be 3D type", K(ret), K(geo.type()), K(geo.type())); + } else { + ObGeometry3D &geo_3D = reinterpret_cast(const_cast(geo)); + if (OB_FAIL(geo_3D.check_empty(is_geo_empty))) { + LOG_WARN("fail to check is geometry empty", K(ret)); + } else if (!is_geo_empty) { + ObGeometry *geo_2D = nullptr; + ObGeoEvalCtx geo_ctx(allocator_, srs_); + geo_ctx.set_is_called_in_pg_expr(true); + ObGeogBox *box = nullptr; + if (OB_FAIL(geo_3D.to_2d_geo(tmp_allocator, geo_2D))) { + LOG_WARN("fail to transfer to 2D geometry", K(ret)); + } else if (OB_FAIL(geo_ctx.append_geo_arg(geo_2D))) { + LOG_WARN("build gis context failed", K(ret), K(geo_ctx.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(geo_ctx, box))) { + LOG_WARN("failed to do box functor failed", K(ret)); + } else if (OB_ISNULL(extent)) { + extent = box; + } else { + ObGeoBoxUtil::box_union(*box, *extent); + } + } + } + return ret; +} + +int ObGeoElevationVisitor::init(const ObGeometry &geo) +{ + int ret = OB_SUCCESS; + ObGeogBox *extent = nullptr; + bool is_geo_empty = false; + if (OB_FAIL(add_geometry(geo, extent, is_geo_empty))) { + LOG_WARN("fail to add geometry to visitor", K(ret)); + } else if (OB_ISNULL(extent_ = OB_NEWx(ObGeoElevationExtent, allocator_, extent))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret)); + } else if (!is_geo_empty && OB_FAIL(extent_->add_geometry(geo))) { + LOG_WARN("fail to add geometry to extent", K(ret)); + } else { + is_inited_ = true; + } + return ret; +} + +int ObGeoElevationVisitor::init(const ObGeometry &geo1, const ObGeometry &geo2) +{ + int ret = OB_SUCCESS; + ObGeogBox *extent = nullptr; + bool is_geo1_empty = false; + bool is_geo2_empty = false; + if (OB_FAIL(add_geometry(geo1, extent, is_geo1_empty))) { + LOG_WARN("fail to add geometry to visitor", K(ret)); + } else if (OB_FAIL(add_geometry(geo2, extent, is_geo2_empty))) { + LOG_WARN("fail to add geometry to visitor", K(ret)); + } else if (OB_ISNULL(extent_ = OB_NEWx(ObGeoElevationExtent, allocator_, extent))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret)); + } else if (!is_geo1_empty && OB_FAIL(extent_->add_geometry(geo1))) { + LOG_WARN("fail to add geometry to extent", K(ret)); + } else if (!is_geo2_empty && OB_FAIL(extent_->add_geometry(geo2))) { + LOG_WARN("fail to add geometry to extent", K(ret)); + } else { + is_inited_ = true; + } + return ret; +} + +bool ObGeoElevationVisitor::prepare(ObGeometry *geo) +{ + bool bret = true; + if (OB_ISNULL(geo) || !is_inited_ || geo->length() < WKB_COMMON_WKB_HEADER_LEN + || ObGeoTypeUtil::is_3d_geo_type(geo->type())) { + bret = false; + } + return bret; +} + +int ObGeoElevationVisitor::append_point(double x, double y, double z) +{ + int ret = OB_SUCCESS; + double val_x = x; + double val_y = y; + if (crs_ == ObGeoCRS::Geographic) { + if (OB_FAIL(srs_->longtitude_convert_from_radians(x, val_x))) { + LOG_WARN("fail to convert radians to longtitude", K(ret)); + } else if (OB_FAIL(srs_->latitude_convert_from_radians(y, val_y))) { + LOG_WARN("fail to convert radians to latitude", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(buffer_.append(val_x))) { + LOG_WARN("failed to append point value x", K(ret), K(x)); + } else if (OB_FAIL(buffer_.append(val_y))) { + LOG_WARN("failed to append point value y", K(ret), K(y)); + } else if (OB_FAIL(buffer_.append(z))) { + LOG_WARN("failed to append point value z", K(ret), K(z)); + } + return ret; +} + +template +int ObGeoElevationVisitor::append_head_info(T *geo, int reserve_len) +{ + int ret = OB_SUCCESS; + type_3D_ = static_cast( + static_cast(geo->type()) + ObGeoTypeUtil::WKB_3D_TYPE_OFFSET); + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(static_cast(ObGeoWkbByteOrder::LittleEndian)))) { + LOG_WARN("failed to append little endian", K(ret)); + } else if (OB_FAIL(buffer_.append(static_cast(type_3D_)))) { + LOG_WARN("failed to append type", K(ret), K(geo->type()), K(type_3D_)); + } else if (OB_FAIL(buffer_.append(static_cast(geo->size())))) { + LOG_WARN("failed to append num value", K(ret), K(geo->size())); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbPoint *geo) +{ + int ret = OB_SUCCESS; + double x = geo->x(); + double y = geo->y(); + uint32_t reserve_len = EWKB_COMMON_WKB_HEADER_LEN + WKB_GEO_DOUBLE_STORED_SIZE * 3; + type_3D_ = static_cast( + static_cast(geo->type()) + ObGeoTypeUtil::WKB_3D_TYPE_OFFSET); + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(static_cast(ObGeoWkbByteOrder::LittleEndian)))) { + LOG_WARN("failed to append point little endian", K(ret)); + } else if (OB_FAIL(buffer_.append(static_cast(type_3D_)))) { + LOG_WARN("failed to append point type", K(ret), K(type_3D_), K(geo->type())); + } else if (OB_FAIL(append_point(x, y, extent_->get_z(x, y)))) { + LOG_WARN("failed to point value", K(ret), K(geo->x()), K(geo->y())); + } + return ret; +} + +template +int ObGeoElevationVisitor::append_line(T_IBIN *geo) +{ + int ret = OB_SUCCESS; + uint32_t reserve_len = WKB_COMMON_WKB_HEADER_LEN + geo->size() * 3 * WKB_GEO_DOUBLE_STORED_SIZE; + if (OB_FAIL(append_head_info(geo, reserve_len))) { + LOG_WARN("failed to append line string head info", K(ret)); + } else { + const T_BIN *line = reinterpret_cast(geo->val()); + typename T_BIN::iterator iter = line->begin(); + for (; OB_SUCC(ret) && iter != line->end(); iter++) { + double x = iter->template get<0>(); + double y = iter->template get<1>(); + if (OB_FAIL(append_point(x, y, extent_->get_z(x, y)))) { + LOG_WARN("failed to point value", K(ret)); + } + } + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeomLineString *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL((append_line(geo)))) { + LOG_WARN("fail to append line", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeogLineString *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL((append_line(geo)))) { + LOG_WARN("fail to append line", K(ret)); + } + return ret; +} + +template +int ObGeoElevationVisitor::append_polygon(T_IBIN *geo) +{ + int ret = OB_SUCCESS; + uint32_t reserve_len = 0; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } else { + T_BIN &poly = *(T_BIN *)(geo->val()); + T_BIN_RING &exterior = poly.exterior_ring(); + if (poly.size() != 0) { + uint32_t ext_num = exterior.size(); + reserve_len = WKB_GEO_ELEMENT_NUM_SIZE + ext_num * 3 * WKB_GEO_DOUBLE_STORED_SIZE; + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(ext_num))) { + LOG_WARN("fail to append ring size", K(ret)); + } + typename T_BIN_RING::iterator iter = exterior.begin(); + for (; OB_SUCC(ret) && iter != exterior.end(); ++iter) { + double x = iter->template get<0>(); + double y = iter->template get<1>(); + if (OB_FAIL(append_point(x, y, extent_->get_z(x, y)))) { + LOG_WARN("failed to point value", K(ret)); + } + } + } + + T_BIN_INNER_RING &inner_rings = poly.inner_rings(); + typename T_BIN_INNER_RING::iterator iterInnerRing = inner_rings.begin(); + for (; OB_SUCC(ret) && iterInnerRing != inner_rings.end(); ++iterInnerRing) { + uint32_t inner_num = iterInnerRing->size(); + reserve_len = WKB_GEO_ELEMENT_NUM_SIZE + inner_num * 3 * WKB_GEO_DOUBLE_STORED_SIZE; + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(inner_num))) { + LOG_WARN("fail to append ring size", K(ret)); + } + typename T_BIN_RING::iterator iter = (*iterInnerRing).begin(); + for (; OB_SUCC(ret) && iter != (*iterInnerRing).end(); ++iter) { + double x = iter->template get<0>(); + double y = iter->template get<1>(); + if (OB_FAIL(append_point(x, y, extent_->get_z(x, y)))) { + LOG_WARN("failed to point value", K(ret)); + } + } + } + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeogPolygon *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL((append_polygon(geo)))) { + LOG_WARN("fail to append polygon", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeomPolygon *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL((append_polygon(geo)))) { + LOG_WARN("fail to append polygon", K(ret)); + } + return ret; +} + +template +int ObGeoElevationVisitor::append_multipoint(T_IBIN *geo) +{ + int ret = OB_SUCCESS; + uint32_t size = geo->size(); + uint32_t reserve_len = size * (EWKB_COMMON_WKB_HEADER_LEN + WKB_GEO_DOUBLE_STORED_SIZE * 3); + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else { + const T_BIN *multi_point = reinterpret_cast(geo->val()); + typename T_BIN::iterator iter = multi_point->begin(); + for (; iter != multi_point->end() && OB_SUCC(ret); iter++) { + double x = iter->template get<0>(); + double y = iter->template get<1>(); + if (OB_FAIL(buffer_.append(static_cast(ObGeoWkbByteOrder::LittleEndian)))) { + LOG_WARN("failed to append point little endian", K(ret)); + } else if (OB_FAIL(buffer_.append(static_cast(ObGeoType::POINTZ)))) { + LOG_WARN("failed to append point type", K(ret)); + } else if (OB_FAIL(append_point(x, y, extent_->get_z(x, y)))) { + LOG_WARN("failed to point value", K(ret)); + } + } + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeogMultiPoint *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } else if (OB_FAIL((append_multipoint(geo)))) { + LOG_WARN("fail to append multipoint", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeomMultiPoint *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } else if (OB_FAIL((append_multipoint(geo)))) { + LOG_WARN("fail to append multipoint", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeogMultiLineString *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeomMultiLineString *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeogMultiPolygon *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeomMultiPolygon *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeogCollection *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::visit(ObIWkbGeomCollection *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObGeoElevationVisitor::get_geometry_3D(ObGeometry *&geo) +{ + int ret = OB_SUCCESS; + if (!is_inited_ || !ObGeoTypeUtil::is_3d_geo_type(type_3D_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("visitor is not inited or not executed", K(ret), K(is_inited_), K(type_3D_)); + } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_type( + *allocator_, type_3D_, ObGeoCRS::Geographic == crs_, true, geo, srid_))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("failed to create swkb", K(ret), K(crs_), K(type_3D_)); + } else { + geo->set_data(buffer_.string()); + } + return ret; +} +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_elevation_visitor.h b/deps/oblib/src/lib/geo/ob_geo_elevation_visitor.h new file mode 100644 index 0000000000..e70aefac7e --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_elevation_visitor.h @@ -0,0 +1,164 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_GEO_ELEVATION_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_GEO_ELEVATION_VISITOR_ +#include "lib/geo/ob_geo_visitor.h" +#include "lib/geo/ob_geo_utils.h" + +namespace oceanbase +{ + +namespace common +{ +class ObGeoElevationCell +{ +public: + explicit ObGeoElevationCell() : z_num_(0), z_sum_(0.0), z_avg_(NAN) + {} + void add_z(double z); + bool is_empty() + { + return z_num_ == 0; + } + double get_avg_z(); + TO_STRING_KV(K_(z_num), K_(z_sum), K_(z_avg)); + +private: + int32_t z_num_; + double z_sum_; + double z_avg_; +}; + +class ObGeoElevationExtent +{ +public: + explicit ObGeoElevationExtent( + const ObGeogBox *extent, int32_t cell_num_x = 3, int32_t cell_num_y = 3); + virtual ~ObGeoElevationExtent() { cells_.destroy(); } + int add_geometry(const ObGeometry &g); + int add_point(double x, double y, double z); + double get_z(double x, double y); + +private: + int64_t get_cell_idx(double x, double y); + void calculate_z(); + + const ObGeogBox *extent_; + int32_t cell_num_x_; + int32_t cell_num_y_; + double cell_size_x_; + double cell_size_y_; + ObArray cells_; + bool is_z_calculated_; + double extent_z_avg_; +}; + +class ObGeoElevationVisitor : public ObEmptyGeoVisitor +{ +public: + explicit ObGeoElevationVisitor(ObIAllocator &allocator, const common::ObSrsItem *srs); + virtual ~ObGeoElevationVisitor() + { if (OB_NOT_NULL(extent_)) + { extent_->~ObGeoElevationExtent(); } + } + int init(const ObGeometry &geo1, const ObGeometry &geo2); + int init(const ObGeometry &geo); + bool prepare(ObGeometry *geo); + // wkb + int visit(ObIWkbPoint *geo); + + int visit(ObIWkbGeogLineString *geo); + int visit(ObIWkbGeomLineString *geo); + + int visit(ObIWkbGeogMultiPoint *geo); + int visit(ObIWkbGeomMultiPoint *geo); + + int visit(ObIWkbGeogPolygon *geo); + int visit(ObIWkbGeomPolygon *geo); + + int visit(ObIWkbGeogMultiLineString *geo); + int visit(ObIWkbGeomMultiLineString *geo); + + int visit(ObIWkbGeogMultiPolygon *geo); + int visit(ObIWkbGeomMultiPolygon *geo); + + int visit(ObIWkbGeogCollection *geo); + int visit(ObIWkbGeomCollection *geo); + + // is_end default false + bool is_end(ObIWkbGeogLineString *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeomLineString *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeogPolygon *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeomPolygon *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeogMultiPoint *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeomMultiPoint *geo) + { + UNUSED(geo); + return true; + } + + int get_geometry_3D(ObGeometry *&geo); + +private: + int add_geometry(const ObGeometry &geo, ObGeogBox *&extent, bool &is_geo_empty); + int append_point(double x, double y, double z); + template + int append_head_info(T *geo, int reserve_len); + template + int append_line(T_IBIN *geo); + template + int append_polygon(T_IBIN *geo); + template + int append_multipoint(T_IBIN *geo); + + ObGeoElevationExtent *extent_; + bool is_inited_; + ObIAllocator *allocator_; + ObWkbBuffer buffer_; + const common::ObSrsItem *srs_; + ObGeoType type_3D_; + ObGeoCRS crs_; + uint32_t srid_; + + DISALLOW_COPY_AND_ASSIGN(ObGeoElevationVisitor); +}; + +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_box.cpp b/deps/oblib/src/lib/geo/ob_geo_func_box.cpp index 325e756fba..0ac9704842 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_box.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_box.cpp @@ -112,7 +112,7 @@ OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeogMultiPoint, ObGeogBox *) *res = tmp; is_start = true; } else { - ObGeoBoxUtil::box_uion(tmp, *res); + ObGeoBoxUtil::box_union(tmp, *res); } } if (OB_SUCC(ret)) { @@ -141,7 +141,7 @@ OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeogMultiLineString, ObGeogBox *) *res = tmp; is_start = true; } else { - ObGeoBoxUtil::box_uion(tmp, *res); + ObGeoBoxUtil::box_union(tmp, *res); } } if (OB_SUCC(ret)) { @@ -170,7 +170,7 @@ OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeogMultiPolygon, ObGeogBox *) *res = tmp; is_start = true; } else { - ObGeoBoxUtil::box_uion(tmp, *res); + ObGeoBoxUtil::box_union(tmp, *res); } } if (OB_SUCC(ret)) { @@ -219,7 +219,7 @@ OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeogCollection, ObGeogBox *) *res = *subres; is_start = true; } else { - ObGeoBoxUtil::box_uion(*subres, *res); + ObGeoBoxUtil::box_union(*subres, *res); } } } @@ -232,6 +232,186 @@ OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeogCollection, ObGeogBox *) return ret; } OB_GEO_FUNC_END; +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeomPoint, ObGeogBox *) +{ + int ret = OB_SUCCESS; + ObGeogBox *res = OB_NEWx(ObGeogBox, context.get_allocator()); + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create geo box", K(ret)); + } else { + const ObWkbGeomPoint *point = reinterpret_cast(g->val()); + res->xmin = point->get<0>(); + res->xmax = point->get<0>(); + res->ymin = point->get<1>(); + res->ymax = point->get<1>(); + result = res; + } + return ret; +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeomLineString, ObGeogBox *) +{ + int ret = OB_SUCCESS; + ObGeogBox *res = OB_NEWx(ObGeogBox, context.get_allocator()); + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create geo box", K(ret)); + } else { + const ObWkbGeomLineString *line = reinterpret_cast(g->val()); + if (OB_FAIL(ObGeoBoxUtil::get_geom_line_box(*line, *res))) { + LOG_WARN("fail to get poly box", K(ret)); + } else { + result = res; + } + } + return ret; +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeomPolygon, ObGeogBox *) +{ + INIT_SUCC(ret); + ObGeogBox *res = OB_NEWx(ObGeogBox, context.get_allocator()); + const ObWkbGeomPolygon *poly = reinterpret_cast(g->val()); + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create geo box", K(ret)); + } else if (OB_FAIL(ObGeoBoxUtil::get_geom_poly_box(*poly, context.get_is_called_in_pg_expr(), *res))) { + LOG_WARN("fail to calc polygon box", K(ret)); + } else { + result = res; + } + return ret; +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeomMultiPoint, ObGeogBox *) +{ + int ret = OB_SUCCESS; + ObGeogBox *res = OB_NEWx(ObGeogBox, context.get_allocator()); + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create geo box", K(ret)); + } else { + const ObWkbGeomMultiPoint *multi_point = reinterpret_cast(g->val()); + if (OB_FAIL(ObGeoBoxUtil::get_geom_line_box(*multi_point, *res))) { + LOG_WARN("fail to get poly box", K(ret)); + } else { + result = res; + } + } + return ret; +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeomMultiLineString, ObGeogBox *) +{ + int ret = OB_SUCCESS; + ObGeogBox *res = OB_NEWx(ObGeogBox, context.get_allocator()); + bool is_first_poly = true; + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create geo box", K(ret)); + } else { + const ObWkbGeomMultiLineString *multiline = reinterpret_cast(g->val()); + ObWkbGeomMultiLineString::iterator iter = multiline->begin(); + for (; OB_SUCC(ret) && iter != multiline->end(); iter++) { + ObGeogBox tmp; + if (OB_FAIL(ObGeoBoxUtil::get_geom_line_box(*iter, tmp))) { + LOG_WARN("fail to get poly box", K(ret)); + } else if (is_first_poly) { + is_first_poly = false; + *res = tmp; + } else { + ObGeoBoxUtil::box_union(tmp, *res); + } + } + if (OB_SUCC(ret)) { + result = res; + } + } + return ret; +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeomMultiPolygon, ObGeogBox *) +{ + int ret = OB_SUCCESS; + ObGeogBox *res = OB_NEWx(ObGeogBox, context.get_allocator()); + bool is_first_poly = true; + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create geo box", K(ret)); + } else { + const ObWkbGeomMultiPolygon *multipoly = reinterpret_cast(g->val()); + ObWkbGeomMultiPolygon::iterator iter = multipoly->begin(); + for (; OB_SUCC(ret) && iter != multipoly->end(); iter++) { + ObGeogBox tmp; + if (OB_FAIL(ObGeoBoxUtil::get_geom_poly_box(*iter, context.get_is_called_in_pg_expr(), tmp))) { + LOG_WARN("fail to calc polygon box", K(ret)); + } else if (is_first_poly) { + is_first_poly = false; + *res = tmp; + } else { + ObGeoBoxUtil::box_union(tmp, *res); + } + } + if (OB_SUCC(ret)) { + result = res; + } + } + return ret; +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBoxImpl, ObWkbGeomCollection, ObGeogBox *) +{ + int ret = OB_SUCCESS; + common::ObIAllocator *allocator = context.get_allocator(); + ObGeogBox *res = OB_NEWx(ObGeogBox, allocator); + bool is_first = true; + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create geo box", K(ret)); + } else { + const ObWkbGeomCollection *coll = reinterpret_cast(g->val()); + ObWkbGeomCollection::iterator iter = coll->begin(); + for (; OB_SUCC(ret) && iter != coll->end(); iter++) { + ObWkbGeogCollection::const_pointer sub_ptr = iter.operator->(); + ObGeoType sub_type = coll->get_sub_type(sub_ptr); + ObGeometry *sub_g = NULL; + if (OB_FAIL(ObGeoTypeUtil::create_geo_by_type(*allocator, sub_type, false, true, sub_g))) { + LOG_WARN("failed to create wkb", K(ret), K(sub_type)); + } else { + ObString wkb_nosrid(WKB_COMMON_WKB_HEADER_LEN, reinterpret_cast(sub_ptr)); + sub_g->set_data(wkb_nosrid); + sub_g->set_srid(g->get_srid()); + ObGeogBox *tmp = NULL; + if (OB_FAIL(eval_wkb_unary(sub_g, context, tmp))) { + LOG_WARN("fail to eval sub geometry", K(ret), K(sub_type)); + } else if (OB_ISNULL(tmp)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("sub geometry box is null", K(ret), K(sub_type)); + } else { + if (is_first) { + is_first = false; + *res = *tmp; + } else { + ObGeoBoxUtil::box_union(*tmp, *res); + } + } + } + } + + if (OB_SUCC(ret)) { + result = res; + } + } + return ret; +} +OB_GEO_FUNC_END; int ObGeoFuncBox::eval(const ObGeoEvalCtx &gis_context, ObGeogBox *&result) { diff --git a/deps/oblib/src/lib/geo/ob_geo_func_buffer.cpp b/deps/oblib/src/lib/geo/ob_geo_func_buffer.cpp index 42cb8e1130..fe67e18c6e 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_buffer.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_buffer.cpp @@ -725,6 +725,24 @@ OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncBufferImpl, ObWkbGeogCollection, ObGeometry *) ObIWkbGeomLineString>(g, context, result, true); } OB_GEO_FUNC_END; +OB_GEO_UNARY_TREE_FUNC_BEGIN(ObGeoFuncBufferImpl, ObCartesianPolygon, ObGeometry *) +{ + INIT_SUCC(ret); + if (OB_SUCC(ob_geo_validate_buffer_input(g, context))) { + const ObGeoBufferStrategy *strategy = context.get_val_arg(0)->strategy_; + if (is_valid_for_polygon(*strategy)) { + ret = eval_buffer_cartisan(g, context, *strategy, result, true); + } else { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("validate strategy for cartisan polygon failed", + K(ret), K(strategy->distance_val_), K(strategy->has_point_s_), + K(strategy->has_join_s_), K(strategy->has_end_s_)); + } + } + return ret; +} OB_GEO_FUNC_END; + template bool ObGeoFuncBufferImpl::apply_bg_equal(GeometryType &geo1, GeometryType &geo2, diff --git a/deps/oblib/src/lib/geo/ob_geo_func_centroid.cpp b/deps/oblib/src/lib/geo/ob_geo_func_centroid.cpp new file mode 100644 index 0000000000..ad979f1179 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_centroid.cpp @@ -0,0 +1,159 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_centroid. + */ + +#define USING_LOG_PREFIX LIB + +#include "lib/geo/ob_geo_dispatcher.h" +#include "lib/geo/ob_geo_func_centroid.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/oblog/ob_log_module.h" +#include "lib/geo/ob_geo_func_utils.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" + +using namespace oceanbase::common; +namespace oceanbase +{ +namespace common +{ +class ObGeoFuncCentroidImpl : public ObIGeoDispatcher +{ + // do nothing for geo types other then polygons and boxes +public: + ObGeoFuncCentroidImpl(); + virtual ~ObGeoFuncCentroidImpl() = default; + // default templates + OB_GEO_UNARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + OB_GEO_TREE_UNARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_GIS_INVALID_DATA); + OB_GEO_CART_BINARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_GIS_INVALID_DATA); + OB_GEO_GEOG_BINARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_GIS_INVALID_DATA); + OB_GEO_CART_TREE_FUNC_DEFAULT(ObGeometry *, OB_ERR_GIS_INVALID_DATA); + OB_GEO_GEOG_TREE_FUNC_DEFAULT(ObGeometry *, OB_ERR_GIS_INVALID_DATA); + +private: + static int centroid_collection(const ObGeometry *g, const ObGeoEvalCtx &context, ObGeometry *&result) + { + int ret = OB_SUCCESS; + if (g->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("input geometry is not collection type", K(ret), K(g->type())); + } else { + ObCartesianMultipoint *mpt = nullptr; + ObCartesianMultilinestring *ml = nullptr; + ObCartesianMultipolygon *mpo = nullptr; + ObIAllocator *allocator = context.get_allocator(); + ObCartesianPoint *res_geo = OB_NEWx(ObCartesianPoint, allocator, 0, 0, g->get_srid(), allocator); + ObGeoToTreeVisitor tree_visitor(allocator); + if (OB_ISNULL(res_geo)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for result grometry", K(ret)); + } else if (OB_FAIL(const_cast(g)->do_visit(tree_visitor))) { + LOG_WARN("failed to transform gc to tree", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_split(*allocator, + *static_cast(tree_visitor.get_geometry()), + mpt, ml, mpo))) { // only split, do not union + LOG_WARN("failed to do gc split", K(ret)); + } else if (OB_ISNULL(mpt) || OB_ISNULL(ml) || OB_ISNULL(mpo)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("unexpected null geometry collection split", K(ret), KP(mpt), KP(ml), KP(mpo)); + } else { + if (!mpo->empty()) { + boost::geometry::centroid(*mpo, *res_geo); + } else if (!ml->empty()) { + boost::geometry::centroid(*ml, *res_geo); + } else { + // return OB_ERR_BOOST_GEOMETRY_CENTROID_EXCEPTION if mpt is empty too + // need caller function to decide what to do + boost::geometry::centroid(*mpt, *res_geo); + } + result = res_geo; + } + } + return ret; + } + + template + static int centroid_default(const ObGeometry *g, const ObGeoEvalCtx &context, ObGeometry *&result) + { + int ret = OB_SUCCESS; + ObCartesianPoint *res_geo = OB_NEWx(ObCartesianPoint, context.get_allocator(), 0, 0, g->get_srid(), context.get_allocator()); + if (OB_ISNULL(res_geo)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for result grometry", K(ret)); + } else { + GeoType *geo_candidate = nullptr; + if (!g->is_tree()) { + geo_candidate = reinterpret_cast(const_cast(g->val())); + } else { + geo_candidate = reinterpret_cast(const_cast(g)); + } + if (OB_ISNULL(geo_candidate)) { + ret = OB_ERR_INVALID_NULL_SDO_GEOMETRY; + LOG_WARN("invalid null geometry", K(ret)); + } else { + boost::geometry::centroid(*geo_candidate, *res_geo); + result = res_geo; + } + } + return ret; + } +}; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncCentroidImpl, ObWkbGeomPoint, ObGeometry *) +{ + return centroid_default(g, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncCentroidImpl, ObWkbGeomMultiPoint, ObGeometry *) +{ + return centroid_default(g, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncCentroidImpl, ObWkbGeomLineString, ObGeometry *) +{ + return centroid_default(g, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncCentroidImpl, ObWkbGeomMultiLineString, ObGeometry *) +{ + return centroid_default(g, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncCentroidImpl, ObWkbGeomPolygon, ObGeometry *) +{ + return centroid_default(g, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncCentroidImpl, ObWkbGeomMultiPolygon, ObGeometry *) +{ + return centroid_default(g, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncCentroidImpl, ObWkbGeomCollection, ObGeometry *) +{ + return centroid_collection(g, context, result); +} +OB_GEO_FUNC_END; + +int ObGeoFuncCentroid::eval(const ObGeoEvalCtx &gis_context, ObGeometry *&result) +{ + return ObGeoFuncCentroidImpl::eval_geo_func(gis_context, result); +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_centroid.h b/deps/oblib/src/lib/geo/ob_geo_func_centroid.h new file mode 100644 index 0000000000..b842c71c13 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_centroid.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_centroid. + */ + +#ifndef OCEANBASE_LIB_OB_GEO_FUNC_CENTROID_ +#define OCEANBASE_LIB_OB_GEO_FUNC_CENTROID_ + +#include "lib/geo/ob_geo_func_common.h" + +namespace oceanbase +{ +namespace common +{ + +class ObGeoFuncCentroid +{ +public: + ObGeoFuncCentroid(); + ~ObGeoFuncCentroid(); + static int eval(const common::ObGeoEvalCtx &gis_context, ObGeometry *&result); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_LIB_OB_GEO_FUNC_CENTROID_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_common.h b/deps/oblib/src/lib/geo/ob_geo_func_common.h index 2005444968..2be7a383dd 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_common.h +++ b/deps/oblib/src/lib/geo/ob_geo_func_common.h @@ -50,11 +50,11 @@ union ObGeoNormalVal { class ObGeoEvalCtx { public: - ObGeoEvalCtx() : allocator_(NULL), srs_(NULL), g_arg_c_(0), v_arg_c_(0){}; + ObGeoEvalCtx() : allocator_(NULL), srs_(NULL), g_arg_c_(0), v_arg_c_(0), is_called_in_pg_expr_(false){}; ObGeoEvalCtx(common::ObIAllocator * allocator) : - allocator_(allocator), srs_(NULL), g_arg_c_(0), v_arg_c_(0) {}; + allocator_(allocator), srs_(NULL), g_arg_c_(0), v_arg_c_(0), is_called_in_pg_expr_(false) {}; ObGeoEvalCtx(common::ObIAllocator * allocator, const common::ObSrsItem *srs_item) : - allocator_(allocator), srs_(srs_item), g_arg_c_(0), v_arg_c_(0) {}; + allocator_(allocator), srs_(srs_item), g_arg_c_(0), v_arg_c_(0), is_called_in_pg_expr_(false) {}; ~ObGeoEvalCtx() = default; inline int append_geo_arg(const common::ObGeometry *g) @@ -154,6 +154,9 @@ public: inline common::ObIAllocator * get_allocator() const { return allocator_; } inline const common::ObSrsItem *get_srs() const { return srs_; } + inline void set_is_called_in_pg_expr(bool in) { is_called_in_pg_expr_ = in; } + inline bool get_is_called_in_pg_expr() const { return is_called_in_pg_expr_; } + // interfaces for unittest only inline void ut_set_geo_count(int count) { @@ -176,11 +179,17 @@ private: int v_arg_c_; // num of other arguments, e.g. distance_sphere const common::ObGeometry *gis_args_[MAX_ARG_COUNT]; // geo arguments ObGeoNormalVal val_args_[MAX_ARG_COUNT]; // other arguments + bool is_called_in_pg_expr_; // distinguish pg/mysql expr call private: DISALLOW_COPY_AND_ASSIGN(ObGeoEvalCtx); }; +struct ObGeoFuncResWithNull { + bool bret = false; + bool is_null = false; +}; + } // sql } // oceanbase #endif // OCEANBASE_LIB_OB_GEO_FUNC_COMMON_H_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_covered_by.cpp b/deps/oblib/src/lib/geo/ob_geo_func_covered_by.cpp index 0140fd1349..1effcfc2d9 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_covered_by.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_covered_by.cpp @@ -307,9 +307,8 @@ OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncCoveredByImpl, ObWkbGeomPolygon, ObWkbGeo ObIAllocator *allocator = context.get_allocator(); uint32_t srid = srs != NULL ? srs->get_srid() : 0; const ObWkbGeomPolygon *geo1 = reinterpret_cast(g1->val()); - ObCartesianMultipolygon res_geo1(srid, *allocator); - boost::geometry::difference(*geo1, *cart_multi_poly, res_geo1); - result = res_geo1.is_empty(); + boost::geometry::correct(*const_cast(geo1)); + result = boost::geometry::covered_by(*geo1, *cart_multi_poly); } return ret; } OB_GEO_FUNC_END; @@ -397,8 +396,8 @@ OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncCoveredByImpl, ObWkbGeomMultiPolygon, ObW uint32_t srid = srs != NULL ? srs->get_srid() : 0; const ObWkbGeomMultiPolygon *geo1 = reinterpret_cast(g1->val()); ObCartesianMultipolygon res_geo1(srid, *allocator); - boost::geometry::difference(*geo1, *cart_multi_poly, res_geo1); - result = res_geo1.is_empty(); + boost::geometry::correct(*const_cast(geo1)); + result = boost::geometry::covered_by(*geo1, *cart_multi_poly); } return ret; } OB_GEO_FUNC_END; @@ -834,9 +833,9 @@ OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncCoveredByImpl, ObWkbGeogPolygon, ObWkbGeo boost::geometry::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); ObLlLaAaStrategy line_strategy(geog_sphere); const ObWkbGeogPolygon *geo1 = reinterpret_cast(g1->val()); - ObGeographMultipolygon res_geo1(srid, *allocator); - boost::geometry::difference(*geo1, *multi_poly, res_geo1, line_strategy); - result = res_geo1.is_empty(); + boost::geometry::strategy::area::geographic<> area_strategy(geog_sphere); + boost::geometry::correct(*const_cast(geo1), area_strategy); + result = boost::geometry::covered_by(*geo1, *multi_poly); } return ret; } OB_GEO_FUNC_END; @@ -929,9 +928,9 @@ OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncCoveredByImpl, ObWkbGeogMultiPolygon, ObW boost::geometry::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); ObLlLaAaStrategy line_strategy(geog_sphere); const ObWkbGeogMultiPolygon *geo1 = reinterpret_cast(g1->val()); - ObGeographMultipolygon res_geo1(srid, *allocator); - boost::geometry::difference(*geo1, *multi_poly, res_geo1, line_strategy); - result = res_geo1.is_empty(); + boost::geometry::strategy::area::geographic<> area_strategy(geog_sphere); + boost::geometry::correct(*const_cast(geo1), area_strategy); + result = boost::geometry::covered_by(*geo1, *multi_poly); } return ret; } OB_GEO_FUNC_END; @@ -1185,6 +1184,15 @@ OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncCoveredByImpl, ObWkbGeogCollection, ObWkb return ret; } OB_GEO_FUNC_END; +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncCoveredByImpl, ObCartesianLineString, ObCartesianPolygon, bool) +{ + UNUSED(context); + const ObCartesianPoint *geo1 = reinterpret_cast(g1); + const ObCartesianPolygon *geo2 = reinterpret_cast(g2); + result = boost::geometry::covered_by(*geo1, *geo2); + return OB_SUCCESS; +} OB_GEO_FUNC_END; + int ObGeoFuncCoveredBy::eval(const ObGeoEvalCtx &gis_context, bool &result) { return ObGeoFuncCoveredByImpl::eval_geo_func(gis_context, result); diff --git a/deps/oblib/src/lib/geo/ob_geo_func_crosses.cpp b/deps/oblib/src/lib/geo/ob_geo_func_crosses.cpp new file mode 100644 index 0000000000..2af86b4754 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_crosses.cpp @@ -0,0 +1,806 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_crosses. + */ + +#define USING_LOG_PREFIX LIB + +#include "lib/geo/ob_geo_dispatcher.h" +#include "lib/geo/ob_geo_func_crosses.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_func_utils.h" + +using namespace oceanbase::common; +namespace oceanbase +{ +namespace common +{ +namespace bg = boost::geometry; + +template +static void disjoint_with_point(const GeometryType1 *geo1, const GeometryType2 *geo2, + ObBGStrategyType strategy, const ObGeoEvalCtx &context, bool &res) +{ + if (strategy == ObBGStrategyType::DEFAULT_NONE) { + res = bg::disjoint(*geo1, *geo2); + } else { + const ObSrsItem *srs = context.get_srs(); + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::within::geographic_winding point_strategy(geog_sphere); + res = bg::disjoint(*geo1, *geo2, point_strategy); + } +} + +template +static int eval_crosses_without_strategy(const ObGeometry *g1, const ObGeometry *g2, bool &result) +{ + int ret = OB_SUCCESS; + const GeoType1 *geo1 = NULL; + const GeoType2 *geo2 = NULL; + if (g1->is_tree()) { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } else { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("multipoint or linestring pointer is null", K(ret), K(geo1), K(geo2)); + } else { + result = bg::crosses(*geo1, *geo2); + } + return ret; +} + +template +static int eval_crosses_with_nonpoint_strategy( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) +{ + INIT_SUCC(ret); + const ObSrsItem *srs = context.get_srs(); + if (OB_ISNULL(srs)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret), K(g1->get_srid()), K(g1), K(g2)); + } else { + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::intersection::geographic_segments<> nonpoint_strategy(geog_sphere); + const GeoType1 *geo1 = NULL; + const GeoType2 *geo2 = NULL; + if (g1->is_tree()) { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } else { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("multipoint or linestring pointer is null", K(ret), K(geo1), K(geo2)); + } else { + result = bg::crosses(*geo1, *geo2, nonpoint_strategy); + } + } + return ret; +} + +// ----- ObGeoFuncCrossesImpl ----- +class ObGeoFuncCrossesImpl : public ObIGeoDispatcher +{ +public: + ObGeoFuncCrossesImpl(); + virtual ~ObGeoFuncCrossesImpl() = default; + + // template for unary + OB_GEO_UNARY_FUNC_DEFAULT(ObGeoFuncResWithNull, OB_ERR_GIS_INVALID_DATA); + OB_GEO_TREE_UNARY_FUNC_DEFAULT(ObGeoFuncResWithNull, OB_ERR_GIS_INVALID_DATA); + OB_GEO_CART_TREE_FUNC_DEFAULT(ObGeoFuncResWithNull, OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS); + OB_GEO_GEOG_TREE_FUNC_DEFAULT(ObGeoFuncResWithNull, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + + // template for binary + // default cases for cartesian + template + struct EvalWkbBi + { + static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, + ObGeoFuncResWithNull &result) + { + // If g1 or g2 is dimension 0, return NULL (SQL/MM 2015, Sect. 5.1.51) + UNUSEDx(g1, g2, context); + result.is_null = true; + return OB_SUCCESS; + } + }; + + // default case for geography + template + struct EvalWkbBiGeog + { + static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, + ObGeoFuncResWithNull &result) + { + // If g1 or g2 is dimension 0, return NULL (SQL/MM 2015, Sect. 5.1.51) + UNUSEDx(g1, g2, context); + result.is_null = true; + return OB_SUCCESS; + } + }; + +private: + template + static void within_with_point(const GeometryType1 *geo1, const GeometryType2 *geo2, + ObBGStrategyType strategy, const ObGeoEvalCtx &context, bool &res) + { + if (strategy == ObBGStrategyType::DEFAULT_NONE) { + res = bg::within(*geo1, *geo2); + } else { + const ObSrsItem *srs = context.get_srs(); + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::within::geographic_winding point_strategy(geog_sphere); + res = bg::within(*geo1, *geo2, point_strategy); + } + } + + template + static int eval_crosses_mpt(const ObGeometry *mpt, const ObGeometry *geo, const ObGeoEvalCtx &context, + ObBGStrategyType strategy, bool &result) + { + int ret = OB_SUCCESS; + const MptType *mpt_bin = NULL; + const GeoType *geo_bin = NULL; + if (mpt->is_tree()) { + mpt_bin = reinterpret_cast(mpt); + geo_bin = reinterpret_cast(geo); + } else { + mpt_bin = reinterpret_cast(mpt->val()); + geo_bin = reinterpret_cast(geo->val()); + } + result = false; + if (OB_ISNULL(mpt_bin) || OB_ISNULL(geo_bin)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("multipoint or linestring pointer is null", K(ret), K(mpt_bin), K(geo_bin)); + } else { + // g1 at least have one point within g2 + // and at least have one point disjoint from g2 + typename MptType::const_iterator iter = mpt_bin->begin(); + bool is_disjoint = false; + bool is_within = false; + for (; iter != mpt_bin->end() && (!is_within || !is_disjoint); iter++) { + typename MptType::value_type &point = *iter; + bool pt_disjoint = false; + if (!is_disjoint) { + disjoint_with_point(&point, geo_bin, strategy, context, pt_disjoint); + is_disjoint = pt_disjoint; + } + if (!pt_disjoint && !is_within) { + within_with_point(&point, geo_bin, strategy, context, is_within); + } + } + result = is_within && is_disjoint; + } + return ret; + } + + static int eval_difference( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&res) + { + int ret = OB_SUCCESS; + ObGeometry *last_res = res; + ObGeoEvalCtx diff_ctx(context.get_allocator(), context.get_srs()); + if (OB_FAIL(diff_ctx.append_geo_arg(g1)) || OB_FAIL(diff_ctx.append_geo_arg(g2))) { + LOG_WARN("failed to append geo to ctx", K(ret)); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(diff_ctx, res))) { + LOG_WARN("failed to do func difference", K(ret)); + } else if (OB_NOT_NULL(last_res)) { + context.get_allocator()->free(last_res); + last_res = nullptr; + } + return ret; + } + + template + static int is_part_difference_gc_gc(typename GcTreeType::sub_mpt_type *mpt1, + typename GcTreeType::sub_ml_type *mls1, typename GcTreeType::sub_mpt_type *mpt2, + typename GcTreeType::sub_ml_type *mls2, typename GcTreeType::sub_mp_type *mpy2, + const ObGeoEvalCtx &context, bool &is_part_difference) + { + int ret = OB_SUCCESS; + ObGeometry *diff_result = nullptr; + is_part_difference = false; + if (OB_FAIL(eval_difference(mpt1, mpt2, context, diff_result))) { + LOG_WARN("failed to do func difference", K(ret)); + } else if (OB_FAIL(eval_difference(diff_result, mls2, context, diff_result))) { + LOG_WARN("failed to do func difference", K(ret)); + } else if (OB_FAIL(eval_difference(diff_result, mpy2, context, diff_result))) { + LOG_WARN("failed to do func difference", K(ret)); + } else if (diff_result->type() != ObGeoType::MULTIPOINT) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("result of func difference might be invalid", K(ret), K(diff_result->type())); + } else { + typename GcTreeType::sub_mpt_type *mpt_diff = + static_cast(diff_result); + if (!mpt_diff->is_empty()) { + is_part_difference = true; + } else { + if (OB_FAIL(eval_difference(mls1, mls2, context, diff_result))) { + LOG_WARN("failed to do func difference", K(ret)); + } else if (OB_FAIL(eval_difference(diff_result, mpy2, context, diff_result))) { + LOG_WARN("failed to do func difference", K(ret)); + } else { + typename GcTreeType::sub_ml_type *mls_diff = + static_cast(diff_result); + is_part_difference = !mls_diff->is_empty(); + } + } + } + return ret; + } + + template + static int has_common_interior_gc_gc(typename GcTreeType::sub_mpt_type *mpt1, + typename GcTreeType::sub_ml_type *mls1, typename GcTreeType::sub_mp_type *mpy1, + typename GcTreeType::sub_mpt_type *mpt2, typename GcTreeType::sub_ml_type *mls2, + typename GcTreeType::sub_mp_type *mpy2, const ObGeoEvalCtx &context, + bool &has_common_interior) + { + int ret = OB_SUCCESS; + has_common_interior = false; + bg::de9im::mask mask_0("0********"); + bg::de9im::mask mask_T("T********"); + bool is_both_dim_1 = + mpy1->is_empty() && !mls1->is_empty() && mpy2->is_empty() && !mls2->is_empty(); + if (mpt1->crs() == ObGeoCRS::Cartesian || is_both_dim_1) { + has_common_interior = + is_both_dim_1 ? bg::relate(*mpt1, *mpt2, mask_0) : bg::relate(*mpt1, *mpt2, mask_T); + typename GcTreeType::sub_mpt_type::iterator iter = mpt1->begin(); + for (; !has_common_interior && iter != mpt1->end(); iter++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter; + if (is_both_dim_1) { + has_common_interior = bg::relate(pt, *mls2, mask_0); + } else { + has_common_interior = bg::relate(pt, *mpt2, mask_T) || bg::relate(pt, *mpy2, mask_T); + } + } + typename GcTreeType::sub_mpt_type::iterator iter2 = mpt2->begin(); + for (; !has_common_interior && iter2 != mpt2->end(); iter2++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter2; + has_common_interior = + is_both_dim_1 ? bg::relate(pt, *mls1, mask_0) : bg::relate(pt, *mpt1, mask_T); + } + if (is_both_dim_1) { + bg::de9im::mask mask_1("1********"); + if (bg::relate(*mls1, *mls2, mask_0)) { + has_common_interior = true; + } else if (bg::relate(*mls1, *mls2, mask_1)) { + // common interior should not be dimension 1 + has_common_interior = false; + } + } else { + if (!has_common_interior) { + has_common_interior = + bg::relate(*mls1, *mls2, mask_T) || bg::relate(*mls1, *mpy2, mask_T); + } + } + } else { + // mpt1->crs() == ObGeoCRS::Geographic && !is_both_dim_1 + const ObSrsItem *srs = context.get_srs(); + if (OB_ISNULL(srs)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret)); + } else { + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::within::geographic_winding point_strategy(geog_sphere); + has_common_interior = bg::relate(*mpt1, *mpt2, mask_T); + typename GcTreeType::sub_mpt_type::iterator iter = mpt1->begin(); + for (; !has_common_interior && iter != mpt1->end(); iter++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter; + if (bg::relate(pt, *mls2, mask_T, point_strategy) + || bg::relate(pt, *mpy2, mask_T, point_strategy)) { + has_common_interior = true; + } + } + typename GcTreeType::sub_mpt_type::iterator iter2 = mpt2->begin(); + for (; !has_common_interior && iter2 != mpt2->end(); iter2++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter2; + if (bg::relate(pt, *mls1, mask_T, point_strategy)) { + has_common_interior = true; + } + } + bg::strategy::intersection::geographic_segments<> nonpoint_strategy(geog_sphere); + if (!has_common_interior) { + has_common_interior = bg::relate(*mls1, *mls2, mask_T, nonpoint_strategy) + || bg::relate(*mls1, *mpy2, mask_T, nonpoint_strategy); + } + } + } + return ret; + } + + // assume that g1 g2 both collection + template + static int eval_crosses_gc_gc(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObGeoFuncResWithNull &result) + { + int ret = OB_SUCCESS; + const ObSrsItem *srs = context.get_srs(); + if (g1->type() != ObGeoType::GEOMETRYCOLLECTION + || g2->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("input geometry should be GEOMETRYCOLLECTION", K(ret), K(g1->type()), K(g2->type())); + } else if (g1->crs() == ObGeoCRS::Geographic && OB_ISNULL(srs)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret)); + } else { + result.bret = false; + typename GcTreeType::sub_mpt_type *mpt1 = NULL; + typename GcTreeType::sub_ml_type *mls1 = NULL; + typename GcTreeType::sub_mp_type *mpy1 = NULL; + ObGeometry *geo1 = const_cast(g1); + ObIAllocator *allocator = context.get_allocator(); + ObGeoToTreeVisitor tree_visitor(allocator); + if (OB_FAIL(geo1->do_visit(tree_visitor))) { + LOG_WARN("failed to transform gc to tree", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_split(*allocator, + *static_cast(tree_visitor.get_geometry()), + mpt1, mls1, mpy1))) { + LOG_WARN("failed to do gc split", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else if (!mpy1->empty()) { + result.is_null = true; + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_union(*allocator, *srs, mpt1, mls1, mpy1))) { + LOG_WARN("failed to do gc union", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection union", K(ret)); + } else { + typename GcTreeType::sub_mpt_type *mpt2 = NULL; + typename GcTreeType::sub_ml_type *mls2 = NULL; + typename GcTreeType::sub_mp_type *mpy2 = NULL; + ObGeometry *geo2 = const_cast(g2); + bool has_common_interior = false; // Check that if g1 and g2 has common interior + ObGeoToTreeVisitor tree_visitor2(allocator); + if (OB_FAIL(geo2->do_visit(tree_visitor2))) { + LOG_WARN("failed to transform gc to tree", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_split(*allocator, + *static_cast(tree_visitor2.get_geometry()), + mpt2, mls2, mpy2))) { + LOG_WARN("failed to do gc split", K(ret)); + } else if (!mpt2->is_empty() && mls2->is_empty() && mpy2->is_empty()) { + // MySQL return NULL, PG return false + result.is_null = true; + } else if (OB_ISNULL(mpt2) || OB_ISNULL(mls2) || OB_ISNULL(mpy2)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_union(*allocator, *srs, mpt2, mls2, mpy2))) { + LOG_WARN("failed to do gc union", K(ret)); + } else if (OB_ISNULL(mpt2) || OB_ISNULL(mls2) || OB_ISNULL(mpy2)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection union", K(ret)); + } else if (OB_FAIL((has_common_interior_gc_gc( + mpt1, mls1, mpy1, mpt2, mls2, mpy2, context, has_common_interior)))) { + LOG_WARN("fail to eval is part joint", K(ret)); + } else if (!has_common_interior) { + result.bret = false; + } else { + // Check that if g1 has at least one point in g2's exterior + if (OB_FAIL((is_part_difference_gc_gc( + mpt1, mls1, mpt2, mls2, mpy2, context, result.bret)))) { + LOG_WARN("fail to eval is part crosses", K(ret)); + } + } + } + } + return ret; + } + + template + static int make_collection(const ObGeometry *g, ObIAllocator *allocator, const ObGeometry *&geo) + { + int ret = OB_SUCCESS; + GcBinType *gc_bin = OB_NEWx(GcBinType, allocator); + ObWkbBuffer buffer(*allocator); + if (OB_ISNULL(gc_bin)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry", K(ret)); + } else if (OB_FAIL(buffer.append(static_cast(ObGeoWkbByteOrder::LittleEndian)))) { + LOG_WARN("fail to append byte order to buffer", K(ret)); + } else if (OB_FAIL(buffer.append(static_cast(ObGeoType::GEOMETRYCOLLECTION)))) { + LOG_WARN("fail to append type to buffer", K(ret)); + } else if (OB_FAIL(buffer.append(static_cast(1)))) { + LOG_WARN("fail to append geo num to buffer", K(ret)); + } else if (OB_FAIL(buffer.append(g->val(), g->length()))) { + LOG_WARN("fail to append geo num to buffer", K(ret)); + } else { + gc_bin->set_data(buffer.string()); + geo = gc_bin; + } + return ret; + } + + template + static int eval_crosses_gc(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObGeoFuncResWithNull &result) + { + int ret = OB_SUCCESS; + const ObGeometry *gc1 = nullptr; + const ObGeometry *gc2 = nullptr; + if (g1->type() == ObGeoType::GEOMETRYCOLLECTION + && g2->type() == ObGeoType::GEOMETRYCOLLECTION) { + gc1 = g1; + gc2 = g2; + } else if (g1->type() == ObGeoType::GEOMETRYCOLLECTION) { + gc1 = g1; + if (OB_FAIL((make_collection(g2, context.get_allocator(), gc2)))) { + LOG_WARN("fail to make collection", K(ret)); + } + } else if (g2->type() == ObGeoType::GEOMETRYCOLLECTION) { + gc2 = g2; + if (OB_FAIL((make_collection(g1, context.get_allocator(), gc1)))) { + LOG_WARN("fail to make collection", K(ret)); + } + } else { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("At least one of g1 and g2 is collection", K(ret), K(g1->type()), K(g2->type())); + } + if (OB_SUCC(ret) && OB_FAIL((eval_crosses_gc_gc(gc1, gc2, context, result)))) { + LOG_WARN("fail to do eval_crosses_gc_gc", K(ret)); + } + return ret; + } +}; + +//===========BIN GEOM========== +/*Point*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomPoint, ObWkbGeomLineString, ObGeoFuncResWithNull) +{ + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomPoint, ObWkbGeomPolygon, ObGeoFuncResWithNull) +{ + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomPoint, ObWkbGeomMultiLineString, ObGeoFuncResWithNull) +{ + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomPoint, ObWkbGeomMultiPolygon, ObGeoFuncResWithNull) +{ + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +/*Linestring*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomLineString, ObWkbGeomLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_crosses_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomLineString, ObWkbGeomPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_crosses_without_strategy(g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomLineString, ObWkbGeomMultiLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_crosses_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomLineString, ObWkbGeomMultiPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_crosses_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +/*Polygon*/ +// return null + +/*MultiPoint*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomMultiPoint, ObWkbGeomLineString, ObGeoFuncResWithNull) +{ + return eval_crosses_mpt( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomMultiPoint, ObWkbGeomPolygon, ObGeoFuncResWithNull) +{ + return eval_crosses_mpt( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiLineString, ObGeoFuncResWithNull) +{ + return eval_crosses_mpt( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPolygon, ObGeoFuncResWithNull) +{ + return eval_crosses_mpt( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiLineString*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomMultiLineString, ObWkbGeomLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_crosses_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomMultiLineString, ObWkbGeomPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_crosses_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_crosses_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_crosses_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiPolygon*/ +// return null + +/*Collection*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeomCollection, ObWkbGeomCollection, ObGeoFuncResWithNull) +{ + return eval_crosses_gc( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncCrossesImpl, ObWkbGeomCollection, ObGeoFuncResWithNull) +{ + return eval_crosses_gc( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncCrossesImpl, ObWkbGeomCollection, ObGeoFuncResWithNull) +{ + return eval_crosses_gc( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +//===========BIN GEOG========== +/*Point*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogPoint, ObWkbGeogLineString, ObGeoFuncResWithNull) +{ + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogPoint, ObWkbGeogPolygon, ObGeoFuncResWithNull) +{ + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogPoint, ObWkbGeogMultiLineString, ObGeoFuncResWithNull) +{ + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogPoint, ObWkbGeogMultiPolygon, ObGeoFuncResWithNull) +{ + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +/*Linestring*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogLineString, ObWkbGeogLineString, ObGeoFuncResWithNull) +{ + return eval_crosses_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogLineString, ObWkbGeogPolygon, ObGeoFuncResWithNull) +{ + return eval_crosses_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogLineString, ObWkbGeogMultiLineString, ObGeoFuncResWithNull) +{ + return eval_crosses_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogLineString, ObWkbGeogMultiPolygon, ObGeoFuncResWithNull) +{ + return eval_crosses_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +/*Polygon*/ +// return null + +/*MultiPoint*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogMultiPoint, ObWkbGeogLineString, ObGeoFuncResWithNull) +{ + return eval_crosses_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogMultiPoint, ObWkbGeogPolygon, ObGeoFuncResWithNull) +{ + return eval_crosses_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiLineString, ObGeoFuncResWithNull) +{ + return eval_crosses_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPolygon, ObGeoFuncResWithNull) +{ + return eval_crosses_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiLineString*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogMultiLineString, ObWkbGeogLineString, ObGeoFuncResWithNull) +{ + return eval_crosses_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogMultiLineString, ObWkbGeogPolygon, ObGeoFuncResWithNull) +{ + return eval_crosses_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiLineString, ObGeoFuncResWithNull) +{ + return eval_crosses_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiPolygon, ObGeoFuncResWithNull) +{ + return eval_crosses_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiPolygon*/ +// return null + +/*Collection*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncCrossesImpl, ObWkbGeogCollection, ObWkbGeogCollection, ObGeoFuncResWithNull) +{ + return eval_crosses_gc( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncCrossesImpl, ObWkbGeogCollection, ObGeoFuncResWithNull) +{ + return eval_crosses_gc( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncCrossesImpl, ObWkbGeogCollection, ObGeoFuncResWithNull) +{ + return eval_crosses_gc( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +int ObGeoFuncCrosses::eval(const ObGeoEvalCtx &gis_context, ObGeoFuncResWithNull &result) +{ + return ObGeoFuncCrossesImpl::eval_geo_func(gis_context, result); +} +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_crosses.h b/deps/oblib/src/lib/geo/ob_geo_func_crosses.h new file mode 100644 index 0000000000..2ecf5420d5 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_crosses.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_crosses. + */ + +#ifndef OCEANBASE_LIB_OB_GEO_FUNC_CROSSES_ +#define OCEANBASE_LIB_OB_GEO_FUNC_CROSSES_ + +#include "lib/geo/ob_geo_func_common.h" + +namespace oceanbase +{ +namespace common +{ +class ObGeoFuncCrosses +{ +public: + ObGeoFuncCrosses(); + virtual ~ObGeoFuncCrosses() = default; + static int eval(const common::ObGeoEvalCtx &gis_context, ObGeoFuncResWithNull &result); +}; + +} // namespace common +} // namespace oceanbase +#endif // OCEANBASE_LIB_OB_GEO_FUNC_CROSSES_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_difference.cpp b/deps/oblib/src/lib/geo/ob_geo_func_difference.cpp index 8609dcaee4..75dc112bf2 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_difference.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_difference.cpp @@ -18,6 +18,8 @@ #include "lib/geo/ob_geo_tree.h" #include "lib/geo/ob_geo_to_tree_visitor.h" #include "lib/oblog/ob_log_module.h" +#include "lib/geo/ob_geo_func_utils.h" +#include "lib/geo/ob_geo_wkb_size_visitor.h" using namespace oceanbase::common; namespace oceanbase @@ -25,13 +27,16 @@ namespace oceanbase namespace common { -template -static int apply_bg_difference(const ObGeometry *g1, const ObGeometry *g2, - const ObGeoEvalCtx &context, ObGeometry *&result) +template +static int apply_bg_difference( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) { INIT_SUCC(ret); - GeometryRes *res = OB_NEWx(GeometryRes, context.get_allocator()); + GeometryRes *res = OB_NEWx(GeometryRes, + context.get_allocator(), + g1->get_srid(), + *context.get_allocator()); if (OB_ISNULL(res)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -45,18 +50,25 @@ static int apply_bg_difference(const ObGeometry *g1, const ObGeometry *g2, geo1 = reinterpret_cast(g1->val()); geo2 = reinterpret_cast(g2->val()); } - boost::geometry::difference(*geo1, *geo2, *res); - result = res; + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("wrong geometry type", K(ret)); + } else { + boost::geometry::difference(*geo1, *geo2, *res); + result = res; + } } return ret; } -template -static int apply_bg_difference_ll_strategy(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) +template +static int apply_bg_difference_ll_strategy( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) { INIT_SUCC(ret); const ObSrsItem *srs = context.get_srs(); - GeometryRes *res = OB_NEWx(GeometryRes, context.get_allocator()); + GeometryRes *res = + OB_NEWx(GeometryRes, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(srs)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("srs is null", K(ret)); @@ -64,7 +76,8 @@ static int apply_bg_difference_ll_strategy(const ObGeometry *g1, const ObGeometr ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); } else { - boost::geometry::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + boost::geometry::srs::spheroid geog_sphere( + srs->semi_major_axis(), srs->semi_minor_axis()); ObLlLaAaStrategy line_strategy(geog_sphere); const GeoType1 *geo1 = NULL; const GeoType2 *geo2 = NULL; @@ -75,18 +88,25 @@ static int apply_bg_difference_ll_strategy(const ObGeometry *g1, const ObGeometr geo1 = reinterpret_cast(g1->val()); geo2 = reinterpret_cast(g2->val()); } - boost::geometry::difference(*geo1, *geo2, *res, line_strategy); - result = res; + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("wrong geometry type", K(ret)); + } else { + boost::geometry::difference(*geo1, *geo2, *res, line_strategy); + result = res; + } } return ret; } -template -static int apply_bg_difference_pl_strategy(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) +template +static int apply_bg_difference_pl_strategy( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) { INIT_SUCC(ret); const ObSrsItem *srs = context.get_srs(); - GeometryRes *res = OB_NEWx(GeometryRes, context.get_allocator()); + GeometryRes *res = + OB_NEWx(GeometryRes, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(srs)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("srs is null", K(ret)); @@ -94,7 +114,8 @@ static int apply_bg_difference_pl_strategy(const ObGeometry *g1, const ObGeometr ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); } else { - boost::geometry::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + boost::geometry::srs::spheroid geog_sphere( + srs->semi_major_axis(), srs->semi_minor_axis()); ObPlPaStrategy point_strategy(geog_sphere); const GeoType1 *geo1 = NULL; const GeoType2 *geo2 = NULL; @@ -105,24 +126,14 @@ static int apply_bg_difference_pl_strategy(const ObGeometry *g1, const ObGeometr geo1 = reinterpret_cast(g1->val()); geo2 = reinterpret_cast(g2->val()); } - boost::geometry::difference(*geo1, *geo2, *res, point_strategy); - result = res; - } - return ret; -} -template -static int apply_bg_to_tree(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) -{ - INIT_SUCC(ret); - // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) - // so just convert g1 to tree - ObGeoToTreeVisitor geom_visitor(context.get_allocator()); - GeometryType *geo1 = const_cast(reinterpret_cast(g1)); - if (OB_FAIL(geo1->do_visit(geom_visitor))) { - LOG_WARN("failed to convert bin to tree", K(ret)); - } else { - result = geom_visitor.get_geometry(); + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("wrong geometry type", K(ret)); + } else { + boost::geometry::difference(*geo1, *geo2, *res, point_strategy); + result = res; + } } return ret; } @@ -138,518 +149,1201 @@ public: OB_GEO_CART_TREE_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS); OB_GEO_GEOG_TREE_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); - template + template struct EvalWkbBi { - static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) + static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, + ObGeometry *&result) { UNUSEDx(g1, g2, context, result); return OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS; } }; - template + template struct EvalWkbBiGeog { - static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) + static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, + ObGeometry *&result) { UNUSEDx(g1, g2, context, result); return OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS; } }; +private: + // g1: collection + template + static int apply_bg_difference_collection(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObGeometry *&result) + { + INIT_SUCC(ret); + CollType *res = OB_NEWx(CollType, context.get_allocator()); + MptType *mpt = NULL; + MlsType *mls = NULL; + MpyType *mpy = NULL; + // prepare data + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memotry for collection", K(ret)); + } else if (g1->is_empty()) { + // do nothing + } else { + const CollType *coll_tree = reinterpret_cast(g1); + if (OB_ISNULL(coll_tree)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("failed to convert to geo tree", K(ret), KP(coll_tree)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_split(*context.get_allocator(), *coll_tree, mpt, mls, mpy))) { + LOG_WARN("failed to do geometry collection split", K(ret)); + } else if (OB_ISNULL(mpt) || OB_ISNULL(mls) || OB_ISNULL(mpy)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret), KP(mpt), KP(mls), KP(mpy)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_union(*context.get_allocator(), *context.get_srs(), mpt, mls, mpy))) { + LOG_WARN("failed to do geometry collection union", K(ret)); + } else if (OB_ISNULL(mpt) || OB_ISNULL(mls) || OB_ISNULL(mpy)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection union", K(ret), KP(mpt), KP(mls), KP(mpy)); + } + + // do difference + if (OB_SUCC(ret) && !mpy->is_empty()) { + ObGeometry *mpy_res = NULL; + if (OB_FAIL(eval_tree_binary(mpy, g2, context, mpy_res))) { + LOG_WARN("fail to eval difference function", K(ret)); + } else if (mpy_res->type() == ObGeoType::POLYGON) { + if (OB_FAIL(res->push_back(*mpy_res))) { + LOG_WARN("fail to push geometry into result", K(ret)); + } + } else { + MpyType *mpy_res_tree = reinterpret_cast(mpy_res); + typename MpyType::iterator iter = mpy_res_tree->begin(); + for (; OB_SUCC(ret) && iter != mpy_res_tree->end(); iter++) { + if (OB_FAIL(res->push_back(*iter))) { + LOG_WARN("fail to push geometry into result", K(ret)); + } + } + } + } + if (OB_SUCC(ret) && !mls->is_empty()) { + ObGeometry *mls_res = NULL; + if (OB_FAIL(eval_tree_binary(mls, g2, context, mls_res))) { + LOG_WARN("fail to eval difference function", K(ret)); + } else if (mls_res->type() == ObGeoType::LINESTRING) { + if (OB_FAIL(res->push_back(*mls_res))) { + LOG_WARN("fail to push geometry into result", K(ret)); + } + } else { + MlsType *mls_res_tree = reinterpret_cast(mls_res); + typename MlsType::iterator iter = mls_res_tree->begin(); + for (; OB_SUCC(ret) && iter != mls_res_tree->end(); iter++) { + if (OB_FAIL(res->push_back(*iter))) { + LOG_WARN("fail to push geometry into result", K(ret)); + } + } + } + } + if (OB_SUCC(ret) && !mpt->is_empty()) { + ObGeometry *mpt_res = NULL; + if (OB_FAIL(eval_tree_binary(mpt, g2, context, mpt_res))) { + LOG_WARN("fail to eval difference function", K(ret)); + } else if (mpt_res->type() == ObGeoType::LINESTRING) { + if (OB_FAIL(res->push_back(*mpt_res))) { + LOG_WARN("fail to push geometry into result", K(ret)); + } + } else { + MptType *mpt_res_tree = reinterpret_cast(mpt_res); + typename MptType::iterator iter = mpt_res_tree->begin(); + for (; OB_SUCC(ret) && iter != mpt_res_tree->end(); iter++) { + typename CollType::sub_pt_type *pt = OB_NEWx(typename CollType::sub_pt_type, context.get_allocator()); + if (OB_ISNULL(pt)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memotry for point", K(ret)); + } else { + pt->set_data(*iter); + if (OB_FAIL(res->push_back(*pt))) { + LOG_WARN("fail to push geometry into result", K(ret)); + } + } + } + } + } + } + + if (OB_SUCC(ret)) { + result = res->size() == 1 ? (&res->front()) : res; + } + return ret; + } +private: + // assume that g1 g2 both collection + template + static int eval_difference_gc_gc( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) + { + int ret = OB_SUCCESS; + ObIAllocator *allocator = context.get_allocator(); + result = nullptr; + if (g1->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("input geometry should be GEOMETRYCOLLECTION", K(ret), K(g1->type()), K(g2->type())); + } else { + typename GcTreeType::sub_mpt_type *mpt1 = NULL; + typename GcTreeType::sub_ml_type *mls1 = NULL; + typename GcTreeType::sub_mp_type *mpy1 = NULL; + ObGeometry *geo1 = const_cast(g1); + GcTreeType *res_coll = + OB_NEWx(GcTreeType, allocator, g1->get_srid(), *allocator); + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo1, mpt1, mls1, mpy1))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1) || OB_ISNULL(res_coll)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("unexpected null geometry collection split", K(ret), K(mpt1), K(mls1), K(mpy1), K(res_coll)); + } else { + bool mpy_empty = mpy1->is_empty(); + bool mls_empty = mls1->is_empty(); + bool mpt_empty = mpt1->is_empty(); + const ObSrsItem *srs = context.get_srs(); + if (!mpy_empty) { + ObGeometry *mpy_bin = nullptr; + ObGeometry *mpy_result = nullptr; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(*allocator, mpy1, mpy_bin, srs))) { + LOG_WARN("fail to transform tree to binary", K(ret)); + } else if (OB_FAIL(eval_wkb_binary(mpy_bin, g2, context, mpy_result))) { + LOG_WARN("fail to eval difference with collection", K(ret)); + } else if (!mpy_result->is_empty()) { + if (mpy_result->type() == ObGeoType::POLYGON) { + if (OB_FAIL(res_coll->push_back(*mpy_result))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } else if (mls_empty && mpt_empty) { + result = mpy_result; + } else { + typename GcTreeType::sub_mp_type &mpy_res = + *reinterpret_cast(mpy_result); + for (int i = 0; OB_SUCC(ret) && i < mpy_res.size(); ++i) { + if (OB_FAIL( + res_coll->push_back(reinterpret_cast(mpy_res[i])))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + } + } + if (OB_SUCC(ret) && !mls_empty) { + ObGeometry *mls_bin = nullptr; + ObGeometry *mls_result = nullptr; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(*allocator, mls1, mls_bin, srs))) { + LOG_WARN("fail to transform tree to binary", K(ret)); + } else if (OB_FAIL(eval_wkb_binary(mls_bin, g2, context, mls_result))) { + LOG_WARN("fail to eval difference with collection", K(ret)); + } else if (!mls_result->is_empty()) { + if (mls_result->type() == ObGeoType::LINESTRING) { + if (OB_FAIL(res_coll->push_back(*mls_result))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } else if (mpy_empty && mpt_empty) { + result = mls_result; + } else { + typename GcTreeType::sub_ml_type &mls_res = + *reinterpret_cast(mls_result); + for (int i = 0; OB_SUCC(ret) && i < mls_res.size(); ++i) { + if (OB_FAIL( + res_coll->push_back(reinterpret_cast(mls_res[i])))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + } + } + if (OB_SUCC(ret) && !mpt_empty) { + ObGeometry *mpt_bin = nullptr; + ObGeometry *mpt_result = nullptr; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(*allocator, mpt1, mpt_bin, srs))) { + LOG_WARN("fail to transform tree to binary", K(ret)); + } else if (OB_FAIL(eval_wkb_binary(mpt_bin, g2, context, mpt_result))) { + LOG_WARN("fail to eval difference with collection", K(ret)); + } else if (!mpt_result->is_empty()) { + if (mpt_result->type() == ObGeoType::POINT) { + if (OB_FAIL(res_coll->push_back(*mpt_result))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } else if (mpy_empty && mls_empty) { + result = mpt_result; + } else { + typename GcTreeType::sub_mpt_type &mpt_res = + *reinterpret_cast(mpt_result); + for (int i = 0; OB_SUCC(ret) && i < mpt_res.size(); ++i) { + typename GcTreeType::sub_mpt_type::value_type &pt = mpt_res[i]; + typename GcTreeType::sub_pt_type *pt_tree = OB_NEWx( + typename GcTreeType::sub_pt_type, + allocator, + pt.template get<0>(), + pt.template get<1>(), + g1->get_srid(), + allocator); + if (OB_ISNULL(pt_tree)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret)); + } else if (OB_FAIL(res_coll->push_back( + reinterpret_cast(*pt_tree)))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + } + } + if (OB_SUCC(ret) && OB_ISNULL(result)) { + result = res_coll->size() == 1 ? *(res_coll->begin()) : res_coll; + } + } + } + return ret; + } + + static int create_multi_type(ObIAllocator &allocator, const ObGeometry *g, ObGeometry *&res) + { + int ret = OB_SUCCESS; + if ((g->type() == ObGeoType::MULTIPOINT) || (g->type() == ObGeoType::MULTILINESTRING) + || (g->type() == ObGeoType::MULTIPOLYGON)) { + res = const_cast(g); + } else { + ObWkbBuffer buffer(allocator); + const uint32_t GEO_NUM = 1; + uint32_t multi_type_num = static_cast(g->type()) + static_cast(3); + if (OB_FAIL(buffer.reserve(g->length() + WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("fail to reserver memory", K(ret), K(g->length())); + } else if (OB_FAIL(buffer.append(static_cast(ObGeoWkbByteOrder::LittleEndian)))) { + LOG_WARN("fail to append buffer", K(ret)); + } else if (OB_FAIL(buffer.append(multi_type_num))) { + LOG_WARN("fail to append buffer", K(ret), K(multi_type_num)); + } else if (OB_FAIL(buffer.append(GEO_NUM))) { + LOG_WARN("fail to append buffer", K(ret), K(GEO_NUM)); + } else if (OB_FAIL(buffer.append(g->val(), g->length()))) { + LOG_WARN("fail to append buffer", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_type(allocator, static_cast(multi_type_num), + g->crs() == ObGeoCRS::Geographic, true, res, g->get_srid()))) { + LOG_WARN("failed to create wkb", K(ret)); + } else { + res->set_data(buffer.string()); + } + } + + return ret; + } + + template + static int eval_difference_gc_other( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) + { + int ret = OB_SUCCESS; + ObIAllocator *allocator = context.get_allocator(); + if (g1->type() != ObGeoType::GEOMETRYCOLLECTION + && g2->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("At least one of g1 and g2 is collection", K(ret), K(g1->type()), K(g2->type())); + } else if (g1->type() == ObGeoType::GEOMETRYCOLLECTION) { + if (OB_FAIL( + (eval_difference_gc_gc(g1, g2, context, result)))) { + LOG_WARN("fail to eval difference with geometrycollection", K(ret)); + } + } else { + bool is_g2_empty = false; + if (g2->is_empty()) { + if (OB_FAIL(ObGeoFuncUtils::apply_bg_to_tree(g1, context, result))) { + LOG_WARN("fail to apply g1 to tree", K(ret)); + } + } else { + // g2 is not empty collection + const GcBinType *geo2 = reinterpret_cast(g2->val()); + typename GcBinType::iterator iter = geo2->begin(); + ObGeometry *tmp_result = nullptr; + bool is_geog = (g2->crs() == oceanbase::common::ObGeoCRS::Geographic); + if (OB_FAIL(create_multi_type(*allocator, g1, tmp_result))) { + LOG_WARN("failt to create multi type", K(ret)); + } + while (OB_SUCC(ret) && iter != geo2->end()) { + typename GcBinType::const_pointer sub_ptr = iter.operator->(); + ObGeoType sub_type = geo2->get_sub_type(sub_ptr); + ObGeometry *sub_g2 = NULL; + if (OB_FAIL( + ObGeoTypeUtil::create_geo_by_type(*allocator, sub_type, is_geog, true, sub_g2))) { + LOG_WARN("failed to create wkb", K(ret), K(sub_type)); + } else { + // Length is not used, cannot get real length untill iter move to the next + ObString wkb_nosrid(WKB_COMMON_WKB_HEADER_LEN, reinterpret_cast(sub_ptr)); + sub_g2->set_data(wkb_nosrid); + sub_g2->set_srid(g2->get_srid()); + ObGeometry *geo_bin = nullptr; + const ObSrsItem *srs = context.get_srs(); + if (OB_FAIL(eval_wkb_binary(tmp_result, sub_g2, context, result))) { + LOG_WARN("fail to do eval", K(ret)); + } else if (FALSE_IT(iter++)) { + } else if (iter != geo2->end()) { + if (OB_FAIL((ObGeoFuncUtils::simplify_multi_geo(result, *allocator)))) { + // should not do simplify in difference functor, it may affect + // ObGeoFuncUtils::ob_geo_gc_union + LOG_WARN("fail to simplify result", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(*allocator, result, geo_bin, srs))) { + LOG_WARN("fail to transform tree to binary", K(ret)); + } else { + tmp_result = geo_bin; + allocator->free(result); + result = nullptr; + } + } + } + } + } + } + return ret; + } }; OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomPoint, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomLineString, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomMultiPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomMultiPoint, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomMultiLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomMultiLineString, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomMultiPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPoint, ObWkbGeomMultiPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; // cartisian linestring -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomLineString, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomMultiPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomMultiPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomMultiLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomMultiLineString, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomMultiPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomLineString, ObWkbGeomMultiPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; // cartisian polygon -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomLineString, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomMultiPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomMultiPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomMultiLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomMultiLineString, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomMultiPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomMultiPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; // cartisian multipoint -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomPoint, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomLineString, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPoint, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiLineString, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; // cartisian mutilinestring -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomLineString, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiLineString, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; // cartisian multipolygon -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomLineString, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiPoint, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiLineString, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiLineString, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiPolygon, ObGeometry *) +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// cartesian geometry collection +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeomCollection, ObWkbGeomCollection, ObGeometry *) +{ + return eval_difference_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomCollection, ObGeometry *) +{ + return eval_difference_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeomCollection, ObGeometry *) +{ + return eval_difference_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; // geographic point OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogPoint, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogLineString, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogPolygon, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogMultiPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogMultiPoint, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogMultiLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogMultiLineString, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogMultiPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPoint, ObWkbGeogMultiPolygon, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; // geographic linestring -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogLineString, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogPolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogMultiPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogMultiPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogMultiLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogMultiLineString, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogMultiPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogLineString, ObWkbGeogMultiPolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; // gepgraphic polygon -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogLineString, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogPolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogMultiPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogMultiPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogMultiLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogMultiLineString, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogMultiPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogMultiPolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; // geographic multipoint -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogPoint, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogLineString, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogPolygon, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPoint, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiLineString, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPolygon, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; // geographic multilinestring -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogLineString, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogPolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiLineString, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiPolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; // geographic mutlipolygon -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogLineString, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogPolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiPoint, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiPoint, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiLineString, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiLineString, ObGeometry *) { // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) // so just convert g1 to tree - return apply_bg_to_tree(g1, g2, context, result); -} OB_GEO_FUNC_END; + return ObGeoFuncUtils::apply_bg_to_tree(g1, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiPolygon, ObGeometry *) +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiPolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianMultipoint, ObCartesianMultipoint, ObGeometry *) +// cartesian geometry collection +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObWkbGeogCollection, ObWkbGeogCollection, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); -} OB_GEO_FUNC_END; + return eval_difference_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogCollection, ObGeometry *) +{ + return eval_difference_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncDifferenceImpl, ObWkbGeogCollection, ObGeometry *) +{ + return eval_difference_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObCartesianMultipoint, ObCartesianMultipoint, ObGeometry *) +{ + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; // tree cartesian polygon -OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianMultipoint, ObCartesianMultilinestring, ObGeometry *) +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObCartesianMultipoint, ObCartesianMultilinestring, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianPolygon, ObCartesianPolygon, ObGeometry *) +{ + return apply_bg_difference(g1, g2, context, result); } OB_GEO_FUNC_END; -OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianMultipoint, ObCartesianMultipolygon, ObGeometry *) +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianPolygon, ObCartesianMultipolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); + return apply_bg_difference(g1, g2, context, result); } OB_GEO_FUNC_END; -OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianLineString, ObCartesianMultilinestring, ObGeometry *) +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianMultipolygon, ObCartesianPolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); + return apply_bg_difference(g1, g2, context, result); } OB_GEO_FUNC_END; -OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianMultilinestring, ObCartesianMultilinestring, ObGeometry *) +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObCartesianMultipoint, ObCartesianMultipolygon, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObCartesianLineString, ObCartesianMultilinestring, ObGeometry *) +{ + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObCartesianMultilinestring, ObCartesianMultilinestring, ObGeometry *) +{ + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObCartesianMultilinestring, ObCartesianMultipolygon, ObGeometry *) +{ + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianPoint, ObCartesianMultilinestring, ObGeometry *) +{ + return apply_bg_difference(g1, g2, context, result); } OB_GEO_FUNC_END; -OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianMultilinestring, ObCartesianMultipolygon, ObGeometry *) +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianPolygon, ObCartesianMultilinestring, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); + // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) + // so just return g1 + result = const_cast(reinterpret_cast(g1)); + return OB_SUCCESS; } OB_GEO_FUNC_END; -OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianMultipolygon, ObCartesianMultipolygon, ObGeometry *) +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianMultipolygon, ObCartesianMultilinestring, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); + // if g1.dimension > g2.dimension, g1 - g2 is equal g1(mysql/postgis) + // so just return g1 + result = const_cast(reinterpret_cast(g1)); + return OB_SUCCESS; } OB_GEO_FUNC_END; -OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObGeographMultipoint, ObGeographMultipoint, ObGeometry *) +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObCartesianGeometrycollection, ObCartesianMultilinestring, ObGeometry *) { - return apply_bg_difference(g1, g2, context, result); + return apply_bg_difference_collection(g1, g2, context, result); } OB_GEO_FUNC_END; +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObCartesianMultipolygon, ObCartesianMultipolygon, ObGeometry *) +{ + return apply_bg_difference(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObGeographMultipoint, ObGeographMultipoint, ObGeometry *) +{ + return apply_bg_difference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + // tree geograph polygon -OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObGeographMultipoint, ObGeographMultilinestring, ObGeometry *) +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObGeographMultipoint, ObGeographMultilinestring, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObGeographMultipoint, ObGeographMultipolygon, ObGeometry *) +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObGeographMultipoint, ObGeographMultipolygon, ObGeometry *) { - return apply_bg_difference_pl_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_pl_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObGeographLineString, ObGeographMultilinestring, ObGeometry *) +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObGeographLineString, ObGeographMultilinestring, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObGeographMultilinestring, ObGeographMultilinestring, ObGeometry *) +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObGeographMultilinestring, ObGeographMultilinestring, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObGeographMultilinestring, ObGeographMultipolygon, ObGeometry *) +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObGeographMultilinestring, ObGeographMultipolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; -OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncDifferenceImpl, ObGeographMultipolygon, ObGeographMultipolygon, ObGeometry *) +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncDifferenceImpl, ObGeographMultipolygon, ObGeographMultipolygon, ObGeometry *) { - return apply_bg_difference_ll_strategy(g1, g2, context, result); -} OB_GEO_FUNC_END; + return apply_bg_difference_ll_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; // implement of outer class eval // use an outer class to void implement templates in header files @@ -658,5 +1352,5 @@ int ObGeoFuncDifference::eval(const ObGeoEvalCtx &gis_context, ObGeometry *&resu return ObGeoFuncDifferenceImpl::eval_geo_func(gis_context, result); } -} // sql -} // oceanbase +} // namespace common +} // namespace oceanbase diff --git a/deps/oblib/src/lib/geo/ob_geo_func_dissolve_polygon.cpp b/deps/oblib/src/lib/geo/ob_geo_func_dissolve_polygon.cpp new file mode 100644 index 0000000000..b5d071bf79 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_dissolve_polygon.cpp @@ -0,0 +1,178 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_dissolve_polygon. + */ + +#define USING_LOG_PREFIX LIB + +#include "lib/geo/ob_geo_dispatcher.h" +#include "lib/geo/ob_geo_func_dissolve_polygon.h" +#include "lib/geo/ob_geo_func_disjoint.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_func_utils.h" + +using namespace oceanbase::common; +namespace oceanbase +{ +namespace common +{ +namespace bg = boost::geometry; +template +static int eval_dissolve_polygon( + const ObGeometry *g1, const ObGeoEvalCtx &context, ObGeometry *&result) +{ + int ret = OB_SUCCESS; + + GeometryType *geo1 = nullptr; + if (!g1->is_tree()) { + geo1 = reinterpret_cast(const_cast(g1->val())); + } else { + geo1 = reinterpret_cast(const_cast(g1)); + } + if (OB_ISNULL(geo1)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create go by type", K(ret), K(geo1)); + } else { + bool is_valid = bg::is_valid(*geo1); + if (!is_valid) { + bool is_self_intersects = bg::intersects(*geo1); + MPY *res = OB_NEWx(MPY, context.get_allocator(), g1->get_srid(), *context.get_allocator()); + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create go by type", K(ret), K(res)); + } else if (is_self_intersects) { + MPY *left_part = + OB_NEWx(MPY, context.get_allocator(), g1->get_srid(), *context.get_allocator()); + MPY *right_part = + OB_NEWx(MPY, context.get_allocator(), g1->get_srid(), *context.get_allocator()); + if (OB_ISNULL(res) || OB_ISNULL(left_part) || OB_ISNULL(right_part)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create go by type", K(ret), K(res), K(left_part), K(right_part)); + } else { + GeometryType *g1_rev = OB_NEWx(GeometryType, context.get_allocator(), *geo1); + if (OB_ISNULL(g1_rev)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create go by type", K(ret)); + } else { + bg::reverse(*g1_rev); + bg::sym_difference(*geo1, *g1_rev, *res); + } + } + } else { + bg::intersection(*geo1, *geo1, *res); + if (res->is_empty() && !geo1->is_empty()) { + bg::reverse(*geo1); + bg::intersection(*geo1, *geo1, *res); + } + } + if (res->size() == 1) { + result = &res->front(); + } else { + result = res; + } + } else { + result = geo1; + } + } + return ret; +} + +template +static int eval_dissolve_multipolygon( + const ObGeometry *g1, const ObGeoEvalCtx &context, ObGeometry *&result) +{ + int ret = OB_SUCCESS; + GeometryType *geo1 = nullptr; + if (!g1->is_tree()) { + geo1 = reinterpret_cast(const_cast(g1->val())); + } else { + geo1 = reinterpret_cast(const_cast(g1)); + } + if (OB_ISNULL(geo1)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create go by type", K(ret), K(geo1)); + } else { + bool is_valid = bg::is_valid(*geo1); + if (!is_valid) { + bool is_self_intersects = bg::intersects(*geo1); + MPY *res = OB_NEWx(MPY, context.get_allocator(), g1->get_srid(), *context.get_allocator()); + if (OB_ISNULL(res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create go by type", K(ret), K(res)); + } else if (is_self_intersects) { + MPY *left_part = + OB_NEWx(MPY, context.get_allocator(), g1->get_srid(), *context.get_allocator()); + MPY *right_part = + OB_NEWx(MPY, context.get_allocator(), g1->get_srid(), *context.get_allocator()); + if (OB_ISNULL(res) || OB_ISNULL(left_part) || OB_ISNULL(right_part)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create go by type", K(ret), K(res), K(left_part), K(right_part)); + } else { + bg::intersection(*geo1, *geo1, *left_part); + bg::reverse(*geo1); + bg::intersection(*geo1, *geo1, *right_part); + bg::union_(*left_part, *right_part, *res); + } + } else { + bg::intersection(*geo1, *geo1, *res); + if (res->is_empty() && !geo1->is_empty()) { + bg::reverse(*geo1); + bg::intersection(*geo1, *geo1, *res); + } + } + if (OB_FAIL(ret)) { + } else if (res->size() == 1) { + result = &res->front(); + } else { + result = res; + } + } else { + result = geo1; + } + } + return ret; +} + +class ObGeoFuncDissolvePolygonImpl + : public ObIGeoDispatcher +{ +public: + ObGeoFuncDissolvePolygonImpl(); + virtual ~ObGeoFuncDissolvePolygonImpl() = default; + OB_GEO_UNARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + OB_GEO_TREE_UNARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + OB_GEO_CART_BINARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS); + OB_GEO_GEOG_BINARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + OB_GEO_CART_TREE_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS); + OB_GEO_GEOG_TREE_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); +}; + +OB_GEO_UNARY_TREE_FUNC_BEGIN(ObGeoFuncDissolvePolygonImpl, ObCartesianPolygon, ObGeometry *) +{ + return eval_dissolve_polygon(g, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_TREE_FUNC_BEGIN(ObGeoFuncDissolvePolygonImpl, ObCartesianMultipolygon, ObGeometry *) +{ + return eval_dissolve_multipolygon( + g, context, result); +} +OB_GEO_FUNC_END; + +int ObGeoFuncDissolvePolygon::eval( + const common::ObGeoEvalCtx &gis_context, common::ObGeometry *&result) +{ + return ObGeoFuncDissolvePolygonImpl::eval_geo_func(gis_context, result); +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_dissolve_polygon.h b/deps/oblib/src/lib/geo/ob_geo_func_dissolve_polygon.h new file mode 100644 index 0000000000..82642263cc --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_dissolve_polygon.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_dissolve_polygon. + */ + +#ifndef OCEANBASE_LIB_OB_GEO_FUNC_DISSOLVEPOLYGON_ +#define OCEANBASE_LIB_OB_GEO_FUNC_DISSOLVEPOLYGON_ + +#include "lib/geo/ob_geo_func_common.h" + +namespace oceanbase +{ +namespace common +{ + +class ObGeoFuncDissolvePolygon +{ +public: + ObGeoFuncDissolvePolygon(); + virtual ~ObGeoFuncDissolvePolygon() = default; + static int eval(const common::ObGeoEvalCtx &gis_context, common::ObGeometry *&result); +}; +} // sql +} // oceanbase +#endif // OCEANBASE_LIB_OB_GEO_FUNC_DISSOLVEPOLYGON_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_equals.cpp b/deps/oblib/src/lib/geo/ob_geo_func_equals.cpp new file mode 100644 index 0000000000..0d476beb48 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_equals.cpp @@ -0,0 +1,718 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_equals. + */ + +#define USING_LOG_PREFIX LIB + +#include "lib/geo/ob_geo_dispatcher.h" +#include "lib/geo/ob_geo_func_equals.h" +#include "lib/geo/ob_geo_func_disjoint.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_func_utils.h" + +using namespace oceanbase::common; +namespace oceanbase +{ +namespace common +{ +namespace bg = boost::geometry; +template +int eval_equals_without_strategy(const ObGeometry *g1, const ObGeometry *g2, bool &result) +{ + INIT_SUCC(ret); + const GeoType1 *geo1 = nullptr; + const GeoType2 *geo2 = nullptr; + if (g1->is_tree()) { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } else { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_INVALID_NULL_SDO_GEOMETRY; + LOG_WARN("input geomery is null", K(ret), K(geo1), K(geo2), K(g1->is_tree())); + } else { + result = bg::equals(*geo1, *geo2); + } + return OB_SUCCESS; +} + +template +int eval_equals_with_nonpoint_strategy( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) +{ + INIT_SUCC(ret); + const ObSrsItem *srs = context.get_srs(); + if (OB_ISNULL(srs)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret), K(g1->get_srid()), K(g1), K(g2)); + } else { + const GeoType1 *geo1 = nullptr; + const GeoType2 *geo2 = nullptr; + if (g1->is_tree()) { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } else { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_INVALID_NULL_SDO_GEOMETRY; + LOG_WARN("input geomery is null", K(ret), K(geo1), K(geo2), K(g1->is_tree())); + } else { + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::intersection::geographic_segments<> nonpoint_strategy(geog_sphere); + result = bg::equals(*geo1, *geo2, nonpoint_strategy); + } + } + return ret; +} + +// ----- ObGeoFuncEqualsImpl ----- +class ObGeoFuncEqualsImpl : public ObIGeoDispatcher +{ +public: + ObGeoFuncEqualsImpl(); + virtual ~ObGeoFuncEqualsImpl() = default; + + // template for unary + OB_GEO_UNARY_FUNC_DEFAULT(bool, OB_ERR_GIS_INVALID_DATA); + OB_GEO_TREE_UNARY_FUNC_DEFAULT(bool, OB_ERR_GIS_INVALID_DATA); + + // template for binary + // default cases for cartesian + template + struct EvalWkbBi + { + static int eval( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; + } + }; + + // default case for geography + template + struct EvalWkbBiGeog + { + static int eval( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; + } + }; + + // template for tree + template + struct EvalTreeBi + { + static int eval( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; + } + }; + + // default case for geography + template + struct EvalTreeBiGeog + { + static int eval( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; + } + }; +private: + // geometry collection + template + static int eval_equals_geometry_collection( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + int ret = OB_SUCCESS; + result = false; + if (g1->type() == ObGeoType::GEOMETRYCOLLECTION) { + bool is_g1_empty = false; + bool is_g2_empty = false; + if (OB_FAIL(ObGeoTypeUtil::check_empty(const_cast(g1), is_g1_empty))) { + LOG_WARN("fail to check is geometry empty", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::check_empty(const_cast(g2), is_g2_empty))) { + LOG_WARN("fail to check is geometry empty", K(ret)); + } else if (is_g1_empty || is_g2_empty) { + result = is_g1_empty && is_g2_empty; + } else { + typename GcTreeType::sub_mpt_type *mpt1 = NULL; + typename GcTreeType::sub_ml_type *mls1 = NULL; + typename GcTreeType::sub_mp_type *mpy1 = NULL; + ObGeometry *geo1 = const_cast(reinterpret_cast(g1)); + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo1, mpt1, mls1, mpy1))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else if (g2->type() == ObGeoType::GEOMETRYCOLLECTION) { + // both collection + typename GcTreeType::sub_mpt_type *mpt2 = NULL; + typename GcTreeType::sub_ml_type *mls2 = NULL; + typename GcTreeType::sub_mp_type *mpy2 = NULL; + ObGeometry *geo2 = const_cast(reinterpret_cast(g2)); + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo2, mpt2, mls2, mpy2))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt2) || OB_ISNULL(mls2) || OB_ISNULL(mpt2)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else if ((mpt1->is_empty() != mpt2->is_empty()) || (mls1->is_empty() != mls2->is_empty()) + || (mpy1->is_empty() != mpy2->is_empty())) { + result = false; + } else { + bool mpt_result = mpt1->is_empty() && mpt2->is_empty(); + if (!mpt_result && OB_FAIL(eval_tree_binary(mpt1, mpt2, context, mpt_result))) { + LOG_WARN("fail to do eval", K(ret), K(result)); + } else { + result = mpt_result; + } + if (OB_SUCC(ret) && result) { + bool mls_result = mls1->is_empty() && mls2->is_empty(); + if (!mls_result && OB_FAIL(eval_tree_binary(mls1, mls2, context, mls_result))) { + LOG_WARN("fail to do eval", K(ret), K(result)); + } else { + result = result && mls_result; + } + } + if (OB_SUCC(ret) && result) { + bool mpy_result = mpy1->is_empty() && mpy2->is_empty(); + if (!mpy_result && OB_FAIL(eval_tree_binary(mpy1, mpy2, context, mpy_result))) { + LOG_WARN("fail to do eval", K(ret), K(result)); + } else { + result = result && mpy_result; + } + } + } + } else { + switch (g2->type()) { + case ObGeoType::POINT: + case ObGeoType::MULTIPOINT: { + if (!mls1->is_empty() || !mpy1->is_empty()) { + result = false; + } else { + ObGeometry *mpt_bin = NULL; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin( + *context.get_allocator(), mpt1, mpt_bin, context.get_srs()))) { + LOG_WARN("failed to convert geo tree to binary", K(ret)); + } else { + ret = eval_wkb_binary(mpt_bin, g2, context, result); + } + } + break; + } + case ObGeoType::LINESTRING: + case ObGeoType::MULTILINESTRING: { + if (!mpt1->is_empty() || !mpy1->is_empty()) { + result = false; + } else { + ObGeometry *mls_bin = NULL; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin( + *context.get_allocator(), mls1, mls_bin, context.get_srs()))) { + LOG_WARN("failed to convert geo tree to binary", K(ret)); + } else { + ret = eval_wkb_binary(mls_bin, g2, context, result); + } + } + break; + } + case ObGeoType::POLYGON: + case ObGeoType::MULTIPOLYGON: { + if (!mls1->is_empty() || !mpt1->is_empty()) { + result = false; + } else { + ObGeometry *mpy_bin = NULL; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin( + *context.get_allocator(), mpy1, mpy_bin, context.get_srs()))) { + LOG_WARN("failed to convert geo tree to binary", K(ret)); + } else { + ret = eval_wkb_binary(mpy_bin, g2, context, result); + } + } + break; + } + default: { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid geometry type", K(ret), K(g2->type())); + } + } + } + } + } else if (g2->type() == ObGeoType::GEOMETRYCOLLECTION) { + ret = eval_equals_geometry_collection(g2, g1, context, result); + } else { + // none of the two geometries are collection type + // not supposed to go to this branch + ret = eval_wkb_binary(g1, g2, context, result); + } + return ret; + } +}; + +//===========BIN GEOM========== +// Geom Point +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomPoint, ObWkbGeomPoint, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomPoint, ObWkbGeomMultiPoint, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom LineString +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomLineString, ObWkbGeomLineString, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObWkbGeomLineString, ObWkbGeomMultiLineString, bool) +{ + return eval_equals_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom Polygon +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomPolygon, ObWkbGeomPolygon, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomPolygon, ObWkbGeomMultiPolygon, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom MultiPoint +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomMultiPoint, ObWkbGeomPoint, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPoint, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom MultiLineString +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObWkbGeomMultiLineString, ObWkbGeomLineString, bool) +{ + return eval_equals_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiLineString, bool) +{ + return eval_equals_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom MultiPolygon +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomMultiPolygon, ObWkbGeomPolygon, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiPolygon, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom Collection +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomCollection, ObWkbGeomCollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomCollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeomCollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +//===========BIN GEOG========== +// Geog Point +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogPoint, ObWkbGeogPoint, bool) +{ + // Default strategy is OK. P/P computations do not depend on shape of ellipsoid. + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogPoint, ObWkbGeogMultiPoint, bool) +{ + // Default strategy is OK. P/P computations do not depend on shape of ellipsoid. + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geog LineString +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogLineString, ObWkbGeogLineString, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObWkbGeogLineString, ObWkbGeogMultiLineString, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// Geog Polygon +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogPolygon, ObWkbGeogPolygon, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogPolygon, ObWkbGeogMultiPolygon, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// Geog MultiPoint +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogMultiPoint, ObWkbGeogPoint, bool) +{ + // Default strategy is OK. P/P computations do not depend on shape of ellipsoid. + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPoint, bool) +{ + // Default strategy is OK. P/P computations do not depend on shape of ellipsoid. + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geog MultiLineString +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObWkbGeogMultiLineString, ObWkbGeogLineString, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiLineString, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// Geog MultiPolygon +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogMultiPolygon, ObWkbGeogPolygon, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiPolygon, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// Geog Collection +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogCollection, ObWkbGeogCollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogCollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncEqualsImpl, ObWkbGeogCollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// cartesian tree +// Geom Point +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObCartesianPoint, ObCartesianPoint, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObCartesianPoint, ObCartesianMultipoint, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom LineString +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObCartesianLineString, ObCartesianLineString, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObCartesianLineString, ObCartesianMultilinestring, bool) +{ + return eval_equals_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom Polygon +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObCartesianPolygon, ObCartesianPolygon, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObCartesianPolygon, ObCartesianMultipolygon, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom MultiPoint +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObCartesianMultipoint, ObCartesianPoint, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObCartesianMultipoint, ObCartesianMultipoint, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom MultiLineString +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObCartesianMultilinestring, ObCartesianLineString, bool) +{ + return eval_equals_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObCartesianMultilinestring, ObCartesianMultilinestring, bool) +{ + return eval_equals_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom MultiPolygon +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObCartesianMultipolygon, ObCartesianPolygon, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObCartesianMultipolygon, ObCartesianMultipolygon, bool) +{ + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geom Collection +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObCartesianGeometrycollection, ObCartesianGeometrycollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_GEO2_BEGIN(ObGeoFuncEqualsImpl, ObCartesianGeometrycollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_GEO1_BEGIN(ObGeoFuncEqualsImpl, ObCartesianGeometrycollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// Geog tree +// Geog Point +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObGeographPoint, ObGeographPoint, bool) +{ + // Default strategy is OK. P/P computations do not depend on shape of ellipsoid. + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObGeographPoint, ObGeographMultipoint, bool) +{ + // Default strategy is OK. P/P computations do not depend on shape of ellipsoid. + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geog LineString +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObGeographLineString, ObGeographLineString, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObGeographLineString, ObGeographMultilinestring, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// Geog Polygon +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObGeographPolygon, ObGeographPolygon, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObGeographPolygon, ObGeographMultipolygon, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// Geog MultiPoint +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObGeographMultipoint, ObGeographPoint, bool) +{ + // Default strategy is OK. P/P computations do not depend on shape of ellipsoid. + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObGeographMultipoint, ObGeographMultipoint, bool) +{ + // Default strategy is OK. P/P computations do not depend on shape of ellipsoid. + return eval_equals_without_strategy(g1, g2, result); +} +OB_GEO_FUNC_END; + +// Geog MultiLineString +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObGeographMultilinestring, ObGeographLineString, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObGeographMultilinestring, ObGeographMultilinestring, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// Geog MultiPolygon +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObGeographMultipolygon, ObGeographPolygon, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncEqualsImpl, ObGeographMultipolygon, ObGeographMultipolygon, bool) +{ + return eval_equals_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// Geog Collection +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncEqualsImpl, ObGeographGeometrycollection, ObGeographGeometrycollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_GEO2_BEGIN(ObGeoFuncEqualsImpl, ObGeographGeometrycollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_GEO1_BEGIN(ObGeoFuncEqualsImpl, ObGeographGeometrycollection, bool) +{ + return eval_equals_geometry_collection(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +int ObGeoFuncEquals::eval(const ObGeoEvalCtx &gis_context, bool &result) +{ + return ObGeoFuncEqualsImpl::eval_geo_func(gis_context, result); +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_equals.h b/deps/oblib/src/lib/geo/ob_geo_func_equals.h new file mode 100644 index 0000000000..0de2ef8e5e --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_equals.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_equals. + */ + +#ifndef OCEANBASE_LIB_OB_GEO_FUNC_EQUALS_ +#define OCEANBASE_LIB_OB_GEO_FUNC_EQUALS_ + +#include "lib/geo/ob_geo_func_common.h" + +namespace oceanbase +{ +namespace common +{ + +class ObGeoFuncEquals +{ +public: + ObGeoFuncEquals(); + virtual ~ObGeoFuncEquals() = default; + static int eval(const common::ObGeoEvalCtx &gis_context, bool &result); +}; + +} // namespace common +} // namespace oceanbase +#endif // OCEANBASE_LIB_OB_GEO_FUNC_EQUALS_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_intersects.cpp b/deps/oblib/src/lib/geo/ob_geo_func_intersects.cpp index a1e2fe0cd7..1517d6aabb 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_intersects.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_intersects.cpp @@ -44,8 +44,15 @@ int eval_intersects_by_disjoint(const ObGeometry *g1, const ObGeometry *g2, cons template int eval_intersects_without_strategy(const ObGeometry *g1, const ObGeometry *g2, bool &result) { - const GeoType1 *geo1 = reinterpret_cast(g1->val()); - const GeoType2 *geo2 = reinterpret_cast(g2->val()); + const GeoType1 *geo1 = nullptr; + const GeoType2 *geo2 = nullptr; + if (!g1->is_tree()) { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } else { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } result = bg::intersects(*geo1, *geo2); return OB_SUCCESS; } @@ -331,6 +338,20 @@ OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncIntersectsImpl, ObWkbGeogPoint, ObWkbGeog return eval_intersects_geometry_collection(g1, g2, context, result); } OB_GEO_FUNC_END; +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncIntersectsImpl, ObCartesianPolygon, ObCartesianPolygon, bool) +{ + UNUSED(context); + return eval_intersects_without_strategy(g1, g2, result); +} OB_GEO_FUNC_END; +// detect polygon self-intersection +OB_GEO_UNARY_TREE_FUNC_BEGIN(ObGeoFuncIntersectsImpl, ObCartesianPolygon, bool) +{ + UNUSED(context); + const ObCartesianPolygon *geo = reinterpret_cast(g); + result = bg::intersects(*geo); + return OB_SUCCESS; +} OB_GEO_FUNC_END; + int ObGeoFuncIntersects::eval(const ObGeoEvalCtx &gis_context, bool &result) { return ObGeoFuncIntersectsImpl::eval_geo_func(gis_context, result); diff --git a/deps/oblib/src/lib/geo/ob_geo_func_isvalid.cpp b/deps/oblib/src/lib/geo/ob_geo_func_isvalid.cpp index bee226d190..077106fbeb 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_isvalid.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_isvalid.cpp @@ -26,11 +26,27 @@ namespace common template static int eval_isvalid_without_strategy(const ObGeometry *g, + const ObGeoEvalCtx &context, bool &result) { INIT_SUCC(ret); - const GeoType *geo_condidate = reinterpret_cast(const_cast(g->val())); - result = bg::is_valid(*geo_condidate); + const GeoType *geo_condidate = nullptr; + if (!g->is_tree()) { + geo_condidate = reinterpret_cast(const_cast(g->val())); + } else { + geo_condidate = reinterpret_cast(const_cast(g)); + } + if (OB_ISNULL(geo_condidate)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("geometry can not be null", K(ret)); + } else { + bg::validity_failure_type reason; + result = bg::is_valid(*geo_condidate, reason); + if (!result && context.get_val_count() > 0) { + ObGeoNormalVal *ret_errno = const_cast(context.get_val_arg(0)); + ret_errno->int64_ = static_cast(reason); + } + } return ret; } @@ -48,7 +64,12 @@ static int eval_isvalid_with_strategy(const ObGeometry *g, bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); bg::strategy::intersection::geographic_segments<> m_geographic_ll_la_aa_strategy(geog_sphere); const GeoType *geo_condidate = reinterpret_cast(const_cast(g->val())); - result = bg::is_valid(*geo_condidate, m_geographic_ll_la_aa_strategy); + bg::validity_failure_type reason; + result = bg::is_valid(*geo_condidate, reason, m_geographic_ll_la_aa_strategy); + if (!result && context.get_val_count() > 0) { + ObGeoNormalVal *ret_errno = const_cast(context.get_val_arg(0)); + ret_errno->int64_ = static_cast(reason); + } } return ret; } @@ -73,7 +94,7 @@ public: static int eval(const ObGeometry *g, const ObGeoEvalCtx &context, bool &result) { UNUSED(context); - return eval_isvalid_without_strategy(g, result); + return eval_isvalid_without_strategy(g, context, result); } }; @@ -157,6 +178,17 @@ OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncIsValidImpl, ObWkbGeogMultiPolygon, bool) return eval_isvalid_with_strategy(g, context, result); } OB_GEO_FUNC_END; +OB_GEO_UNARY_TREE_FUNC_BEGIN(ObGeoFuncIsValidImpl, ObCartesianPolygon, bool) +{ + return eval_isvalid_without_strategy(g, context, result); +} OB_GEO_FUNC_END; + +OB_GEO_UNARY_TREE_FUNC_BEGIN(ObGeoFuncIsValidImpl, ObCartesianMultipolygon, bool) +{ + UNUSED(context); + return eval_isvalid_without_strategy(g, context, result); +} OB_GEO_FUNC_END; + int ObGeoFuncIsValid::eval(const ObGeoEvalCtx &gis_context, bool &result) { return ObGeoFuncIsValidImpl::eval_geo_func(gis_context, result); diff --git a/deps/oblib/src/lib/geo/ob_geo_func_length.cpp b/deps/oblib/src/lib/geo/ob_geo_func_length.cpp new file mode 100644 index 0000000000..b8c1eca821 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_length.cpp @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_length. + */ + +#define USING_LOG_PREFIX LIB +#include "lib/geo/ob_geo_dispatcher.h" +#include "lib/geo/ob_geo_func_length.h" +#include "lib/geo/ob_geo_utils.h" + +using namespace oceanbase::common; +namespace bg = boost::geometry; + +namespace oceanbase +{ +namespace common +{ + +template +static int eval_length_without_strategy(const ObGeometry *g, double &result) +{ + INIT_SUCC(ret); + const GeoType *geo_condidate = reinterpret_cast(const_cast(g->val())); + if (OB_ISNULL(geo_condidate)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid null geometry", K(ret)); + } else { + result = bg::length(*geo_condidate); + } + return ret; +} + +template +static int eval_length_with_strategy( + const ObGeometry *g, const ObGeoEvalCtx &context, double &result) +{ + INIT_SUCC(ret); + const ObSrsItem *srs = context.get_srs(); + const GeoType *geo_condidate = reinterpret_cast(const_cast(g->val())); + if (OB_ISNULL(srs) || OB_ISNULL(geo_condidate)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("geography srs or geometry is null", K(ret), K(srs), K(geo_condidate)); + } else { + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::distance::andoyer> m_geographic_ll_la_aa_strategy( + geog_sphere); + result = bg::length(*geo_condidate, m_geographic_ll_la_aa_strategy); + } + return ret; +} + +class ObGeoFuncLengthImpl : public ObIGeoDispatcher +{ +public: + ObGeoFuncLengthImpl(); + virtual ~ObGeoFuncLengthImpl() = default; + // default templates + OB_GEO_UNARY_FUNC_DEFAULT(double, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + OB_GEO_TREE_UNARY_FUNC_DEFAULT(double, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + OB_GEO_CART_BINARY_FUNC_DEFAULT(double, OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS); + OB_GEO_GEOG_BINARY_FUNC_DEFAULT(double, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + OB_GEO_CART_TREE_FUNC_DEFAULT(double, OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS); + OB_GEO_GEOG_TREE_FUNC_DEFAULT(double, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); +}; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncLengthImpl, ObWkbGeomLineString, double) +{ + UNUSED(context); + return eval_length_without_strategy(g, result); +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncLengthImpl, ObWkbGeomMultiLineString, double) +{ + UNUSED(context); + return eval_length_without_strategy(g, result); +} +OB_GEO_FUNC_END; + +// geography +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncLengthImpl, ObWkbGeogLineString, double) +{ + return eval_length_with_strategy(g, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_UNARY_FUNC_BEGIN(ObGeoFuncLengthImpl, ObWkbGeogMultiLineString, double) +{ + return eval_length_with_strategy(g, context, result); +} +OB_GEO_FUNC_END; + +int ObGeoFuncLength::eval(const ObGeoEvalCtx &gis_context, double &result) +{ + return ObGeoFuncLengthImpl::eval_geo_func(gis_context, result); +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_length.h b/deps/oblib/src/lib/geo/ob_geo_func_length.h new file mode 100644 index 0000000000..9fe273bea1 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_length.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_length. + */ + +#ifndef OCEANBASE_LIB_OB_GEO_FUNC_LENGTH_ +#define OCEANBASE_LIB_OB_GEO_FUNC_LENGTH_ + +#include "lib/geo/ob_geo_func_common.h" + +namespace oceanbase +{ +namespace common +{ + +class ObGeoFuncLength +{ +public: + ObGeoFuncLength(); + ~ObGeoFuncLength(); + static int eval(const common::ObGeoEvalCtx &gis_context, double &result); +}; + +} // namespace common +} // namespace oceanbase +#endif // OCEANBASE_LIB_OB_GEO_FUNC_LENGTH_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_overlaps.cpp b/deps/oblib/src/lib/geo/ob_geo_func_overlaps.cpp new file mode 100644 index 0000000000..bd17dbf54b --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_overlaps.cpp @@ -0,0 +1,707 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_overlaps. + */ + +#define USING_LOG_PREFIX LIB + +#include "lib/geo/ob_geo_dispatcher.h" +#include "lib/geo/ob_geo_func_overlaps.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_func_utils.h" + +using namespace oceanbase::common; +namespace oceanbase +{ +namespace common +{ +namespace bg = boost::geometry; +template +int eval_overlaps_without_strategy(const ObGeometry *g1, const ObGeometry *g2, bool &result) +{ + int ret = OB_SUCCESS; + const GeoType1 *geo1 = NULL; + const GeoType2 *geo2 = NULL; + if (g1->is_tree()) { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } else { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("multipoint or linestring pointer is null", K(ret), K(geo1), K(geo2)); + } else { + result = bg::overlaps(*geo1, *geo2); + } + return ret; +} + +template +int eval_overlaps_with_nonpoint_strategy( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) +{ + INIT_SUCC(ret); + const ObSrsItem *srs = context.get_srs(); + if (OB_ISNULL(srs)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret), K(g1->get_srid()), K(g1), K(g2)); + } else { + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::intersection::geographic_segments<> nonpoint_strategy(geog_sphere); + const GeoType1 *geo1 = NULL; + const GeoType2 *geo2 = NULL; + if (g1->is_tree()) { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } else { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("multipoint or linestring pointer is null", K(ret), K(geo1), K(geo2)); + } else { + result = bg::overlaps(*geo1, *geo2, nonpoint_strategy); + } + } + return ret; +} + +// ----- ObGeoFuncOverlapsImpl ----- +class ObGeoFuncOverlapsImpl : public ObIGeoDispatcher +{ +public: + ObGeoFuncOverlapsImpl(); + virtual ~ObGeoFuncOverlapsImpl() = default; + + // template for unary + OB_GEO_UNARY_FUNC_DEFAULT(ObGeoFuncResWithNull, OB_ERR_GIS_INVALID_DATA); + OB_GEO_TREE_UNARY_FUNC_DEFAULT(ObGeoFuncResWithNull, OB_ERR_GIS_INVALID_DATA); + OB_GEO_CART_TREE_FUNC_DEFAULT(ObGeoFuncResWithNull, OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS); + OB_GEO_GEOG_TREE_FUNC_DEFAULT(ObGeoFuncResWithNull, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + + // template for binary + // default cases for cartesian + template + struct EvalWkbBi + { + static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, + ObGeoFuncResWithNull &result) + { + // If dim(g1) != dim(g2), return NULL (SQL/MM 2015, Part 3, Sect. 5.1.54). + UNUSEDx(g1, g2, context); + result.is_null = true; + return OB_SUCCESS; + } + }; + + // default case for geography + template + struct EvalWkbBiGeog + { + static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, + ObGeoFuncResWithNull &result) + { + // If dim(g1) != dim(g2), return NULL (SQL/MM 2015, Part 3, Sect. 5.1.54). + UNUSEDx(g1, g2, context); + result.is_null = true; + return OB_SUCCESS; + } + }; + +private: + // assume that g1 g2 both collection + template + static int eval_overlaps_gc_gc(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObGeoFuncResWithNull &result) + { + int ret = OB_SUCCESS; + if (g1->type() != ObGeoType::GEOMETRYCOLLECTION + || g2->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("input geometry should be GEOMETRYCOLLECTION", K(ret), K(g1->type()), K(g2->type())); + } else { + result.bret = false; + typename GcTreeType::sub_mpt_type *mpt1 = NULL; + typename GcTreeType::sub_ml_type *mls1 = NULL; + typename GcTreeType::sub_mp_type *mpy1 = NULL; + ObGeometry *geo1 = const_cast(reinterpret_cast(g1)); + uint8_t dim1 = -1; + uint8_t dim2 = -1; + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo1, mpt1, mls1, mpy1))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else { + if (!mpy1->empty()) { + dim1 = 2; + } else if (!mls1->empty()) { + dim1 = 1; + } else if (!mpt1->empty()) { + dim1 = 0; + } else { + result.is_null = true; + } + } + + typename GcTreeType::sub_mpt_type *mpt2 = NULL; + typename GcTreeType::sub_ml_type *mls2 = NULL; + typename GcTreeType::sub_mp_type *mpy2 = NULL; + ObGeometry *geo2 = const_cast(reinterpret_cast(g2)); + if (OB_SUCC(ret) && !result.is_null) { + // bool has_common_interior = false; // Check that if g1 and g2 has common interior + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo2, mpt2, mls2, mpy2))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt2) || OB_ISNULL(mls2) || OB_ISNULL(mpy2)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else { + if (!mpy2->empty()) { + dim2 = 2; + } else if (!mls2->empty()) { + dim2 = 1; + } else if (!mpt2->empty()) { + dim2 = 0; + } else { + result.is_null = true; + } + } + } + + if (OB_FAIL(ret) || result.is_null) { + // do nothing + } else if (dim1 == -1 || dim1 != dim2) { + result.is_null = true; + } else { + ObGeoFuncResWithNull mpt_res; + ObGeoFuncResWithNull mls_res; + ObGeoFuncResWithNull mpy_res; + switch (dim1) { + case 2: + if (OB_FAIL(eval_tree_binary(mpy1, mpy2, context, mpy_res))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + case 1: + if (OB_FAIL(eval_tree_binary(mls1, mls2, context, mls_res))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + case 0: + if (OB_FAIL(eval_tree_binary(mpt1, mpt2, context, mpt_res))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + break; + default: { + // should not go here + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected dim provided to overlaps", K(ret), K(dim1)); + } + } + result.bret |= mpy_res.bret || mpt_res.bret || mls_res.bret; + } + } + return ret; + } + + template + static int eval_overlaps_gc_other(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObGeoFuncResWithNull &result) + { + int ret = OB_SUCCESS; + if (g1->type() != ObGeoType::GEOMETRYCOLLECTION + && g2->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("At least one of g1 and g2 is collection", K(ret), K(g1->type()), K(g2->type())); + } else if (g2->type() == ObGeoType::GEOMETRYCOLLECTION + && g1->type() == ObGeoType::GEOMETRYCOLLECTION) { + if (OB_FAIL(eval_overlaps_gc_gc(g1, g2, context, result))) { + LOG_WARN("fail to eval overlaps with geometrycollection", K(ret)); + } + } else if (g2->type() == ObGeoType::GEOMETRYCOLLECTION) { + ret = eval_overlaps_gc_other(g2, g1, context, result); + } else { + // now assert g1 is colletion and g2 is not collection. + result.bret = false; + typename GcTreeType::sub_mpt_type *mpt1 = NULL; + typename GcTreeType::sub_ml_type *mls1 = NULL; + typename GcTreeType::sub_mp_type *mpy1 = NULL; + ObGeometry *geo1 = const_cast(reinterpret_cast(g1)); + uint8_t dim1 = -1; + uint8_t dim2 = -1; + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo1, mpt1, mls1, mpy1))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else { + if (!mpy1->empty()) { + dim1 = 2; + } else if (!mls1->empty()) { + dim1 = 1; + } else if (!mpt1->empty()) { + dim1 = 0; + } else { + result.is_null = true; + } + } + + ObGeoToTreeVisitor to_tree(context.get_allocator()); + ObGeometry *geo2 = const_cast(g2); + if (OB_FAIL(ret) || result.is_null) { + // do nothing + } else if (OB_FAIL(geo2->do_visit(to_tree))) { + LOG_WARN("fail to do visit with ObGeoToTreeVisitor", K(ret)); + } else { + ObGeometry *g2_tree = to_tree.get_geometry(); + switch (g2_tree->type()) { + case ObGeoType::POINT: + case ObGeoType::MULTIPOINT: { + if (dim1 != 0) { + result.is_null = true; + } else if (OB_FAIL(eval_tree_binary(mpt1, g2_tree, context, result))) { + LOG_WARN("fail to do eval_tree_binary", K(ret), K(g2_tree->type())); + } + break; + } + case ObGeoType::LINESTRING: + case ObGeoType::MULTILINESTRING: { + if (dim1 != 1) { + result.is_null = true; + } else if (OB_FAIL(eval_tree_binary(mls1, g2_tree, context, result))) { + LOG_WARN("fail to do eval_tree_binary", K(ret), K(g2_tree->type())); + } + break; + } + case ObGeoType::POLYGON: + case ObGeoType::MULTIPOLYGON: { + if (dim1 != 2) { + result.is_null = true; + } else if (OB_FAIL(eval_tree_binary(mpy1, g2_tree, context, result))) { + LOG_WARN("fail to do eval_tree_binary", K(ret), K(g2_tree->type())); + } + break; + } + default: { + // should not go here + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected dim provided to overlaps", K(ret), K(dim1)); + break; + } + } + } + } + return ret; + } +}; + +//===========BIN CART========== +/*Point*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomPoint, ObWkbGeomPoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomPoint, ObWkbGeomMultiPoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +/*Linestring*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomLineString, ObWkbGeomLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomLineString, ObWkbGeomMultiLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +/*Polygon*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomPolygon, ObWkbGeomPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy(g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomPolygon, ObWkbGeomMultiPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiPoint*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomMultiPoint, ObWkbGeomPoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPoint, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiLineString*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomMultiLineString, ObWkbGeomLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiPolygon*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomMultiPolygon, ObWkbGeomPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +/*Collection*/ +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeomCollection, ObWkbGeomCollection, ObGeoFuncResWithNull) +{ + return eval_overlaps_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncOverlapsImpl, ObWkbGeomCollection, ObGeoFuncResWithNull) +{ + return eval_overlaps_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncOverlapsImpl, ObWkbGeomCollection, ObGeoFuncResWithNull) +{ + return eval_overlaps_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +//===========BIN GEOG========== +/*Point*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogPoint, ObWkbGeogPoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogPoint, ObWkbGeogMultiPoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +/*Linestring*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogLineString, ObWkbGeogLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogLineString, ObWkbGeogMultiLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +/*Polygon*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogPolygon, ObWkbGeogPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogPolygon, ObWkbGeogMultiPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiPoint*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogMultiPoint, ObWkbGeogPoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPoint, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiLineString*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogMultiLineString, ObWkbGeogLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +/*MultiPolygon*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogMultiPolygon, ObWkbGeogPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +/*Collection*/ +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObWkbGeogCollection, ObWkbGeogCollection, ObGeoFuncResWithNull) +{ + return eval_overlaps_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncOverlapsImpl, ObWkbGeogCollection, ObGeoFuncResWithNull) +{ + return eval_overlaps_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncOverlapsImpl, ObWkbGeogCollection, ObGeoFuncResWithNull) +{ + return eval_overlaps_gc_other(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +//===========TREE CART (not completely)========== +// multipoint +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObCartesianMultipoint, ObCartesianMultipoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObCartesianMultipoint, ObCartesianPoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +// multilinestring +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncOverlapsImpl, ObCartesianMultilinestring, + ObCartesianMultilinestring, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObCartesianMultilinestring, ObCartesianLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +// multipolygon +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObCartesianMultipolygon, ObCartesianMultipolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObCartesianMultipolygon, ObCartesianPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_without_strategy( + g1, g2, result.bret); +} +OB_GEO_FUNC_END; + +//===========TREE GEOG (not completely)========== +// multipoint +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObGeographMultipoint, ObGeographMultipoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObGeographMultipoint, ObGeographPoint, ObGeoFuncResWithNull) +{ + // point is completely contained by another geometry, so they are not overlaps + UNUSEDx(g1, g2, context); + result.bret = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +// multilinestring +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncOverlapsImpl, ObGeographMultilinestring, + ObGeographMultilinestring, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObGeographMultilinestring, ObGeographLineString, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +// multipolygon +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObGeographMultipolygon, ObGeographMultipolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncOverlapsImpl, ObGeographMultipolygon, ObGeographPolygon, ObGeoFuncResWithNull) +{ + UNUSED(context); + return eval_overlaps_with_nonpoint_strategy( + g1, g2, context, result.bret); +} +OB_GEO_FUNC_END; + +int ObGeoFuncOverlaps::eval(const ObGeoEvalCtx &gis_context, ObGeoFuncResWithNull &result) +{ + return ObGeoFuncOverlapsImpl::eval_geo_func(gis_context, result); +} +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_overlaps.h b/deps/oblib/src/lib/geo/ob_geo_func_overlaps.h new file mode 100644 index 0000000000..71b511d235 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_overlaps.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_overlaps. + */ + +#ifndef OCEANBASE_LIB_OB_GEO_FUNC_OVERLAPS_ +#define OCEANBASE_LIB_OB_GEO_FUNC_OVERLAPS_ + +#include "lib/geo/ob_geo_func_common.h" + +namespace oceanbase +{ +namespace common +{ +class ObGeoFuncOverlaps +{ +public: + ObGeoFuncOverlaps(); + virtual ~ObGeoFuncOverlaps() = default; + static int eval(const common::ObGeoEvalCtx &gis_context, ObGeoFuncResWithNull &result); +}; + +} // namespace common +} // namespace oceanbase +#endif // OCEANBASE_LIB_OB_GEO_FUNC_OVERLAPS_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_register.h b/deps/oblib/src/lib/geo/ob_geo_func_register.h index 1c8bcd3cd4..7f7dac632b 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_register.h +++ b/deps/oblib/src/lib/geo/ob_geo_func_register.h @@ -29,6 +29,14 @@ #include "lib/geo/ob_geo_func_isvalid.h" #include "lib/geo/ob_geo_func_distance_sphere.h" #include "lib/geo/ob_geo_func_within.h" +#include "lib/geo/ob_geo_func_equals.h" +#include "lib/geo/ob_geo_func_touches.h" +#include "lib/geo/ob_geo_func_centroid.h" +#include "lib/geo/ob_geo_func_crosses.h" +#include "lib/geo/ob_geo_func_overlaps.h" +#include "lib/geo/ob_geo_func_length.h" +#include "lib/geo/ob_geo_func_symdifference.h" +#include "lib/geo/ob_geo_func_dissolve_polygon.h" namespace oceanbase { @@ -56,9 +64,16 @@ enum class ObGeoFuncType IsValid = 12, DistanceSphere = 13, Within = 14, + Equals = 15, + Touches = 16, + Centroid = 17, + Crosses = 18, + Overlaps = 19, + Length = 20, + SymDifference = 21, + DissolvePolygon = 22, ObGisFuncTypeMax }; - class ObGeoFuncNotImplemented { public: @@ -160,6 +175,54 @@ struct ObGeoFunc typedef ObGeoFuncWithin gis_func; }; +template <> +struct ObGeoFunc +{ + typedef ObGeoFuncEquals geo_func; +}; + +template <> +struct ObGeoFunc +{ + typedef ObGeoFuncTouches geo_func; +}; + +template <> +struct ObGeoFunc +{ + typedef ObGeoFuncCentroid geo_func; +}; + +template <> +struct ObGeoFunc +{ + typedef ObGeoFuncCrosses geo_func; +}; + +template <> +struct ObGeoFunc +{ + typedef ObGeoFuncOverlaps geo_func; +}; + +template <> +struct ObGeoFunc +{ + typedef ObGeoFuncLength geo_func; +}; + +template <> +struct ObGeoFunc +{ + typedef ObGeoFuncSymDifference geo_func; +}; + +template <> +struct ObGeoFunc +{ + typedef ObGeoFuncDissolvePolygon geo_func; +}; + } // sql } // oceanbase #endif // OCEANBASE_LIB_OB_GEO_FUNC_REGISTER_ diff --git a/deps/oblib/src/lib/geo/ob_geo_func_symdifference.cpp b/deps/oblib/src/lib/geo/ob_geo_func_symdifference.cpp new file mode 100644 index 0000000000..a88a856a00 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_symdifference.cpp @@ -0,0 +1,1527 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_symdifference. + */ + +#define USING_LOG_PREFIX LIB + +#include "lib/geo/ob_geo_dispatcher.h" +#include "lib/geo/ob_geo_func_symdifference.h" +#include "lib/geo/ob_geo_tree.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" +#include "lib/oblog/ob_log_module.h" +#include "lib/geo/ob_geo_func_utils.h" + +using namespace oceanbase::common; +namespace oceanbase +{ +namespace common +{ + +namespace bg = boost::geometry; +template +static int get_specific_geos(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, const GeoType1 *&geo1, const GeoType2 *&geo2, GeometryRes *&res) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(g1) || OB_ISNULL(g2)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("wrong geometry type", K(ret)); + } else if (g1->is_tree()) { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } else { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } + if (OB_SUCC(ret)) { + res = OB_NEWx(GeometryRes, context.get_allocator(), g1->get_srid(), *context.get_allocator()); + if (OB_ISNULL(res) || OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("wrong geometry type or create geometry failed", K(ret), K(res), K(geo1), K(geo2)); + } + } + return ret; +} + +template +static int apply_bg_symdifference_pt_pt( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) +{ + INIT_SUCC(ret); + GeometryRes *res = nullptr; + const GeoType1 *geo1 = nullptr; + const GeoType2 *geo2 = nullptr; + if (OB_FAIL(get_specific_geos(g1, g2, context, geo1, geo2, res))) { + LOG_WARN("fail to get specific geometry", K(ret)); + } else { + ObIAllocator *allocator = context.get_allocator(); + GeometryRes *union_res = OB_NEWx(GeometryRes, allocator, g1->get_srid(), *allocator); + GeometryRes *intersection_res = OB_NEWx(GeometryRes, allocator, g1->get_srid(), *allocator); + if (OB_ISNULL(union_res) || OB_ISNULL(intersection_res)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to create geometry", K(ret), K(union_res), K(intersection_res)); + } else { + bg::union_(*geo1, *geo2, *union_res); + bg::intersection(*geo1, *geo2, *intersection_res); + bg::difference(*union_res, *intersection_res, *res); + result = res; + } + } + return ret; +} + +template +static int push_disjoint_point(PtBinType &geo1, GeoType &geo2, const ObGeoEvalCtx &context, + ObBGStrategyType strategy, GeoCollType &res) +{ + int ret = OB_SUCCESS; + bool is_disjoint = false; + if (strategy == ObBGStrategyType::DEFAULT_NONE) { + is_disjoint = bg::disjoint(geo1, geo2); + } else if (OB_ISNULL(context.get_srs())) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("invalid null srs", K(ret)); + } else { + const ObSrsItem *srs = context.get_srs(); + boost::geometry::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + ObPlPaStrategy point_strategy(geog_sphere); + is_disjoint = bg::disjoint(geo1, geo2, point_strategy); + } + if (OB_SUCC(ret) && is_disjoint) { + ObIAllocator *allocator = context.get_allocator(); + typename GeoCollType::sub_pt_type *pt = OB_NEWx(typename GeoCollType::sub_pt_type, + allocator, + geo1.template get<0>(), + geo1.template get<1>(), + 0, + allocator); + if (OB_ISNULL(pt)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory for geometry", K(ret)); + } else if (OB_FAIL(res.push_back(*reinterpret_cast(pt)))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + return ret; +} + +template +static int push_not_empty_geo(ObGeometry &geo, const ObGeoEvalCtx &context, GeometryRes &res) +{ + int ret = OB_SUCCESS; + bool is_geo_empty = false; + if (OB_FAIL(ObGeoTypeUtil::check_empty(&geo, is_geo_empty))) { + LOG_WARN("fail to check is geometry empty", K(ret)); + } else if (!is_geo_empty) { + ObGeoToTreeVisitor geom_visitor(context.get_allocator()); + if (OB_FAIL(geo.do_visit(geom_visitor))) { + LOG_WARN("failed to convert bin to tree", K(ret)); + } else if (OB_FAIL(res.push_back(*geom_visitor.get_geometry()))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + return ret; +} + +template +static int apply_bg_symdifference_pl_pa(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObBGStrategyType strategy, ObGeometry *&result) +{ + INIT_SUCC(ret); + GeoCollType *res = nullptr; + const PtBinType *pt = nullptr; + const GeoType *geo2 = nullptr; + if (OB_FAIL(get_specific_geos(g1, g2, context, pt, geo2, res))) { + LOG_WARN("fail to get specific geometry", K(ret)); + } else if (OB_FAIL(push_not_empty_geo(*const_cast(g2), context, *res))) { + LOG_WARN("fail to push back not empty geometry", K(ret)); + } else if (OB_FAIL(push_disjoint_point(*pt, *geo2, context, strategy, *res))) { + LOG_WARN("fail to push disjoint point", K(ret)); + } else { + result = res; + } + return ret; +} + +template +static int apply_bg_symdifference(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObGeometry *&result, + ObBGStrategyType strategy = ObBGStrategyType::DEFAULT_NONE) +{ + INIT_SUCC(ret); + GeometryRes *res = nullptr; + const GeoType1 *geo1 = nullptr; + const GeoType2 *geo2 = nullptr; + if (OB_FAIL(get_specific_geos(g1, g2, context, geo1, geo2, res))) { + LOG_WARN("fail to get specific geometry", K(ret)); + } else if (strategy == ObBGStrategyType::DEFAULT_NONE) { + bg::sym_difference(*geo1, *geo2, *res); + } else if (OB_ISNULL(context.get_srs())) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("invalid null srs", K(ret)); + } else { + const ObSrsItem *srs = context.get_srs(); + boost::geometry::srs::spheroid geog_sphere( + srs->semi_major_axis(), srs->semi_minor_axis()); + ObLlLaAaStrategy line_strategy(geog_sphere); + bg::sym_difference(*geo1, *geo2, *res, line_strategy); + } + if (OB_SUCC(ret)) { + result = res; + } + return ret; +} + +template +static int apply_bg_symdifference_la(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObGeometry *&result, + ObBGStrategyType strategy = ObBGStrategyType::DEFAULT_NONE) +{ + INIT_SUCC(ret); + GeoCollType *res = nullptr; + const GeoType1 *geo1 = nullptr; + const GeoType2 *geo2 = nullptr; + ObIAllocator *allocator = context.get_allocator(); + if (OB_FAIL(get_specific_geos(g1, g2, context, geo1, geo2, res))) { + LOG_WARN("fail to get specific geometry", K(ret)); + } else if (OB_FAIL(push_not_empty_geo(*const_cast(g2), context, *res))) { + LOG_WARN("fail to push back not empty geometry", K(ret)); + } + if (OB_SUCC(ret)) { + typename GeoCollType::sub_ml_type *diff_res = + OB_NEWx(typename GeoCollType::sub_ml_type, allocator, g1->get_srid(), *allocator); + if (OB_ISNULL(diff_res)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("wrong geometry type or create geometry failed", K(ret)); + } else if (strategy == ObBGStrategyType::DEFAULT_NONE) { + bg::difference(*geo1, *geo2, *diff_res); + } else if (OB_ISNULL(context.get_srs())) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("invalid null srs", K(ret)); + } else { + const ObSrsItem *srs = context.get_srs(); + boost::geometry::srs::spheroid geog_sphere( + srs->semi_major_axis(), srs->semi_minor_axis()); + ObLlLaAaStrategy line_strategy(geog_sphere); + bg::difference(*geo1, *geo2, *diff_res, line_strategy); + } + if (OB_SUCC(ret)) { + typename GeoCollType::sub_ml_type::iterator iter = diff_res->begin(); + for (; OB_SUCC(ret) && iter != diff_res->end(); iter++) { + if (OB_FAIL(res->push_back(*iter))) { + LOG_WARN("fail to push back geometry to collection", K(ret)); + } + } + } + } + if (OB_SUCC(ret)) { + result = res; + } + return ret; +} + +template +static int apply_bg_symdifference_mpl_mpa(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObBGStrategyType strategy, ObGeometry *&result) +{ + INIT_SUCC(ret); + GeoCollType *res = nullptr; + const MptType *mpt_bin = nullptr; + const GeoType *geo2 = nullptr; + if (OB_FAIL(get_specific_geos(g1, g2, context, mpt_bin, geo2, res))) { + LOG_WARN("fail to get specific geometry", K(ret)); + } else if (OB_FAIL(push_not_empty_geo(*const_cast(g2), context, *res))) { + LOG_WARN("fail to push back not empty geometry", K(ret)); + } + typename MptType::const_iterator iter = mpt_bin->begin(); + for (; OB_SUCC(ret) && iter != mpt_bin->end(); iter++) { + if (OB_FAIL(push_disjoint_point(*iter, *geo2, context, strategy, *res))) { + LOG_WARN("fail to push disjoint point", K(ret)); + } + } + if (OB_SUCC(ret)) { + result = res; + } + + return ret; +} + +template +static int apply_bg_symdifference_coll_common(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObGeometry *&result, typename GcTreeType::sub_mpt_type *&mpt, + typename GcTreeType::sub_ml_type *&mls, typename GcTreeType::sub_mp_type *&mpy) +{ + int ret = OB_SUCCESS; + bool is_g2_empty = false; + if (g1->type() == ObGeoType::GEOMETRYCOLLECTION || g2->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("input geometry is wrong", K(ret), K(g1->type()), K(g2->type())); + } else if (OB_FAIL(ObGeoTypeUtil::check_empty(const_cast(g2), is_g2_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_g2_empty) { + if (OB_FAIL(ObGeoFuncUtils::apply_bg_to_tree(g1, context, result))) { + LOG_WARN("fail to apply bg to tree", K(ret)); + } + } else { + ObGeometry *geo2 = const_cast(g2); + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo2, mpt, mls, mpy))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt) || OB_ISNULL(mls) || OB_ISNULL(mpt)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("unexpected null geometry collection split", K(ret), K(mpt), K(mls), K(mpt)); + } + } + return ret; +} + +template +static int simplify_and_push_geometry( + ObIAllocator &allocator, ObGeometry *push_geo, GcTreeType &geo_coll) +{ + int ret = OB_SUCCESS; + if (OB_FAIL((ObGeoFuncUtils::simplify_multi_geo(push_geo, allocator)))) { + LOG_WARN("fail to simplify result", K(ret)); + } else if (OB_FAIL(geo_coll.push_back(*push_geo))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + return ret; +} + +template +static int apply_bg_symdifference_pt_coll(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObBGStrategyType strategy, ObGeometry *&result) +{ + int ret = OB_SUCCESS; + typename GcTreeType::sub_mpt_type *mpt = nullptr; + typename GcTreeType::sub_ml_type *mls = nullptr; + typename GcTreeType::sub_mp_type *mpy = nullptr; + if (OB_FAIL( + apply_bg_symdifference_coll_common(g1, g2, context, result, mpt, mls, mpy))) { + LOG_WARN("fail to apply symdifference collection common", K(ret)); + } else if (OB_ISNULL(result)) { + ObIAllocator *allocator = context.get_allocator(); + ObGeometry *g1_tree = nullptr; + ObGeoToTreeVisitor tree_visitor(allocator); + ObGeometry *mpt_res = nullptr; + if (OB_FAIL(const_cast(g1)->do_visit(tree_visitor))) { + LOG_WARN("fail to convert geometry to tree", K(ret)); + } else if (FALSE_IT(g1_tree = tree_visitor.get_geometry())) { + } else if (OB_FAIL((apply_bg_symdifference_pt_pt(g1_tree, mpt, context, mpt_res)))) { + LOG_WARN("fail to do symdifference between pointlike and pointlike type", K(ret)); + } else { + uint32_t srid = g1->get_srid(); + typename GcTreeType::sub_mpt_type *mls_res = + OB_NEWx(typename GcTreeType::sub_mpt_type, allocator, srid, *allocator); + typename GcTreeType::sub_mpt_type *mpy_res = + OB_NEWx(typename GcTreeType::sub_mpt_type, allocator, srid, *allocator); + GcTreeType *res = OB_NEWx(GcTreeType, allocator, srid, *allocator); + if (OB_ISNULL(mls_res) || OB_ISNULL(mpy_res) || OB_ISNULL(res)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("wrong geometry type or create geometry failed", + K(ret), + K(mls_res), + K(mpy_res), + K(res)); + } else if (strategy == ObBGStrategyType::DEFAULT_NONE) { + bg::difference( + *reinterpret_cast(mpt_res), *mls, *mls_res); + bg::difference(*mls_res, *mpy, *mpy_res); + } else if (OB_ISNULL(context.get_srs())) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("invalid null srs", K(ret)); + } else { + const ObSrsItem *srs = context.get_srs(); + boost::geometry::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + ObPlPaStrategy point_strategy(geog_sphere); + ObLlLaAaStrategy line_strategy(geog_sphere); + bg::difference( + *reinterpret_cast(mpt_res), *mls, *mls_res, point_strategy); + bg::difference(*mls_res, *mpy, *mpy_res, point_strategy); + } + if (OB_SUCC(ret) && !mpy_res->is_empty() + && OB_FAIL(simplify_and_push_geometry( + *allocator, reinterpret_cast(mpy_res), *res))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + if (OB_SUCC(ret) && !mls->is_empty() + && OB_FAIL(simplify_and_push_geometry( + *allocator, reinterpret_cast(mls), *res))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + if (OB_SUCC(ret) && !mpy->is_empty() + && OB_FAIL(simplify_and_push_geometry( + *allocator, reinterpret_cast(mpy), *res))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + if (OB_SUCC(ret)) { + result = res; + } + } + } + return ret; +} + +template +static int apply_bg_symdifference_line_coll(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObBGStrategyType strategy, ObGeometry *&result) +{ + int ret = OB_SUCCESS; + typename GcTreeType::sub_mpt_type *mpt = nullptr; + typename GcTreeType::sub_ml_type *mls = nullptr; + typename GcTreeType::sub_mp_type *mpy = nullptr; + if (OB_FAIL( + apply_bg_symdifference_coll_common(g1, g2, context, result, mpt, mls, mpy))) { + LOG_WARN("fail to apply symdifference collection common", K(ret)); + } else if (OB_ISNULL(result)) { + ObIAllocator *allocator = context.get_allocator(); + ObGeometry *g1_tree = nullptr; + ObGeoToTreeVisitor tree_visitor(allocator); + if (OB_FAIL(const_cast(g1)->do_visit(tree_visitor))) { + LOG_WARN("fail to convert geometry to tree", K(ret)); + } else if (FALSE_IT(g1_tree = tree_visitor.get_geometry())) { + } else { + uint32_t srid = g1->get_srid(); + typename GcTreeType::sub_ml_type *mls_res = + OB_NEWx(typename GcTreeType::sub_ml_type, allocator, srid, *allocator); + GcTreeType *res = OB_NEWx(GcTreeType, allocator, srid, *allocator); + typename GcTreeType::sub_ml_type *mls_diff_res = + OB_NEWx(typename GcTreeType::sub_ml_type, allocator, srid, *allocator); + typename GcTreeType::sub_mpt_type *mpt_res = + OB_NEWx(typename GcTreeType::sub_mpt_type, allocator, srid, *allocator); + if (OB_ISNULL(mpt_res) || OB_ISNULL(mls_res) || OB_ISNULL(res) || OB_ISNULL(mls_diff_res)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("wrong geometry type or create geometry failed", + K(ret), + K(mpt_res), + K(mls_res), + K(res), + K(mls_diff_res)); + } else if (strategy == ObBGStrategyType::DEFAULT_NONE) { + bg::difference(*reinterpret_cast(g1_tree), *mpy, *mls_res); + bg::sym_difference(*mls, *mls_res, *mls_diff_res); + bg::difference(*mpt, *reinterpret_cast(g1_tree), *mpt_res); + } else if (OB_ISNULL(context.get_srs())) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("invalid null srs", K(ret)); + } else { + const ObSrsItem *srs = context.get_srs(); + boost::geometry::srs::spheroid geog_sphere( + srs->semi_major_axis(), srs->semi_minor_axis()); + ObLlLaAaStrategy line_strategy(geog_sphere); + bg::difference(*reinterpret_cast(g1_tree), *mpy, *mls_res, line_strategy); + bg::sym_difference(*mls, *mls_res, *mls_diff_res, line_strategy); + ObPlPaStrategy point_strategy(geog_sphere); + bg::difference(*mpt, *reinterpret_cast(g1_tree), *mpt_res, point_strategy); + } + if (OB_SUCC(ret) && !mpy->is_empty() + && OB_FAIL(simplify_and_push_geometry( + *allocator, reinterpret_cast(mpy), *res))) { + LOG_WARN("fail to simplify and push geometry", K(ret)); + } + if (OB_SUCC(ret) && !mls_diff_res->is_empty() + && OB_FAIL(simplify_and_push_geometry( + *allocator, reinterpret_cast(mls_diff_res), *res))) { + LOG_WARN("fail to simplify and push geometry", K(ret)); + } + if (OB_SUCC(ret) && !mpt_res->is_empty() + && OB_FAIL(simplify_and_push_geometry( + *allocator, reinterpret_cast(mpt_res), *res))) { + LOG_WARN("fail to simplify and push geometry", K(ret)); + } + if (OB_SUCC(ret)) { + result = res; + } + } + } + return ret; +} + +template +static int apply_bg_symdifference_poly_coll(const ObGeometry *g1, const ObGeometry *g2, + const ObGeoEvalCtx &context, ObBGStrategyType strategy, ObGeometry *&result) +{ + int ret = OB_SUCCESS; + typename GcTreeType::sub_mpt_type *mpt = nullptr; + typename GcTreeType::sub_ml_type *mls = nullptr; + typename GcTreeType::sub_mp_type *mpy = nullptr; + if (OB_FAIL( + apply_bg_symdifference_coll_common(g1, g2, context, result, mpt, mls, mpy))) { + LOG_WARN("fail to apply symdifference collection common", K(ret)); + } else if (OB_ISNULL(result)) { + ObIAllocator *allocator = context.get_allocator(); + ObGeometry *g1_tree = nullptr; + ObGeoToTreeVisitor tree_visitor(allocator); + if (OB_FAIL(const_cast(g1)->do_visit(tree_visitor))) { + LOG_WARN("fail to convert geometry to tree", K(ret)); + } else if (FALSE_IT(g1_tree = tree_visitor.get_geometry())) { + } else { + uint32_t srid = g1->get_srid(); + typename GcTreeType::sub_ml_type *mls_res = + OB_NEWx(typename GcTreeType::sub_ml_type, allocator, srid, *allocator); + GcTreeType *res = OB_NEWx(GcTreeType, allocator, srid, *allocator); + typename GcTreeType::sub_mp_type *mpy_res = + OB_NEWx(typename GcTreeType::sub_mp_type, allocator, srid, *allocator); + typename GcTreeType::sub_mpt_type *mpt_res = + OB_NEWx(typename GcTreeType::sub_mpt_type, allocator, srid, *allocator); + if (OB_ISNULL(mpt_res) || OB_ISNULL(mls_res) || OB_ISNULL(res) || OB_ISNULL(mpy_res)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("wrong geometry type or create geometry failed", + K(ret), + K(mpt_res), + K(mls_res), + K(res), + K(mpy_res)); + } else if (strategy == ObBGStrategyType::DEFAULT_NONE) { + bg::sym_difference(*reinterpret_cast(g1_tree), *mpy, *mpy_res); + bg::difference(*mls, *reinterpret_cast(g1_tree), *mls_res); + bg::difference(*mpt, *reinterpret_cast(g1_tree), *mpt_res); + } else if (OB_ISNULL(context.get_srs())) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("invalid null srs", K(ret)); + } else { + const ObSrsItem *srs = context.get_srs(); + boost::geometry::srs::spheroid geog_sphere( + srs->semi_major_axis(), srs->semi_minor_axis()); + ObLlLaAaStrategy line_strategy(geog_sphere); + ObPlPaStrategy point_strategy(geog_sphere); + bg::sym_difference( + *reinterpret_cast(g1_tree), *mpy, *mpy_res, line_strategy); + bg::difference(*mls, *reinterpret_cast(g1_tree), *mls_res, line_strategy); + bg::difference(*mpt, *reinterpret_cast(g1_tree), *mpt_res, point_strategy); + } + if (OB_SUCC(ret) && !mpy_res->is_empty() + && OB_FAIL(simplify_and_push_geometry( + *allocator, reinterpret_cast(mpy_res), *res))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + if (OB_SUCC(ret) && !mls_res->is_empty() + && OB_FAIL(simplify_and_push_geometry( + *allocator, reinterpret_cast(mls_res), *res))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + if (OB_SUCC(ret) && !mpt_res->is_empty() + && OB_FAIL(simplify_and_push_geometry( + *allocator, reinterpret_cast(mpt_res), *res))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + if (OB_SUCC(ret)) { + result = res; + } + } + } + return ret; +} + +class ObGeoFuncSymDifferenceImpl : public ObIGeoDispatcher +{ +public: + ObGeoFuncSymDifferenceImpl(); + virtual ~ObGeoFuncSymDifferenceImpl() = default; + // template for unary + OB_GEO_UNARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_GIS_INVALID_DATA); + OB_GEO_TREE_UNARY_FUNC_DEFAULT(ObGeometry *, OB_ERR_GIS_INVALID_DATA); + OB_GEO_CART_TREE_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS); + OB_GEO_GEOG_TREE_FUNC_DEFAULT(ObGeometry *, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + + template + struct EvalWkbBi + { + static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, + ObGeometry *&result) + { + UNUSEDx(g1, g2, context, result); + return OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS; + } + }; + + template + struct EvalWkbBiGeog + { + static int eval(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, + ObGeometry *&result) + { + UNUSEDx(g1, g2, context, result); + return OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS; + } + }; + +private: + // assume that g1 g2 both collection + template + static int eval_symdifference_gc_gc( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) + { + int ret = OB_SUCCESS; + ObIAllocator *allocator = context.get_allocator(); + result = nullptr; + bool is_g1_empty = false; + bool is_g2_empty = false; + if (g1->type() != ObGeoType::GEOMETRYCOLLECTION + || g2->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("input geometry should be GEOMETRYCOLLECTION", K(ret), K(g1->type()), K(g2->type())); + } else if (OB_FAIL(ObGeoTypeUtil::check_empty(const_cast(g1), is_g1_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::check_empty(const_cast(g2), is_g2_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_g1_empty) { + if (is_g2_empty) { + GcTreeType *res_coll = OB_NEWx(GcTreeType, allocator, g1->get_srid(), *allocator); + if (OB_ISNULL(res_coll)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory for gometry", K(ret)); + } else { + result = res_coll; + } + } else if (OB_FAIL(ObGeoFuncUtils::apply_bg_to_tree(g2, context, result))) { + LOG_WARN("fail to apply bg to tree", K(ret)); + } + } else { + typename GcTreeType::sub_mpt_type *mpt1 = nullptr; + typename GcTreeType::sub_ml_type *mls1 = nullptr; + typename GcTreeType::sub_mp_type *mpy1 = nullptr; + ObGeometry *geo1 = const_cast(g1); + ObGeometry *mpy_bin = nullptr; + ObGeometry *mls_bin = nullptr; + ObGeometry *mpt_bin = nullptr; + ObGeometry *mpy_res = nullptr; + ObGeometry *mpy_res_bin = nullptr; + ObGeometry *mls_res = nullptr; + ObGeometry *mls_res_bin = nullptr; + const ObSrsItem *srs = context.get_srs(); + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo1, mpt1, mls1, mpy1))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(*allocator, mpy1, mpy_bin, srs))) { + LOG_WARN("fail to convert geometry tree to bin", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(*allocator, mls1, mls_bin, srs))) { + LOG_WARN("fail to convert geometry tree to bin", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(*allocator, mpt1, mpt_bin, srs))) { + LOG_WARN("fail to convert geometry tree to bin", K(ret)); + } else if (OB_FAIL(eval_wkb_binary(mpy_bin, g2, context, mpy_res))) { + LOG_WARN("fail to eval wkb binary", K(ret)); + } else if (OB_FAIL(!mpy_res->is_empty() && (ObGeoFuncUtils::simplify_multi_geo(mpy_res, *allocator)))) { + LOG_WARN("fail to simplify result", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(*allocator, mpy_res, mpy_res_bin, srs))) { + LOG_WARN("fail to convert geometry tree to bin", K(ret)); + } else if (OB_FAIL(eval_wkb_binary(mls_bin, mpy_res_bin, context, mls_res))) { + LOG_WARN("fail to eval wkb binary", K(ret)); + } else if (OB_FAIL(!mls_res->is_empty() && (ObGeoFuncUtils::simplify_multi_geo(mls_res, *allocator)))) { + LOG_WARN("fail to simplify result", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(*allocator, mls_res, mls_res_bin, srs))) { + LOG_WARN("fail to convert geometry tree to bin", K(ret)); + } else if (OB_FAIL(eval_wkb_binary(mpt_bin, mls_res_bin, context, result))) { + LOG_WARN("fail to eval wkb binary", K(ret)); + } else if (OB_FAIL(!result->is_empty() && (ObGeoFuncUtils::simplify_multi_geo(result, *allocator)))) { + LOG_WARN("fail to simplify result", K(ret)); + } + } + return ret; + } +}; + +// cartesian point +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPoint, ObWkbGeomPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_pt( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPoint, ObWkbGeomLineString, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPoint, ObWkbGeomPolygon, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPoint, ObWkbGeomMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_pt( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPoint, ObWkbGeomMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPoint, ObWkbGeomMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPoint, ObWkbGeomCollection, ObGeometry *) +{ + return apply_bg_symdifference_pt_coll( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +// cartisian linestring +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomLineString, ObWkbGeomPoint, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomLineString, ObWkbGeomLineString, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomLineString, ObWkbGeomPolygon, ObGeometry *) +{ + return apply_bg_symdifference_la(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomLineString, ObWkbGeomMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomLineString, ObWkbGeomMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomLineString, ObWkbGeomMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_la(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomLineString, ObWkbGeomCollection, ObGeometry *) +{ + return apply_bg_symdifference_line_coll( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +// cartisian polygon +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomPoint, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomLineString, ObGeometry *) +{ + return apply_bg_symdifference_la(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomPolygon, ObGeometry *) +{ + return apply_bg_symdifference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_la(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomPolygon, ObWkbGeomCollection, ObGeometry *) +{ + return apply_bg_symdifference_poly_coll( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +// cartisian multipoint +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_pt( + g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomLineString, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomPolygon, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_pt(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPoint, ObWkbGeomCollection, ObGeometry *) +{ + return apply_bg_symdifference_pt_coll( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +// cartisian mutilinestring +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomPoint, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomLineString, ObGeometry *) +{ + return apply_bg_symdifference(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomPolygon, ObGeometry *) +{ + return apply_bg_symdifference_la(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_la(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiLineString, ObWkbGeomCollection, ObGeometry *) +{ + return apply_bg_symdifference_line_coll(g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +// cartisian multipolygon +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomPoint, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomLineString, ObGeometry *) +{ + return apply_bg_symdifference_la(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomPolygon, ObGeometry *) +{ + return apply_bg_symdifference( + g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_la(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomMultiPolygon, ObWkbGeomCollection, ObGeometry *) +{ + return apply_bg_symdifference_poly_coll( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +// cartesian collection +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomCollection, ObWkbGeomPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_coll( + g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomCollection, ObWkbGeomLineString, ObGeometry *) +{ + return apply_bg_symdifference_line_coll( + g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomCollection, ObWkbGeomPolygon, ObGeometry *) +{ + return apply_bg_symdifference_poly_coll( + g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomCollection, ObWkbGeomMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_coll( + g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomCollection, ObWkbGeomMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_line_coll(g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomCollection, ObWkbGeomMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_poly_coll( + g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeomCollection, ObWkbGeomCollection, ObGeometry *) +{ + return eval_symdifference_gc_gc(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +//----------------geographic-------------------// +// geograph point +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPoint, ObWkbGeogPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_pt( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPoint, ObWkbGeogLineString, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPoint, ObWkbGeogPolygon, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPoint, ObWkbGeogMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_pt( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPoint, ObWkbGeogMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPoint, ObWkbGeogMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPoint, ObWkbGeogCollection, ObGeometry *) +{ + return apply_bg_symdifference_pt_coll( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +// geograph linestring +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogLineString, ObWkbGeogPoint, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogLineString, ObWkbGeogLineString, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result, ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogLineString, ObWkbGeogPolygon, ObGeometry *) +{ + return apply_bg_symdifference_la(g1, g2, context, result, + ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogLineString, ObWkbGeogMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogLineString, ObWkbGeogMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result, ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogLineString, ObWkbGeogMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_la(g1, g2, context, result, + ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogLineString, ObWkbGeogCollection, ObGeometry *) +{ + return apply_bg_symdifference_line_coll( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +// geograph polygon +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogPoint, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogLineString, ObGeometry *) +{ + return apply_bg_symdifference_la(g2, g1, context, result, + ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogPolygon, ObGeometry *) +{ + return apply_bg_symdifference( + g1, g2, context, result, ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_la(g2, g1, context, result, + ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference( + g1, g2, context, result, ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogPolygon, ObWkbGeogCollection, ObGeometry *) +{ + return apply_bg_symdifference_poly_coll( + g1, g2, context, ObBGStrategyType::LL_LA_AA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +// geograph multipoint +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_pt( + g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogLineString, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogPolygon, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_pt(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPoint, ObWkbGeogCollection, ObGeometry *) +{ + return apply_bg_symdifference_pt_coll( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +// geograph mutilinestring +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogPoint, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogLineString, ObGeometry *) +{ + return apply_bg_symdifference(g2, g1, context, result, ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogPolygon, ObGeometry *) +{ + return apply_bg_symdifference_la(g1, g2, context, result, + ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result, ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_la(g1, g2, context, result, + ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiLineString, ObWkbGeogCollection, ObGeometry *) +{ + return apply_bg_symdifference_line_coll( + g1, g2, context, ObBGStrategyType::LL_LA_AA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +// geograph multipolygon +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogPoint, ObGeometry *) +{ + return apply_bg_symdifference_pl_pa(g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogLineString, ObGeometry *) +{ + return apply_bg_symdifference_la(g2, g1, context, result, + ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogPolygon, ObGeometry *) +{ + return apply_bg_symdifference( + g2, g1, context, result, ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_mpl_mpa(g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_la(g2, g1, context, result, + ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result, ObBGStrategyType::LL_LA_AA_STRATEGY); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogMultiPolygon, ObWkbGeogCollection, ObGeometry *) +{ + return apply_bg_symdifference_poly_coll( + g1, g2, context, ObBGStrategyType::LL_LA_AA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +// geograph collection +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogCollection, ObWkbGeogPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_coll( + g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogCollection, ObWkbGeogLineString, ObGeometry *) +{ + return apply_bg_symdifference_line_coll( + g2, g1, context, ObBGStrategyType::LL_LA_AA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogCollection, ObWkbGeogPolygon, ObGeometry *) +{ + return apply_bg_symdifference_poly_coll( + g2, g1, context, ObBGStrategyType::LL_LA_AA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogCollection, ObWkbGeogMultiPoint, ObGeometry *) +{ + return apply_bg_symdifference_pt_coll( + g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogCollection, ObWkbGeogMultiLineString, ObGeometry *) +{ + return apply_bg_symdifference_line_coll( + g2, g1, context, ObBGStrategyType::LL_LA_AA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogCollection, ObWkbGeogMultiPolygon, ObGeometry *) +{ + return apply_bg_symdifference_poly_coll( + g2, g1, context, ObBGStrategyType::LL_LA_AA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncSymDifferenceImpl, ObWkbGeogCollection, ObWkbGeogCollection, ObGeometry *) +{ + return eval_symdifference_gc_gc(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// tree cartesian polygon +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncSymDifferenceImpl, ObCartesianPolygon, ObCartesianPolygon, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result); +} OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncSymDifferenceImpl, ObCartesianPolygon, ObCartesianMultipolygon, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result); +} OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncSymDifferenceImpl, ObCartesianMultipolygon, ObCartesianPolygon, ObGeometry *) +{ + return apply_bg_symdifference(g1, g2, context, result); +} OB_GEO_FUNC_END; + +// implement of outer class eval +// use an outer class to void implement templates in header files +int ObGeoFuncSymDifference::eval(const ObGeoEvalCtx &gis_context, ObGeometry *&result) +{ + return ObGeoFuncSymDifferenceImpl::eval_geo_func(gis_context, result); +} + +} // namespace common +} // namespace oceanbase diff --git a/deps/oblib/src/lib/geo/ob_geo_func_symdifference.h b/deps/oblib/src/lib/geo/ob_geo_func_symdifference.h new file mode 100644 index 0000000000..6c9165da24 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_symdifference.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_symdifference. + */ + +#ifndef OCEANBASE_LIB_OB_GEO_FUNC_SYMDIFFERENCE_H_ +#define OCEANBASE_LIB_OB_GEO_FUNC_SYMDIFFERENCE_H_ + +#include "lib/geo/ob_geo_func_common.h" + +namespace oceanbase +{ +namespace common +{ + +class ObGeoFuncSymDifference +{ +public: + ObGeoFuncSymDifference(); + ~ObGeoFuncSymDifference(); + static int eval(const common::ObGeoEvalCtx &gis_context, common::ObGeometry *&result); +}; + + + +} // sql +} // oceanbase +#endif // OCEANBASE_LIB_OB_GEO_FUNC_SYMDIFFERENCE_H_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_touches.cpp b/deps/oblib/src/lib/geo/ob_geo_func_touches.cpp new file mode 100644 index 0000000000..9063386760 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_touches.cpp @@ -0,0 +1,1154 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_touches. + */ + +#define USING_LOG_PREFIX LIB + +#include "lib/geo/ob_geo_dispatcher.h" +#include "lib/geo/ob_geo_func_touches.h" +#include "lib/geo/ob_geo_func_disjoint.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_func_utils.h" + +using namespace oceanbase::common; +namespace oceanbase +{ +namespace common +{ +namespace bg = boost::geometry; +template +static void touches_with_point(const GeometryType1 *geo1, const GeometryType2 *geo2, + ObBGStrategyType strategy, const ObGeoEvalCtx &context, bool &res) +{ + if (strategy == ObBGStrategyType::DEFAULT_NONE) { + res = bg::touches(*geo1, *geo2); + } else { + const ObSrsItem *srs = context.get_srs(); + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::within::geographic_winding point_strategy(geog_sphere); + res = bg::touches(*geo1, *geo2, point_strategy); + } +} + +template +static void within_with_point(const GeometryType1 *geo1, const GeometryType2 *geo2, + ObBGStrategyType strategy, const ObGeoEvalCtx &context, bool &res) +{ + if (strategy == ObBGStrategyType::DEFAULT_NONE) { + res = bg::within(*geo1, *geo2); + } else { + const ObSrsItem *srs = context.get_srs(); + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::within::geographic_winding point_strategy(geog_sphere); + res = bg::within(*geo1, *geo2, point_strategy); + } +} + +template +static int eval_touches_mpt(const ObGeometry *mpt, const ObGeometry *geo, const ObGeoEvalCtx &context, + ObBGStrategyType strategy, bool &result) +{ + int ret = OB_SUCCESS; + const MptType *mpt_bin = NULL; + const GeoType *geo_bin = NULL; + if (mpt->is_tree()) { + mpt_bin = reinterpret_cast(mpt); + geo_bin = reinterpret_cast(geo); + } else { + mpt_bin = reinterpret_cast(mpt->val()); + geo_bin = reinterpret_cast(geo->val()); + } + result = false; + if (OB_ISNULL(mpt_bin) || OB_ISNULL(geo_bin)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("multipoint or linestring pointer is null", K(ret), K(mpt_bin), K(geo_bin)); + } else { + // At least one point in g1 has to touch g2, + // and none of the points in g1 may be within g2 + typename MptType::const_iterator iter = mpt_bin->begin(); + bool pt_within = false; + for (; OB_SUCC(ret) && iter != mpt_bin->end() && !pt_within; iter++) { + typename MptType::value_type &pt = *iter; + bool pt_touches = false; + if (!result) { + touches_with_point(&pt, geo_bin, strategy, context, pt_touches); + result = pt_touches; + } + if (!pt_touches) { + within_with_point(&pt, geo_bin, strategy, context, pt_within); + } + } + if (pt_within) { + result = false; + } + } + return ret; +} + +template +static int eval_touches_with_point_strategy( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) +{ + INIT_SUCC(ret); + const ObSrsItem *srs = context.get_srs(); + if (OB_ISNULL(srs)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret), K(g1->get_srid()), K(g1), K(g2)); + } else { + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::within::geographic_winding point_strategy(geog_sphere); + const GeoType1 *geo1 = reinterpret_cast(g1->val()); + const GeoType2 *geo2 = reinterpret_cast(g2->val()); + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("multipoint or linestring pointer is null", K(ret), K(geo1), K(geo2)); + } else { + result = bg::touches(*geo1, *geo2, point_strategy); + } + } + return ret; +} + +template +static int eval_touches_without_strategy(const ObGeometry *g1, const ObGeometry *g2, bool &result) +{ + int ret = OB_SUCCESS; + const GeoType1 *geo1 = NULL; + const GeoType2 *geo2 = NULL; + if (g1->is_tree()) { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } else { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("multipoint or linestring pointer is null", K(ret), K(geo1), K(geo2)); + } else { + result = bg::touches(*geo1, *geo2); + } + return ret; +} + +template +static int eval_touches_with_nonpoint_strategy( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) +{ + INIT_SUCC(ret); + const ObSrsItem *srs = context.get_srs(); + if (OB_ISNULL(srs)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret), K(g1->get_srid()), K(g1), K(g2)); + } else { + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::intersection::geographic_segments<> nonpoint_strategy(geog_sphere); + const GeoType1 *geo1 = NULL; + const GeoType2 *geo2 = NULL; + if (g1->is_tree()) { + geo1 = reinterpret_cast(g1); + geo2 = reinterpret_cast(g2); + } else { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("multipoint or linestring pointer is null", K(ret), K(geo1), K(geo2)); + } else { + result = bg::touches(*geo1, *geo2, nonpoint_strategy); + } + } + return ret; +} + +// ----- ObGeoFuncTouchesImpl ----- +class ObGeoFuncTouchesImpl : public ObIGeoDispatcher +{ +public: + ObGeoFuncTouchesImpl(); + virtual ~ObGeoFuncTouchesImpl() = default; + + // template for unary + OB_GEO_UNARY_FUNC_DEFAULT(bool, OB_ERR_GIS_INVALID_DATA); + OB_GEO_TREE_UNARY_FUNC_DEFAULT(bool, OB_ERR_GIS_INVALID_DATA); + OB_GEO_CART_TREE_FUNC_DEFAULT(bool, OB_ERR_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS); + OB_GEO_GEOG_TREE_FUNC_DEFAULT(bool, OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS); + + // template for binary + // default cases for cartesian + template + struct EvalWkbBi + { + static int eval( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + UNUSED(context); + return eval_touches_without_strategy(g1, g2, result); + } + }; + + // default case for geography (calc using nonpoint_strategy) + template + struct EvalWkbBiGeog + { + static int eval( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + return eval_touches_with_nonpoint_strategy(g1, g2, context, result); + } + }; + +private: + template + static int is_part_touches_gc_other(typename GcTreeType::sub_mpt_type *mpt1, + typename GcTreeType::sub_ml_type *mls1, typename GcTreeType::sub_mp_type *mpy1, + const ObGeometry *g2, const ObGeoEvalCtx &context, bool &is_part_touches) + { + int ret = OB_SUCCESS; + is_part_touches = false; + if (OB_SUCC(ret) && !is_part_touches && !mls1->is_empty()) { + ObGeometry *mls_bin = NULL; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin( + *context.get_allocator(), mls1, mls_bin, context.get_srs()))) { + LOG_WARN("failed to convert geo tree to binary", K(ret)); + } else if (OB_FAIL(eval_wkb_binary(mls_bin, g2, context, is_part_touches))) { + LOG_WARN("fail to eval wkb binary", K(ret)); + } + } + if (OB_SUCC(ret) && !is_part_touches && !mpy1->is_empty()) { + ObGeometry *mpy_bin = NULL; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin( + *context.get_allocator(), mpy1, mpy_bin, context.get_srs()))) { + LOG_WARN("failed to convert geo tree to binary", K(ret)); + } else if (OB_FAIL(eval_wkb_binary(mpy_bin, g2, context, is_part_touches))) { + LOG_WARN("fail to eval wkb binary", K(ret)); + } + } + return ret; + } + + template + static int is_part_touches_gc_gc(typename GcTreeType::sub_mpt_type *mpt1, + typename GcTreeType::sub_ml_type *mls1, typename GcTreeType::sub_mp_type *mpy1, + typename GcTreeType::sub_mpt_type *mpt2, typename GcTreeType::sub_ml_type *mls2, + typename GcTreeType::sub_mp_type *mpy2, const ObGeoEvalCtx &context, bool &is_part_touches) + { + int ret = OB_SUCCESS; + is_part_touches = false; + if (!is_part_touches && !mpy1->is_empty() && !mls2->is_empty()) { + if (OB_FAIL(eval_tree_binary(mpy1, mls2, context, is_part_touches))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + } + if (OB_SUCC(ret) && !is_part_touches && !mpy1->is_empty() && !mpy2->is_empty()) { + if (OB_FAIL(eval_tree_binary(mpy1, mpy2, context, is_part_touches))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + } + if (OB_SUCC(ret) && !is_part_touches && !mls1->is_empty() && !mls2->is_empty()) { + if (OB_FAIL(eval_tree_binary(mls1, mls2, context, is_part_touches))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + } + if (OB_SUCC(ret) && !is_part_touches && !mls1->is_empty() && !mpy2->is_empty()) { + if (OB_FAIL(eval_tree_binary(mls1, mpy2, context, is_part_touches))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + } + if (OB_SUCC(ret) && !is_part_touches && !mpt1->is_empty() && !mls2->is_empty()) { + if (OB_FAIL(eval_tree_binary(mpt1, mls2, context, is_part_touches))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + } + if (OB_SUCC(ret) && !is_part_touches && !mpt1->is_empty() && !mpy2->is_empty()) { + if (OB_FAIL(eval_tree_binary(mpt1, mpy2, context, is_part_touches))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + } + if (OB_SUCC(ret) && !is_part_touches && !mls1->is_empty() && !mpt2->is_empty()) { + if (OB_FAIL(eval_tree_binary(mls1, mpt2, context, is_part_touches))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + } + if (OB_SUCC(ret) && !is_part_touches && !mpy1->is_empty() && !mpt2->is_empty()) { + if (OB_FAIL(eval_tree_binary(mpy1, mpt2, context, is_part_touches))) { + LOG_WARN("fail to eval tree binary", K(ret)); + } + } + return ret; + } + + template + static int is_part_joint_gc_gc(typename GcTreeType::sub_mpt_type *mpt1, + typename GcTreeType::sub_ml_type *mls1, typename GcTreeType::sub_mp_type *mpy1, + typename GcTreeType::sub_mpt_type *mpt2, typename GcTreeType::sub_ml_type *mls2, + typename GcTreeType::sub_mp_type *mpy2, const ObGeoEvalCtx &context, bool &is_part_joint) + { + int ret = OB_SUCCESS; + bg::de9im::mask mask("T********"); + is_part_joint = false; + if (mpt1->crs() == ObGeoCRS::Cartesian) { + typename GcTreeType::sub_mpt_type::iterator iter = mpt1->begin(); + for (; !is_part_joint && iter != mpt1->end(); iter++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter; + if (bg::relate(pt, *mpt2, mask) || bg::relate(pt, *mls2, mask) + || bg::relate(pt, *mpy2, mask)) { + is_part_joint = true; + } + } + typename GcTreeType::sub_mpt_type::iterator iter2 = mpt2->begin(); + for (; !is_part_joint && iter2 != mpt2->end(); iter2++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter2; + if (bg::relate(pt, *mls1, mask) || bg::relate(pt, *mpy1, mask)) { + is_part_joint = true; + } + } + if (!is_part_joint + && (bg::relate(*mls1, *mls2, mask) || bg::relate(*mls1, *mpy2, mask) + || bg::relate(*mpy1, *mls2, mask) || bg::relate(*mpy1, *mpy2, mask))) { + is_part_joint = true; + } + } else { + const ObSrsItem *srs = context.get_srs(); + if (OB_ISNULL(srs)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret)); + } else { + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::within::geographic_winding point_strategy(geog_sphere); + bg::strategy::intersection::geographic_segments<> nonpoint_strategy(geog_sphere); + typename GcTreeType::sub_mpt_type::iterator iter = mpt1->begin(); + for (; !is_part_joint && iter != mpt1->end(); iter++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter; + if (bg::relate(pt, *mpt2, mask) || bg::relate(pt, *mls2, mask, point_strategy) + || bg::relate(pt, *mpy2, mask, point_strategy)) { + is_part_joint = true; + } + } + typename GcTreeType::sub_mpt_type::iterator iter2 = mpt2->begin(); + for (; !is_part_joint && iter2 != mpt2->end(); iter2++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter2; + if (bg::relate(pt, *mls1, mask, point_strategy) + || bg::relate(pt, *mpy1, mask, point_strategy)) { + is_part_joint = true; + } + } + if (!is_part_joint + && (bg::relate(*mls1, *mls2, mask, nonpoint_strategy) + || bg::relate(*mls1, *mpy2, mask, nonpoint_strategy) + || bg::relate(*mpy1, *mls2, mask, nonpoint_strategy) + || bg::relate(*mpy1, *mpy2, mask, nonpoint_strategy))) { + is_part_joint = true; + } + } + } + return ret; + } + + template + static void is_relate(ObGeometry *g, typename GcTreeType::sub_mpt_type *mpt, + typename GcTreeType::sub_ml_type *mls, typename GcTreeType::sub_mp_type *mpy, + bool &is_part_joint) + { + bg::de9im::mask mask("T********"); + GeoType *geo = reinterpret_cast(g); + typename GcTreeType::sub_mpt_type::iterator iter = mpt->begin(); + for (; !is_part_joint && iter != mpt->end(); iter++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter; + if (bg::relate(pt, *geo, mask)) { + is_part_joint = true; + } + } + if (!is_part_joint && (bg::relate(*mls, *geo, mask) || bg::relate(*mpy, *geo, mask))) { + is_part_joint = true; + } + } + + template + static void is_relate_with_strategy(ObGeometry *g, typename GcTreeType::sub_mpt_type *mpt, + typename GcTreeType::sub_ml_type *mls, typename GcTreeType::sub_mp_type *mpy, + const ObSrsItem *srs, bool &is_part_joint) + { + bg::de9im::mask mask("T********"); + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::within::geographic_winding point_strategy(geog_sphere); + bg::strategy::intersection::geographic_segments<> nonpoint_strategy(geog_sphere); + GeoType *geo = reinterpret_cast(g); + typename GcTreeType::sub_mpt_type::iterator iter = mpt->begin(); + for (; !is_part_joint && iter != mpt->end(); iter++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter; + if (bg::relate(pt, *geo, mask, point_strategy)) { + is_part_joint = true; + } + } + if (!is_part_joint + && (bg::relate(*mls, *geo, mask, nonpoint_strategy) + || bg::relate(*mpy, *geo, mask, nonpoint_strategy))) { + is_part_joint = true; + } + } + + template + static int is_part_joint_gc_other_geog(typename GcTreeType::sub_mpt_type *mpt1, + typename GcTreeType::sub_ml_type *mls1, typename GcTreeType::sub_mp_type *mpy1, + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + int ret = OB_SUCCESS; + bool is_part_joint = false; + bg::de9im::mask mask("T********"); + ObGeometry *g2_tree = NULL; + ObGeoToTreeVisitor geo2_visitor(context.get_allocator()); + ObGeometry *g2_nconst = const_cast(g2); + if (OB_FAIL(g2_nconst->do_visit(geo2_visitor))) { + LOG_WARN("failed to do geo2 to_tree visit", K(ret)); + } else if (FALSE_IT(g2_tree = geo2_visitor.get_geometry())) { + } else if (OB_ISNULL(g2_tree)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("fail to get g2 tree type", K(ret)); + } else { + const ObSrsItem *srs = context.get_srs(); + if (OB_ISNULL(srs)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("srs is null", K(ret), K(g1->get_srid()), K(g1), K(g2)); + } else { + bg::srs::spheroid geog_sphere(srs->semi_major_axis(), srs->semi_minor_axis()); + bg::strategy::within::geographic_winding point_strategy(geog_sphere); + bg::strategy::intersection::geographic_segments<> nonpoint_strategy(geog_sphere); + switch (g2->type()) { + case ObGeoType::POINT: { + ObGeographPoint *geo2 = reinterpret_cast(g2_tree); + if (!mpt1->is_empty() && mls1->is_empty() && mpy1->is_empty()) { + is_part_joint = true; + } else if (bg::relate(*mpt1, *geo2, mask) + || bg::relate(*mls1, *geo2, mask, point_strategy) + || bg::relate(*mpy1, *geo2, mask, point_strategy)) { + is_part_joint = true; + } + break; + } + case ObGeoType::LINESTRING: { + is_relate_with_strategy( + g2_tree, mpt1, mls1, mpy1, srs, is_part_joint); + break; + } + case ObGeoType::POLYGON: { + is_relate_with_strategy( + g2_tree, mpt1, mls1, mpy1, srs, is_part_joint); + break; + } + case ObGeoType::MULTILINESTRING: { + is_relate_with_strategy( + g2_tree, mpt1, mls1, mpy1, srs, is_part_joint); + break; + } + case ObGeoType::MULTIPOLYGON: { + is_relate_with_strategy( + g2_tree, mpt1, mls1, mpy1, srs, is_part_joint); + break; + } + case ObGeoType::MULTIPOINT: { + if (!mpt1->is_empty() && mls1->is_empty() && mpy1->is_empty()) { + is_part_joint = true; + } + typename GcTreeType::sub_mpt_type *geo2_mpt = + reinterpret_cast(g2_tree); + typename GcTreeType::sub_mpt_type::iterator iter = geo2_mpt->begin(); + for (; !is_part_joint && iter != geo2_mpt->end(); iter++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter; + if (bg::relate(pt, *mls1, mask, point_strategy) + || bg::relate(pt, *mpy1, mask, point_strategy)) { + is_part_joint = true; + } + } + // Default strategy is OK for multipoint-multipoint. + if (!is_part_joint && bg::relate(*mpt1, *geo2_mpt, mask)) { + is_part_joint = true; + } + break; + } + default: { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid geometry type", K(ret), K(g2->type())); + } + } + } + } + if (OB_SUCC(ret)) { + result = !is_part_joint; + } + return ret; + } + + template + static int is_part_joint_gc_other_cart(typename GcTreeType::sub_mpt_type *mpt1, + typename GcTreeType::sub_ml_type *mls1, typename GcTreeType::sub_mp_type *mpy1, + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + int ret = OB_SUCCESS; + bool is_part_joint = false; + bg::de9im::mask mask("T********"); + ObGeometry *g2_tree = NULL; + ObGeoToTreeVisitor geo2_visitor(context.get_allocator()); + ObGeometry *g2_nconst = const_cast(g2); + if (OB_FAIL(g2_nconst->do_visit(geo2_visitor))) { + LOG_WARN("failed to do geo2 to_tree visit", K(ret)); + } else if (FALSE_IT(g2_tree = geo2_visitor.get_geometry())) { + } else if (OB_ISNULL(g2_tree)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("fail to get g2 tree type", K(ret)); + } else { + switch (g2->type()) { + case ObGeoType::POINT: { + ObCartesianPoint *geo2 = reinterpret_cast(g2_tree); + if (!mpt1->is_empty() && mls1->is_empty() && mpy1->is_empty()) { + is_part_joint = true; + } else if (bg::relate(*mpt1, *geo2, mask) || bg::relate(*mls1, *geo2, mask) + || bg::relate(*mpy1, *geo2, mask)) { + is_part_joint = true; + } + break; + } + case ObGeoType::LINESTRING: { + is_relate( + g2_tree, mpt1, mls1, mpy1, is_part_joint); + break; + } + case ObGeoType::POLYGON: { + is_relate( + g2_tree, mpt1, mls1, mpy1, is_part_joint); + break; + } + case ObGeoType::MULTILINESTRING: { + is_relate( + g2_tree, mpt1, mls1, mpy1, is_part_joint); + break; + } + case ObGeoType::MULTIPOLYGON: { + is_relate( + g2_tree, mpt1, mls1, mpy1, is_part_joint); + break; + } + case ObGeoType::MULTIPOINT: { + if (!mpt1->is_empty() && mls1->is_empty() && mpy1->is_empty()) { + is_part_joint = true; + } + typename GcTreeType::sub_mpt_type *geo2_mpt = + reinterpret_cast(g2_tree); + typename GcTreeType::sub_mpt_type::iterator iter = geo2_mpt->begin(); + for (; !is_part_joint && iter != geo2_mpt->end(); iter++) { + typename GcTreeType::sub_mpt_type::value_type &pt = *iter; + if (bg::relate(pt, *mls1, mask) || bg::relate(pt, *mpy1, mask)) { + is_part_joint = true; + } + } + if (!is_part_joint && bg::relate(*mpt1, *geo2_mpt, mask)) { + is_part_joint = true; + } + break; + } + default: { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid geometry type", K(ret), K(g2->type())); + } + } + } + + if (OB_SUCC(ret)) { + result = !is_part_joint; + } + return ret; + } + + template + static int eval_touches_gc_other_cart( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + int ret = OB_SUCCESS; + result = false; + if (g1->type() == ObGeoType::GEOMETRYCOLLECTION + && g2->type() == ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("g1 and g2 are both geometry collection", K(ret), K(g1->type()), K(g2->type())); + } else if (g1->type() == ObGeoType::GEOMETRYCOLLECTION) { + typename GcTreeType::sub_mpt_type *mpt1 = NULL; + typename GcTreeType::sub_ml_type *mls1 = NULL; + typename GcTreeType::sub_mp_type *mpy1 = NULL; + ObGeometry *geo1 = const_cast(reinterpret_cast(g1)); + ObIAllocator *allocator = context.get_allocator(); + ObGeoToTreeVisitor tree_visitor(allocator); + bool is_part_joint = false; + bool is_part_touches = false; + bool point_intersects = false; + if (OB_FAIL(geo1->do_visit(tree_visitor))) { + LOG_WARN("failed to transform gc to tree", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_split(*allocator, + *static_cast(tree_visitor.get_geometry()), + mpt1, mls1, mpy1))) { + LOG_WARN("failed to do gc split", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else if (!mpt1->is_empty() && + (g2->type() == ObGeoType::POINT || g2->type() == ObGeoType::MULTIPOINT)) { + ObGeometry *mpt_bin = NULL; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin( + *context.get_allocator(), mpt1, mpt_bin, context.get_srs()))) { + LOG_WARN("failed to convert geo tree to binary", K(ret)); + } else { + ObGeoEvalCtx intersects_context(context.get_allocator(), context.get_srs()); + intersects_context.append_geo_arg(mpt_bin); + intersects_context.append_geo_arg(g2); + if (OB_FAIL(ObGeoFuncIntersects::eval(intersects_context, point_intersects))) { + LOG_WARN("eval disjoint for intersects failed", K(ret)); + } else if (point_intersects) { + result = false; + } + } + } + + if (point_intersects || OB_FAIL(ret)) { + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_union(*allocator, *context.get_srs(), mpt1, mls1, mpy1))) { + LOG_WARN("fail to do gc union", K(ret)); + } else { + // Check that at least one part of g1 touches at least one part of g2. + if (OB_FAIL((is_part_touches_gc_other( + mpt1, mls1, mpy1, g2, context, is_part_touches)))) { + LOG_WARN("fail to do is part touches gc other", K(ret)); + } else if (!is_part_touches) { + result = false; + } else if (OB_FAIL((is_part_joint_gc_other_cart( + mpt1, mls1, mpy1, g1, g2, context, result)))) { + LOG_WARN("fail to eval is part joint", K(ret)); + } + } + } else if (g2->type() == ObGeoType::GEOMETRYCOLLECTION) { + ret = eval_touches_gc_other_cart(g2, g1, context, result); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("g1 and g2 are not geometry collection", K(ret), K(g1->type()), K(g2->type())); + } + return ret; + } + + template + static int eval_touches_gc_other_geog( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + int ret = OB_SUCCESS; + result = false; + if (g1->type() == ObGeoType::GEOMETRYCOLLECTION + && g2->type() == ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("g1 and g2 are both geometry collection", K(ret), K(g1->type()), K(g2->type())); + } else if (g1->type() == ObGeoType::GEOMETRYCOLLECTION) { + typename GcTreeType::sub_mpt_type *mpt1 = NULL; + typename GcTreeType::sub_ml_type *mls1 = NULL; + typename GcTreeType::sub_mp_type *mpy1 = NULL; + ObGeometry *geo1 = const_cast(reinterpret_cast(g1)); + ObIAllocator *allocator = context.get_allocator(); + ObGeoToTreeVisitor tree_visitor(allocator); + bool is_part_joint = false; + bool is_part_touches = false; + bool point_intersects = false; + if (OB_FAIL(geo1->do_visit(tree_visitor))) { + LOG_WARN("failed to transform gc to tree", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_split(*allocator, + *static_cast(tree_visitor.get_geometry()), + mpt1, mls1, mpy1))) { + LOG_WARN("failed to do gc split", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else if (!mpt1->is_empty() && + (g2->type() == ObGeoType::POINT || g2->type() == ObGeoType::MULTIPOINT)) { + ObGeometry *mpt_bin = NULL; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin( + *context.get_allocator(), mpt1, mpt_bin, context.get_srs()))) { + LOG_WARN("failed to convert geo tree to binary", K(ret)); + } else { + ObGeoEvalCtx intersects_context(context.get_allocator(), context.get_srs()); + intersects_context.append_geo_arg(mpt_bin); + intersects_context.append_geo_arg(g2); + if (OB_FAIL(ObGeoFuncIntersects::eval(intersects_context, point_intersects))) { + LOG_WARN("eval disjoint for intersects failed", K(ret)); + } else if (point_intersects) { + result = false; + } + } + } + + if (point_intersects || OB_FAIL(ret)) { + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_union(*allocator, *context.get_srs(), mpt1, mls1, mpy1))) { + LOG_WARN("fail to do gc union", K(ret)); + } else { + // Check that at least one part of g1 touches at least one part of g2. + bool is_part_touches = false; + if (OB_FAIL((is_part_touches_gc_other( + mpt1, mls1, mpy1, g2, context, is_part_touches)))) { + LOG_WARN("fail to do is part touches gc other", K(ret)); + } else if (!is_part_touches) { + result = false; + } else if (OB_FAIL((is_part_joint_gc_other_geog( + mpt1, mls1, mpy1, g1, g2, context, result)))) { + LOG_WARN("fail to eval is part joint", K(ret)); + } + } + } else if (g2->type() == ObGeoType::GEOMETRYCOLLECTION) { + ret = eval_touches_gc_other_geog(g2, g1, context, result); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("g1 and g2 are not geometry collection", K(ret), K(g1->type()), K(g2->type())); + } + return ret; + } + + // assume that g1 g2 both collection + template + static int eval_touches_gc_gc( + const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, bool &result) + { + int ret = OB_SUCCESS; + if (g1->type() != ObGeoType::GEOMETRYCOLLECTION + || g2->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("g1 or g2 is not geometry collection", K(ret), K(g1->type()), K(g2->type())); + } else { + result = false; + typename GcTreeType::sub_mpt_type *mpt1 = NULL; + typename GcTreeType::sub_ml_type *mls1 = NULL; + typename GcTreeType::sub_mp_type *mpy1 = NULL; + ObGeometry *geo1 = const_cast(reinterpret_cast(g1)); + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo1, mpt1, mls1, mpy1))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt1) || OB_ISNULL(mls1) || OB_ISNULL(mpy1)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else { + typename GcTreeType::sub_mpt_type *mpt2 = NULL; + typename GcTreeType::sub_ml_type *mls2 = NULL; + typename GcTreeType::sub_mp_type *mpy2 = NULL; + ObGeometry *geo2 = const_cast(reinterpret_cast(g2)); + // Check that at least one part of g1 touches at least one part of g2. + bool is_part_touches = false; + bool is_part_joint = false; // Check that the interiors of g1 and g2 are disjoint. + if (OB_FAIL(ObGeoFuncUtils::ob_gc_prepare(context, geo2, mpt2, mls2, mpy2))) { + LOG_WARN("failed to prepare gc", K(ret)); + } else if (OB_ISNULL(mpt2) || OB_ISNULL(mls2) || OB_ISNULL(mpy2)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else if (!mpt1->is_empty() && mls1->is_empty() && mpy1->is_empty() && !mpt2->is_empty() + && mls2->is_empty() && mpy2->is_empty()) { + // MySQL return NULL, PG return false + result = false; + } else if (OB_FAIL((is_part_touches_gc_gc( + mpt1, mls1, mpy1, mpt2, mls2, mpy2, context, is_part_touches)))) { + LOG_WARN("fail to eval is part touches", K(ret)); + } else if (!is_part_touches) { + result = false; + } else if (OB_FAIL((is_part_joint_gc_gc( + mpt1, mls1, mpy1, mpt2, mls2, mpy2, context, is_part_joint)))) { + LOG_WARN("fail to eval is part joint", K(ret)); + } else { + result = !is_part_joint; + } + } + } + return ret; + } +}; + +//===========BIN GEOM========== +// Geom Point/MultiPoint: cartesian cases return false (PG) / NULL (MySQL) +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomPoint, ObWkbGeomPoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomPoint, ObWkbGeomMultiPoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomMultiPoint, ObWkbGeomPoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomMultiPoint, ObWkbGeomMultiPoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +// cartesian cases with eval_touches_mpt (MultiPoint) +OB_GEO_CART_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomMultiPoint, bool) +{ + return eval_touches_mpt( + g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomMultiPoint, bool) +{ + return eval_touches_mpt( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +// Geom Collection +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomCollection, ObWkbGeomCollection, bool) +{ + return eval_touches_gc_gc(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomCollection, bool) +{ + return eval_touches_gc_other_cart(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomCollection, bool) +{ + return eval_touches_gc_other_cart(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// handle ambiguous partial specializations +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomCollection, ObWkbGeomMultiPoint, bool) +{ + return eval_touches_gc_other_cart(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeomMultiPoint, ObWkbGeomCollection, bool) +{ + return eval_touches_gc_other_cart(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +//===========BIN GEOG========== +// handle ambiguous partial specializations +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogCollection, ObWkbGeogPoint, bool) +{ + return eval_touches_gc_other_geog(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogPoint, ObWkbGeogCollection, bool) +{ + return eval_touches_gc_other_geog(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// geometrycollection for geography +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogCollection, ObWkbGeogCollection, bool) +{ + return eval_touches_gc_gc(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogCollection, bool) +{ + return eval_touches_gc_other_geog(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogCollection, bool) +{ + return eval_touches_gc_other_geog(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// cases use eval_touches_mpt (multi point) +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogMultiPoint, ObWkbGeogPolygon, bool) +{ + return eval_touches_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPolygon, bool) +{ + return eval_touches_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogPolygon, ObWkbGeogMultiPoint, bool) +{ + return eval_touches_mpt( + g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObWkbGeogMultiPolygon, ObWkbGeogMultiPoint, bool) +{ + return eval_touches_mpt( + g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogMultiPoint, ObWkbGeogLineString, bool) +{ + return eval_touches_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogLineString, ObWkbGeogMultiPoint, bool) +{ + return eval_touches_mpt( + g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiLineString, bool) +{ + return eval_touches_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObWkbGeogMultiLineString, ObWkbGeogMultiPoint, bool) +{ + return eval_touches_mpt( + g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +// geograpyic cases return false (PG) / NULL (MySQL) +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogPoint, ObWkbGeogPoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogMultiPoint, ObWkbGeogMultiPoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogPoint, ObWkbGeogMultiPoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogMultiPoint, ObWkbGeogPoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +// geograpyic cases using point strategy (point and nonpoint types) +OB_GEO_GEOG_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogPoint, bool) +{ + return eval_touches_with_point_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncTouchesImpl, ObWkbGeogPoint, bool) +{ + return eval_touches_with_point_strategy(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +//============================Tree Cart(only Multi)======================== +// multipoint +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObCartesianMultipoint, ObCartesianMultipoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObCartesianMultipoint, ObCartesianMultipolygon, bool) +{ + return eval_touches_mpt( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObCartesianMultipoint, ObCartesianMultilinestring, bool) +{ + return eval_touches_mpt( + g1, g2, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +// multilinestring +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObCartesianMultilinestring, ObCartesianMultipoint, bool) +{ + return eval_touches_mpt( + g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObCartesianMultilinestring, ObCartesianMultipolygon, bool) +{ + UNUSED(context); + return eval_touches_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObCartesianMultilinestring, ObCartesianMultilinestring, bool) +{ + UNUSED(context); + return eval_touches_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +// multipolygon +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObCartesianMultipolygon, ObCartesianMultipoint, bool) +{ + return eval_touches_mpt( + g2, g1, context, ObBGStrategyType::DEFAULT_NONE, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObCartesianMultipolygon, ObCartesianMultipolygon, bool) +{ + UNUSED(context); + return eval_touches_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObCartesianMultipolygon, ObCartesianMultilinestring, bool) +{ + UNUSED(context); + return eval_touches_without_strategy( + g1, g2, result); +} +OB_GEO_FUNC_END; + +//============================Tree Geog(only Multi)======================== +// multipoint +OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncTouchesImpl, ObGeographMultipoint, ObGeographMultipoint, bool) +{ + UNUSEDx(g1, g2, context); + result = false; + return OB_SUCCESS; +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObGeographMultipoint, ObGeographMultipolygon, bool) +{ + return eval_touches_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObGeographMultipoint, ObGeographMultilinestring, bool) +{ + return eval_touches_mpt( + g1, g2, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +// multilinestring +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObGeographMultilinestring, ObGeographMultipoint, bool) +{ + return eval_touches_mpt( + g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObGeographMultilinestring, ObGeographMultipolygon, bool) +{ + return eval_touches_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObGeographMultilinestring, ObGeographMultilinestring, bool) +{ + return eval_touches_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +// multipolygon +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObGeographMultipolygon, ObGeographMultipoint, bool) +{ + return eval_touches_mpt( + g2, g1, context, ObBGStrategyType::PL_PA_STRATEGY, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObGeographMultipolygon, ObGeographMultipolygon, bool) +{ + return eval_touches_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_TREE_FUNC_BEGIN( + ObGeoFuncTouchesImpl, ObGeographMultipolygon, ObGeographMultilinestring, bool) +{ + return eval_touches_with_nonpoint_strategy( + g1, g2, context, result); +} +OB_GEO_FUNC_END; + +int ObGeoFuncTouches::eval(const ObGeoEvalCtx &gis_context, bool &result) +{ + return ObGeoFuncTouchesImpl::eval_geo_func(gis_context, result); +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_touches.h b/deps/oblib/src/lib/geo/ob_geo_func_touches.h new file mode 100644 index 0000000000..f4cdc8d10c --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_func_touches.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for ob_geo_func_touches. + */ + +#ifndef OCEANBASE_LIB_OB_GEO_FUNC_TOUCHES_ +#define OCEANBASE_LIB_OB_GEO_FUNC_TOUCHES_ + +#include "lib/geo/ob_geo_func_common.h" + +namespace oceanbase +{ +namespace common +{ +class ObGeoFuncTouches +{ +public: + ObGeoFuncTouches(); + virtual ~ObGeoFuncTouches() = default; + static int eval(const common::ObGeoEvalCtx &gis_context, bool &result); +}; + +} // namespace common +} // namespace oceanbase +#endif // OCEANBASE_LIB_OB_GEO_FUNC_TOUCHES_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_transform.cpp b/deps/oblib/src/lib/geo/ob_geo_func_transform.cpp index ca27f39087..7b9e489f97 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_transform.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_transform.cpp @@ -43,9 +43,12 @@ private: static int apply_bg_transform_point(const ObGeometry *g, const ObGeoEvalCtx &context, ObGeometry *&result) { int ret = OB_SUCCESS; + lib::ObMemAttr last_mem_attr = lib::ObMallocHookAttrGuard::get_tl_mem_attr(); + lib::ObMallocHookAttrGuard tmp_500(lib::ObMemAttr(OB_SERVER_TENANT_ID, "BoostCache")); boost::geometry::srs::proj4 src_proj4(context.get_val_arg(0)->string_->ptr()); boost::geometry::srs::proj4 dest_proj4(context.get_val_arg(1)->string_->ptr()); boost::geometry::srs::transformation<> transformer(src_proj4, dest_proj4); + lib::ObMallocHookAttrGuard malloc_guard(last_mem_attr); const PtInType *src_geo = reinterpret_cast(g->val()); PtResType *dest_geo = NULL; if (OB_ISNULL(dest_geo = OB_NEWx(PtResType, (context.get_allocator())))) { @@ -78,9 +81,12 @@ private: ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create geo by type", K(ret)); } else { + lib::ObMemAttr last_mem_attr = lib::ObMallocHookAttrGuard::get_tl_mem_attr(); + lib::ObMallocHookAttrGuard tmp_500(lib::ObMemAttr(OB_SERVER_TENANT_ID, "BoostCache")); boost::geometry::srs::proj4 src_proj4(context.get_val_arg(0)->string_->ptr()); boost::geometry::srs::proj4 dest_proj4(context.get_val_arg(1)->string_->ptr()); boost::geometry::srs::transformation<> transformer(src_proj4, dest_proj4); + lib::ObMallocHookAttrGuard malloc_guard(last_mem_attr); const GeometryInType *src_geo = reinterpret_cast(g->val()); transformer.forward(*src_geo, *dest_geo); result = dest_geo; diff --git a/deps/oblib/src/lib/geo/ob_geo_func_union.cpp b/deps/oblib/src/lib/geo/ob_geo_func_union.cpp index 88df23efa0..07f95fd801 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_union.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_union.cpp @@ -18,6 +18,8 @@ #include "lib/geo/ob_geo_tree.h" #include "lib/geo/ob_geo_to_tree_visitor.h" #include "lib/oblog/ob_log_module.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_func_utils.h" using namespace oceanbase::common; namespace oceanbase @@ -25,13 +27,6 @@ namespace oceanbase namespace common { -enum class ObBGStrategyType -{ - DEFAULT_NONE = 0, - PL_PA_STRATEGY, - LL_LA_AA_STRATEGY, -}; - template static void apply_bg_union_inner(const GeometryType1 *geo1, const GeometryType2 *geo2, const ObGeoEvalCtx &context, ObGeographMultilinestring *res) @@ -64,7 +59,7 @@ template static int apply_bg_union(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) { INIT_SUCC(ret); - GeometryRes *res = OB_NEWx(GeometryRes, context.get_allocator()); + GeometryRes *res = OB_NEWx(GeometryRes, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(res)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -133,7 +128,7 @@ template get_srid(), *context.get_allocator()); if (OB_ISNULL(res)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -169,7 +164,7 @@ template get_srid(), *context.get_allocator()); if (OB_ISNULL(res)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -211,7 +206,7 @@ static int apply_bg_diff_union_collection(const ObGeometry *g1, const ObGeometry INIT_SUCC(ret); GeometryRes *res = NULL; - GeometryDiffType *diff_geo = OB_NEWx(GeometryDiffType, context.get_allocator()); + GeometryDiffType *diff_geo = OB_NEWx(GeometryDiffType, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(diff_geo)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -219,7 +214,7 @@ static int apply_bg_diff_union_collection(const ObGeometry *g1, const ObGeometry const GeometryType1 *geo1 = reinterpret_cast(g1->val()); const GeometryType2 *geo2 = reinterpret_cast(g2->val()); apply_bg_difference(geo1, geo2, context, diff_geo); - res = OB_NEWx(GeometryRes, context.get_allocator()); + res = OB_NEWx(GeometryRes, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(res)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -288,7 +283,7 @@ static int apply_bg_union_multiline_multipolygon(const ObGeometry *g1, const ObG { INIT_SUCC(ret); GeometryRes *res = NULL; - GeometryDiffType *diff_geo = OB_NEWx(GeometryDiffType, context.get_allocator()); + GeometryDiffType *diff_geo = OB_NEWx(GeometryDiffType, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(diff_geo)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -296,7 +291,7 @@ static int apply_bg_union_multiline_multipolygon(const ObGeometry *g1, const ObG const GeometryType1 *geo1 = reinterpret_cast(g1->val()); const GeometryType2 *geo2 = reinterpret_cast(g2->val()); apply_bg_difference(geo1, geo2, context, diff_geo); - res = OB_NEWx(GeometryRes, context.get_allocator()); + res = OB_NEWx(GeometryRes, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(res)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -307,14 +302,20 @@ static int apply_bg_union_multiline_multipolygon(const ObGeometry *g1, const ObG LOG_WARN("failed to do geo visit", K(ret)); } else { GeometryTreeType2 *geo2_tree = static_cast(visitor.get_geometry()); - FOREACH_X(item, *geo2_tree, OB_SUCC(ret)) { - if (OB_FAIL(res->push_back(*item))) { + if (diff_geo->is_empty()) { + if (OB_FAIL(res->push_back(*geo2_tree))) { LOG_WARN("failed to add geo to collection", K(ret)); } - } - FOREACH_X(diff_item, *diff_geo, OB_SUCC(ret)) { - if (OB_FAIL(res->push_back(*diff_item))) { - LOG_WARN("failed to add geo to collection", K(ret)); + } else { + FOREACH_X(item, *geo2_tree, OB_SUCC(ret)) { + if (OB_FAIL(res->push_back(*item))) { + LOG_WARN("failed to add geo to collection", K(ret)); + } + } + FOREACH_X(diff_item, *diff_geo, OB_SUCC(ret)) { + if (OB_FAIL(res->push_back(*diff_item))) { + LOG_WARN("failed to add geo to collection", K(ret)); + } } } } @@ -332,7 +333,7 @@ static int apply_bg_union_multipoint_multigeo(const ObGeometry *g1, const ObGeom { INIT_SUCC(ret); GeometryRes *res = NULL; - GeometryDiffType *diff_geo = OB_NEWx(GeometryDiffType, context.get_allocator()); + GeometryDiffType *diff_geo = OB_NEWx(GeometryDiffType, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(diff_geo)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -340,7 +341,7 @@ static int apply_bg_union_multipoint_multigeo(const ObGeometry *g1, const ObGeom const GeometryType1 *geo1 = reinterpret_cast(g1->val()); const GeometryType2 *geo2 = reinterpret_cast(g2->val()); apply_bg_difference(geo1, geo2, context, diff_geo); - res = OB_NEWx(GeometryRes, context.get_allocator()); + res = OB_NEWx(GeometryRes, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(res)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -351,14 +352,20 @@ static int apply_bg_union_multipoint_multigeo(const ObGeometry *g1, const ObGeom LOG_WARN("failed to do geo visit", K(ret)); } else { GeometryTreeType2 *geo2_tree = static_cast(visitor.get_geometry()); - FOREACH_X(item, *geo2_tree, OB_SUCC(ret)) { - if (OB_FAIL(res->push_back(*item))) { + if (diff_geo->is_empty()) { + if (OB_FAIL(res->push_back(*geo2_tree))) { LOG_WARN("failed to add geo to collection", K(ret)); } - } - FOREACH_X(diff_item, *diff_geo, OB_SUCC(ret)) { - if (OB_FAIL(push_back_innerpoint(*diff_item, context, *res))) { - LOG_WARN("failed to add geo to collection", K(ret)); + } else { + FOREACH_X(item, *geo2_tree, OB_SUCC(ret)) { + if (OB_FAIL(res->push_back(*item))) { + LOG_WARN("failed to add geo to collection", K(ret)); + } + } + FOREACH_X(diff_item, *diff_geo, OB_SUCC(ret)) { + if (OB_FAIL(push_back_innerpoint(*diff_item, context, *res))) { + LOG_WARN("failed to add geo to collection", K(ret)); + } } } } @@ -376,7 +383,7 @@ static int apply_bg_union_multipoint_geo(const ObGeometry *g1, const ObGeometry { INIT_SUCC(ret); GeometryRes *res = NULL; - GeometryDiffType *diff_geo = OB_NEWx(GeometryDiffType, context.get_allocator()); + GeometryDiffType *diff_geo = OB_NEWx(GeometryDiffType, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(diff_geo)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create geo by type", K(ret)); @@ -384,7 +391,7 @@ static int apply_bg_union_multipoint_geo(const ObGeometry *g1, const ObGeometry const GeometryType1 *geo1 = reinterpret_cast(g1->val()); const GeometryType2 *geo2 = reinterpret_cast(g2->val()); apply_bg_difference(geo1, geo2, context, diff_geo); - res = OB_NEWx(GeometryRes, context.get_allocator()); + res = OB_NEWx(GeometryRes, context.get_allocator(), g1->get_srid(), *context.get_allocator()); if (OB_ISNULL(res)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to create go by type", K(ret)); @@ -441,6 +448,91 @@ public: } }; + template + static int eval_unions_gc(const ObGeometry *g1, const ObGeometry *g2, const ObGeoEvalCtx &context, ObGeometry *&result) + { + int ret = OB_SUCCESS; + if (g1->type() != ObGeoType::GEOMETRYCOLLECTION && g2->type() != ObGeoType::GEOMETRYCOLLECTION) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("both g1 or g2 are not geometry collection", K(ret), K(g1->type()), K(g2->type())); + } else { + ObIAllocator *allocator = context.get_allocator(); + bool is_g1_empty = false; + bool is_g2_empty = false; + uint32_t srid = g1->get_srid(); + GcTreeType *res_coll = OB_NEWx(GcTreeType, allocator, srid, *allocator); + ObGeometry *geo1 = const_cast(g1); + ObGeometry *geo2 = const_cast(g2); + if (OB_ISNULL(res_coll)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failt alloc memory for geometry", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::check_empty(geo1, is_g1_empty))) { + LOG_WARN("fail to check is g1 empty", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::check_empty(geo2, is_g2_empty))) { + LOG_WARN("fail to check is g2 empty", K(ret)); + } else if (!is_g1_empty || !is_g2_empty) { + typename GcTreeType::sub_mpt_type *mpt = NULL; + typename GcTreeType::sub_ml_type *mls = NULL; + typename GcTreeType::sub_mp_type *mpy = NULL; + ObGeoToTreeVisitor tree_visitor1(allocator); + ObGeoToTreeVisitor tree_visitor2(allocator); + GcTreeType *geo_coll = OB_NEWx(GcTreeType, allocator, srid, *allocator); + ObGeometry *g1_tree = nullptr; + ObGeometry *g2_tree = nullptr; + if (OB_ISNULL(geo_coll)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failt alloc memory for geometry", K(ret)); + } else if (OB_FAIL(geo1->do_visit(tree_visitor1))) { + LOG_WARN("fail to do visit", K(ret)); + } else if (FALSE_IT(g1_tree = tree_visitor1.get_geometry())) { + } else if (OB_FAIL(geo_coll->push_back(*g1_tree))) { + LOG_WARN("fail to push back geometry", K(ret)); + } else if (OB_FAIL(geo2->do_visit(tree_visitor2))) { + LOG_WARN("fail to do visit", K(ret)); + } else if (FALSE_IT(g2_tree = tree_visitor2.get_geometry())) { + } else if (OB_FAIL(geo_coll->push_back(*g2_tree))) { + LOG_WARN("fail to push back geometry", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_split(*allocator, *geo_coll, mpt, mls, mpy))) { + LOG_WARN("failed to do gc split", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_union(*allocator, *context.get_srs(), mpt, mls, mpy))) { + LOG_WARN("failed to do gc union", K(ret)); + } else { + for (int i = 0; OB_SUCC(ret) && i < mpy->size(); ++i) { + if (OB_FAIL( + res_coll->push_back(reinterpret_cast((*mpy)[i])))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + for (int i = 0; OB_SUCC(ret) && i < mls->size(); ++i) { + if (OB_FAIL( + res_coll->push_back(reinterpret_cast((*mls)[i])))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + for (int i = 0; OB_SUCC(ret) && i < mpt->size(); ++i) { + typename GcTreeType::sub_mpt_type::value_type &pt = (*mpt)[i]; + PtType *pt_tree = OB_NEWx(PtType, + allocator, + pt.template get<0>(), + pt.template get<1>(), + srid, + allocator); + if (OB_ISNULL(pt_tree)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret)); + } else if (OB_FAIL(res_coll->push_back( + reinterpret_cast(*pt_tree)))) { + LOG_WARN("fail to push back geometry", K(ret)); + } + } + } + } + if (OB_SUCC(ret)) { + result = res_coll; + } + } + return ret; + } }; // cartesian point @@ -606,7 +698,7 @@ OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeomMultiLineString, ObWk OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeomMultiLineString, ObWkbGeomLineString, ObGeometry *) { - return apply_bg_union(g2, g1, context, result); + return apply_bg_union(g2, g1, context, result); } OB_GEO_FUNC_END; OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeomMultiLineString, ObWkbGeomPolygon, ObGeometry *) @@ -674,6 +766,25 @@ OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeomMultiPolygon, ObWkbGe return apply_bg_union(g1, g2, context, result); } OB_GEO_FUNC_END; +// cartisian collection +OB_GEO_CART_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeomCollection, ObWkbGeomCollection, ObGeometry *) +{ + return eval_unions_gc(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncUnionImpl, ObWkbGeomCollection, ObGeometry *) +{ + return eval_unions_gc(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_CART_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncUnionImpl, ObWkbGeomCollection, ObGeometry *) +{ + return eval_unions_gc(g1, g2, context, result); +} +OB_GEO_FUNC_END; + // geographic point OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeogPoint, ObWkbGeogPoint, ObGeometry *) { @@ -837,7 +948,7 @@ OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeogMultiLineString, ObWk OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeogMultiLineString, ObWkbGeogLineString, ObGeometry *) { - return apply_bg_union(g2, g1, context, result); + return apply_bg_union(g2, g1, context, result); } OB_GEO_FUNC_END; OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeogMultiLineString, ObWkbGeogPolygon, ObGeometry *) @@ -905,6 +1016,26 @@ OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeogMultiPolygon, ObWkbGe return apply_bg_union(g1, g2, context, result); } OB_GEO_FUNC_END; +// geograph collection +OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncUnionImpl, ObWkbGeogCollection, ObWkbGeogCollection, ObGeometry *) +{ + return eval_unions_gc(g1, g2, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO2_BEGIN(ObGeoFuncUnionImpl, ObWkbGeogCollection, ObGeometry *) +{ + return eval_unions_gc(g2, g1, context, result); +} +OB_GEO_FUNC_END; + +OB_GEO_GEOG_BINARY_FUNC_GEO1_BEGIN(ObGeoFuncUnionImpl, ObWkbGeogCollection, ObGeometry *) +{ + return eval_unions_gc(g1, g2, context, result); +} +OB_GEO_FUNC_END; + + // tree cartesian polygon OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncUnionImpl, ObCartesianPolygon, ObCartesianPolygon, ObGeometry *) { @@ -921,6 +1052,11 @@ OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncUnionImpl, ObCartesianMultipolygon, ObCarte return apply_bg_union(g1, g2, context, result); } OB_GEO_FUNC_END; +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncUnionImpl, ObCartesianMultipolygon, ObCartesianPolygon, ObGeometry *) +{ + return apply_bg_union(g2, g1, context, result); +} OB_GEO_FUNC_END; + // tree geograph polygon OB_GEO_GEOG_TREE_FUNC_BEGIN(ObGeoFuncUnionImpl, ObGeographPolygon, ObGeographPolygon, ObGeometry *) { diff --git a/deps/oblib/src/lib/geo/ob_geo_func_utils.cpp b/deps/oblib/src/lib/geo/ob_geo_func_utils.cpp index 854dcea3fa..0f2cf8e656 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_utils.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_utils.cpp @@ -24,6 +24,18 @@ namespace oceanbase namespace common { +int ObGeoFuncUtils::apply_bg_to_tree(const ObGeometry *g1, const ObGeoEvalCtx &context, ObGeometry *&result) +{ + INIT_SUCC(ret); + ObGeoToTreeVisitor geom_visitor(context.get_allocator()); + ObGeometry *geo1 = const_cast(g1); + if (OB_FAIL(geo1->do_visit(geom_visitor))) { + LOG_WARN("failed to convert bin to tree", K(ret)); + } else { + result = geom_visitor.get_geometry(); + } + return ret; +} } // sql } // oceanbase diff --git a/deps/oblib/src/lib/geo/ob_geo_func_utils.h b/deps/oblib/src/lib/geo/ob_geo_func_utils.h index 289f85022f..d85627a0a0 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_utils.h +++ b/deps/oblib/src/lib/geo/ob_geo_func_utils.h @@ -23,6 +23,11 @@ namespace oceanbase { namespace common { +enum class ObBGStrategyType { + DEFAULT_NONE = 0, + PL_PA_STRATEGY, + LL_LA_AA_STRATEGY, +}; class ObGeoFuncUtils { @@ -51,12 +56,22 @@ public: typename GcTreeType::sub_ml_type *&multi_line, typename GcTreeType::sub_mp_type *&multi_poly); + static int apply_bg_to_tree(const ObGeometry *g1, const ObGeoEvalCtx &context, ObGeometry *&result); + template + static int remove_duplicate_multi_geo(ObGeometry *&geo, common::ObIAllocator &allocator, const ObSrsItem *srs); + template + static int simplify_geo_collection(ObGeometry *&geo, common::ObIAllocator &allocator, const ObSrsItem *srs); + template + static int simplify_multi_geo(ObGeometry *&geo, common::ObIAllocator &allocator); + private: template static int ob_geo_gc_split_inner(const GcTreeType &gc, typename GcTreeType::sub_mpt_type &mpt, typename GcTreeType::sub_ml_type &ml, typename GcTreeType::sub_mp_type &mpo); + template + static int is_in_geometry(const ObGeometry &geo, const MpType &multi_geo, const ObSrsItem *srs, bool &res); }; template @@ -198,12 +213,21 @@ int ObGeoFuncUtils::ob_gc_prepare(const ObGeoEvalCtx &context, INIT_SUCC(ret); ObIAllocator *allocator = context.get_allocator(); const ObSrsItem *srs = context.get_srs(); - ObGeoToTreeVisitor tree_visitor(allocator); + const GcTreeType *gc_tree = nullptr; + if (gc->is_tree()) { + gc_tree = static_cast(gc); + } else { + ObGeoToTreeVisitor tree_visitor(allocator); + if (OB_FAIL(gc->do_visit(tree_visitor))) { + OB_LOG(WARN, "failed to transform gc to tree", K(ret)); + } else { + gc_tree = static_cast(tree_visitor.get_geometry()); + } + } - if (OB_FAIL(gc->do_visit(tree_visitor))) { - OB_LOG(WARN, "failed to transform gc to tree", K(ret)); + if (OB_FAIL(ret)) { } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_split(*allocator, - *static_cast(tree_visitor.get_geometry()), + *gc_tree, multi_point, multi_line, multi_poly))) { OB_LOG(WARN, "failed to do gc split", K(ret)); } else if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_union(*allocator, *srs, multi_point, @@ -296,6 +320,281 @@ int ObGeoFuncUtils::ob_geo_gc_split_inner(const GcTreeType &gc, return ret; } +template +int ObGeoFuncUtils::is_in_geometry(const ObGeometry &geo, const MpType &multi_geo, const ObSrsItem *srs, bool &res) +{ + int ret = OB_SUCCESS; + ObArenaAllocator temp_allocator; + for (int32_t j = 0; j < multi_geo.size() && OB_SUCC(ret) && !res; j++) { + ObGeoEvalCtx gis_context(&temp_allocator, srs); + if (OB_FAIL(gis_context.append_geo_arg(&geo)) || OB_FAIL(gis_context.append_geo_arg(&multi_geo[j]))) { + OB_LOG(WARN, "build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, res))) { + OB_LOG(WARN, "eval st intersection failed", K(ret)); + } + } + return ret; +} + +template +int ObGeoFuncUtils::simplify_multi_geo(ObGeometry *&geo, common::ObIAllocator &allocator) +{ + // e.g. MULTILINESTRING((0 0, 1 1)) -> LINESTRING(0 0, 1 1) + int ret= OB_SUCCESS; + switch (geo->type()) { + case ObGeoType::MULTILINESTRING: { + typename GcType::sub_ml_type *mp = reinterpret_cast(geo); + if (OB_ISNULL(mp)) { + ret = OB_ERR_GIS_INVALID_DATA; + OB_LOG(WARN, "invalid null pointer", K(ret)); + } else if (mp->size() == 1) { + geo = &(mp->front()); + } + break; + } + case ObGeoType::MULTIPOINT: { + typename GcType::sub_mpt_type *mpt = reinterpret_cast(geo); + if (OB_ISNULL(mpt)) { + ret = OB_ERR_GIS_INVALID_DATA; + OB_LOG(WARN, "invalid null pointer", K(ret)); + } else if (mpt->size() == 1) { + typename GcType::sub_pt_type *p = OB_NEWx(typename GcType::sub_pt_type, &allocator); + if (OB_ISNULL(p)) { + ret = OB_ERR_GIS_INVALID_DATA; + OB_LOG(WARN, "invalid null pointer", K(ret)); + } else { + p->set_data(mpt->front()); + geo = p; + } + } + break; + } + case ObGeoType::MULTIPOLYGON: { + typename GcType::sub_mp_type *mp = reinterpret_cast(geo); + if (OB_ISNULL(mp)) { + ret = OB_ERR_GIS_INVALID_DATA; + OB_LOG(WARN, "invalid null pointer", K(ret)); + } else if (mp->size() == 1) { + geo = &(mp->front()); + } + break; + } + case ObGeoType::GEOMETRYCOLLECTION: { + GcType *mp = reinterpret_cast(geo); + if (OB_ISNULL(mp)) { + ret = OB_ERR_GIS_INVALID_DATA; + OB_LOG(WARN, "invalid null pointer", K(ret)); + } else if (mp->size() == 1) { + geo = &(mp->front()); + if (OB_FAIL((simplify_multi_geo(geo, allocator)))) { + OB_LOG(WARN, "fail to simplify geometry", K(ret)); + } + } + break; + } + default: { + break; // do nothing + } + } + return ret; +} + +// for geo tree +template +int ObGeoFuncUtils::simplify_geo_collection(ObGeometry *&geo, common::ObIAllocator &allocator, const ObSrsItem *srs) +{ + int ret = OB_SUCCESS; + if (geo->type() != ObGeoType::GEOMETRYCOLLECTION) { + // do nothing + } else { + GcTreeType *&geo_coll = reinterpret_cast(geo); + ObGeoType front_type; + bool need_simplify = true; + if (geo_coll->size() < 2) { + need_simplify = false; + } else { + front_type = geo_coll->front().type(); + for (uint32_t i = 1; need_simplify && i < geo_coll->size(); ++i) { + if (((*geo_coll)[i]).type() != front_type) { + need_simplify = false; + } + } + } + if (need_simplify) { + switch(front_type) { + case ObGeoType::POINT: { + typename GcTreeType::sub_mpt_type *res_geo = OB_NEWx(typename GcTreeType::sub_mpt_type, &allocator, geo->get_srid(), allocator); + if (OB_ISNULL(res_geo)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to alloc memory", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < geo_coll->size(); ++i) { + typename GcTreeType::sub_pt_type &geo_point = reinterpret_cast((*geo_coll)[i]); + if (OB_FAIL(res_geo->push_back(geo_point))) { + OB_LOG(WARN, "failed to add point to multipoint", K(ret)); + } + } + if (OB_SUCC(ret)) { + geo = res_geo; + } + break; + } + case ObGeoType::LINESTRING: { + typename GcTreeType::sub_ml_type *res_geo = OB_NEWx(typename GcTreeType::sub_ml_type, &allocator, geo->get_srid(), allocator); + if (OB_ISNULL(res_geo)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to alloc memory", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < geo_coll->size(); ++i) { + if (OB_FAIL(res_geo->push_back((*geo_coll)[i]))) { + OB_LOG(WARN, "failed to add linestring to multilinestring", K(ret)); + } + } + if (OB_SUCC(ret)) { + geo = res_geo; + } + break; + } + case ObGeoType::POLYGON: { + typename GcTreeType::sub_mp_type *res_geo = OB_NEWx(typename GcTreeType::sub_mp_type, &allocator, geo->get_srid(), allocator); + if (OB_ISNULL(res_geo)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "fail to alloc memory", K(ret)); + } + for (uint32_t i = 0; OB_SUCC(ret) && i < geo_coll->size(); ++i) { + if (OB_FAIL(res_geo->push_back((*geo_coll)[i]))) { + OB_LOG(WARN, "failed to add polygon to multipolygon", K(ret)); + } + } + if (OB_SUCC(ret)) { + geo = res_geo; + } + break; + } + default: { + // do nothing + break; + } + } + } + } + return ret; +} + +// for geo tree +template +int ObGeoFuncUtils::remove_duplicate_multi_geo(ObGeometry *&geo, common::ObIAllocator &allocator, const ObSrsItem *srs) +{ + int ret = OB_SUCCESS; + ObArenaAllocator temp_allocator; + switch (geo->type()) { + case ObGeoType::POINT: + case ObGeoType::LINESTRING: + case ObGeoType::POLYGON: { + break; + } + case ObGeoType::MULTIPOINT: { + typename GcTreeType::sub_mpt_type *res_geo = OB_NEWx(typename GcTreeType::sub_mpt_type, &allocator, geo->get_srid(), allocator); + typename GcTreeType::sub_mpt_type &sp_geo = reinterpret_cast(*geo); + if (OB_ISNULL(res_geo)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "failt to allocate memory for geometry", K(ret), K(geo->type())); + } + for (int32_t i = 0; i < sp_geo.size() && OB_SUCC(ret); i++) { + bool in_res_geo = false; + for (int32_t j = 0; j < res_geo->size() && OB_SUCC(ret) && !in_res_geo; j++) { + if ((sp_geo[i].template get<0>() == (*res_geo)[j].template get<0>()) + && (sp_geo[i].template get<1>() == (*res_geo)[j].template get<1>())) { + in_res_geo = true; + } + } + if (OB_SUCC(ret) && !in_res_geo) { + typename GcTreeType::sub_pt_type pt(sp_geo[i].template get<0>(), sp_geo[i].template get<1>()); + if (OB_FAIL(res_geo->push_back(pt))) { + OB_LOG(WARN, "fail to push back geometry", K(ret)); + } + } + } + if (OB_SUCC(ret)) { + geo = res_geo; + } + break; + } + case ObGeoType::MULTILINESTRING: { + typename GcTreeType::sub_ml_type *res_geo = OB_NEWx(typename GcTreeType::sub_ml_type, &allocator, geo->get_srid(), allocator); + typename GcTreeType::sub_ml_type &sp_geo = reinterpret_cast(*geo); + if (OB_ISNULL(res_geo)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "failt to allocate memory for geometry", K(ret), K(geo->type())); + } + for (int32_t i = 0; i < sp_geo.size() && OB_SUCC(ret); i++) { + bool in_res_geo = false; + if (OB_FAIL(is_in_geometry(sp_geo[i], *res_geo, srs, in_res_geo))) { + OB_LOG(WARN, "fail to check is in geometry", K(ret)); + } else if (!in_res_geo && res_geo->push_back(sp_geo[i])) { + OB_LOG(WARN, "fail to push back geometry", K(ret)); + } + } + if (OB_SUCC(ret)) { + geo = res_geo; + } + break; + } + case ObGeoType::MULTIPOLYGON: { + typename GcTreeType::sub_mp_type *res_geo = OB_NEWx(typename GcTreeType::sub_mp_type, &allocator, geo->get_srid(), allocator); + typename GcTreeType::sub_mp_type &sp_geo = reinterpret_cast(*geo); + if (OB_ISNULL(res_geo)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "failt to allocate memory for geometry", K(ret), K(geo->type())); + } + for (int32_t i = 0; i < sp_geo.size() && OB_SUCC(ret); i++) { + bool in_res_geo = false; + if (OB_FAIL(is_in_geometry(sp_geo[i], *res_geo, srs, in_res_geo))) { + OB_LOG(WARN, "fail to check is in geometry", K(ret)); + } else if (!in_res_geo && res_geo->push_back(sp_geo[i])) { + OB_LOG(WARN, "fail to push back geometry", K(ret)); + } + } + if (OB_SUCC(ret)) { + geo = res_geo; + } + break; + } + case ObGeoType::GEOMETRYCOLLECTION: { + GcTreeType *res_geo = OB_NEWx(GcTreeType, &allocator, geo->get_srid(), allocator); + GcTreeType *&sp_geo = reinterpret_cast(geo); + if (OB_ISNULL(res_geo)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + OB_LOG(WARN, "failt to allocate memory for geometry", K(ret), K(geo->type())); + } + for (int32_t i = 0; i < sp_geo->size() && OB_SUCC(ret); i++) { + bool in_res_geo = false; + ObGeometry *cur_geo = &(*sp_geo)[i]; + if (OB_FAIL(remove_duplicate_multi_geo(cur_geo, allocator, srs))) { + OB_LOG(WARN, "fail to remove dupilicate multi geometry", K(ret)); + } else if (OB_FAIL(is_in_geometry(*cur_geo, *res_geo, srs, in_res_geo))) { + OB_LOG(WARN, "fail to check is in geometry", K(ret)); + } else if (!in_res_geo && res_geo->push_back(*cur_geo)) { + OB_LOG(WARN, "fail to push back geometry", K(ret)); + } + } + if (OB_SUCC(ret)) { + geo = res_geo; + } + break; + } + default: { + ret = OB_NOT_SUPPORTED; + OB_LOG(WARN, "geometry type not supported", K(ret), K(geo->type())); + break; + } + } + + if (OB_SUCC(ret) && OB_FAIL((simplify_multi_geo(geo, allocator)))) { + OB_LOG(WARN, "fail to simplify result", K(ret)); + } + return ret; +} } // sql } // oceanbase #endif // OCEANBASE_LIB_OB_GEO_FUNC_UTILS_H_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_func_within.cpp b/deps/oblib/src/lib/geo/ob_geo_func_within.cpp index 76b9d60181..0dd7ca5b75 100644 --- a/deps/oblib/src/lib/geo/ob_geo_func_within.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_func_within.cpp @@ -85,10 +85,23 @@ static int apply_bg_within(const ObGeometry *g1, bool &result) { UNUSED(context); - const GeoType1 *geo1 = reinterpret_cast(g1->val()); - const GeoType2 *geo2 = reinterpret_cast(g2->val()); - result = bg::within(*geo1, *geo2); - return OB_SUCCESS; + int ret = OB_SUCCESS; + const GeoType1 *geo1 = nullptr; + const GeoType2 *geo2 = nullptr; + if (!g1->is_tree()) { + geo1 = reinterpret_cast(g1->val()); + geo2 = reinterpret_cast(g2->val()); + } else { + geo1 = reinterpret_cast(const_cast(g1)); + geo2 = reinterpret_cast(const_cast(g2)); + } + if (OB_ISNULL(geo1) || OB_ISNULL(geo2)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("geometry can not be null", K(ret), K(geo1), K(geo2)); + } else { + result = bg::within(*geo1, *geo2); + } + return ret; } template @@ -1578,6 +1591,11 @@ OB_GEO_GEOG_BINARY_FUNC_BEGIN(ObGeoFuncWithinImpl, ObWkbGeogCollection, ObWkbGeo return ret; } OB_GEO_FUNC_END; +OB_GEO_CART_TREE_FUNC_BEGIN(ObGeoFuncWithinImpl, ObCartesianPoint, ObCartesianPolygon, bool) +{ + return apply_bg_within(g1, g2, context, result); +} OB_GEO_FUNC_END; + int ObGeoFuncWithin::eval(const ObGeoEvalCtx &gis_context, bool &result) { return ObGeoFuncWithinImpl::eval_geo_func(gis_context, result); diff --git a/deps/oblib/src/lib/geo/ob_geo_grid_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_grid_visitor.cpp new file mode 100644 index 0000000000..6109705b6a --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_grid_visitor.cpp @@ -0,0 +1,215 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "ob_geo_grid_visitor.h" +#include "lib/ob_errno.h" + +namespace oceanbase +{ +namespace common +{ +bool ObGeoGridVisitor::prepare(ObGeometry *geo) +{ + bool bret = true; + if (OB_ISNULL(geo) || !geo->is_tree() || OB_ISNULL(grid_)) { + bret = false; + } + reset_duplicate_point(); + return bret; +} + +bool ObGeoGridVisitor::is_duplicate_point(double x, double y) +{ + bool bret = false; + if (grid_->x_size > 0) { + if (!use_floor_) { + x = rint((x - grid_->x_ip) / grid_->x_size) * grid_->x_size + grid_->x_ip; + } else { + x = floor((x - grid_->x_ip) / grid_->x_size) * grid_->x_size + grid_->x_ip; + } + } + if (grid_->y_size > 0) { + if (!use_floor_) { + y = rint((y - grid_->y_ip) / grid_->y_size) * grid_->y_size + grid_->y_ip; + } else { + y = floor((y - grid_->y_ip) / grid_->y_size) * grid_->y_size + grid_->y_ip; + } + } + bool x_equals = fabs(x - last_x_) <= 1e-12; + bool y_equals = fabs(y - last_y_) <= 1e-12; + if ((std::isnan(last_x_) && std::isnan(last_y_)) || !x_equals || !y_equals) { + last_x_ = x; + last_y_ = y; + } else { + bret = true; + } + return bret; +} + +void ObGeoGridVisitor::reset_duplicate_point() +{ + last_x_ = NAN; + last_y_ = NAN; +} + +template +void ObGeoGridVisitor::point_visit(POINT *geo) +{ + if (!is_duplicate_point(geo->x(), geo->y())) { + geo->x(last_x_); + geo->y(last_y_); + } +} + +int ObGeoGridVisitor::visit(ObCartesianPoint *geo) +{ + point_visit(geo); + return OB_SUCCESS; +} + +template +void ObGeoGridVisitor::multi_point_visit(LINE &geo, int32_t min_point) +{ + int32_t valid_idx = 0; + int64_t sz = geo.size(); + for (int32_t i = 0; i < sz; ++i) { + if (!is_duplicate_point(geo[i].template get<0>(), geo[i].template get<1>())) { + geo[valid_idx].template set<0>(last_x_); + geo[valid_idx].template set<1>(last_y_); + ++valid_idx; + } + } + if (valid_idx < min_point) { + geo.clear(); + } else { + geo.resize(valid_idx); + } + reset_duplicate_point(); +} + +int ObGeoGridVisitor::visit(ObCartesianLineString *geo) +{ + multi_point_visit(*geo, LINESTRING_MIN_POINT); + return OB_SUCCESS; +} + +template +void ObGeoGridVisitor::polygon_visit(POLYGON &geo) +{ + if (geo.size() > 0) { + RING &ext_ring = geo.exterior_ring(); + multi_point_visit(ext_ring, RING_MIN_POINT); + if (ext_ring.empty()) { + // if ext ring is invalid, then total polygon is invalid + geo.interior_rings().clear(); + } else if (geo.inner_ring_size() > 0) { + uint64_t inner_sz = geo.inner_ring_size(); + int32_t valid_inner_ring = 0; + for (uint32_t i = 0; i < inner_sz; ++i) { + RING &inner_ring = geo.inner_ring(i); + multi_point_visit(inner_ring, RING_MIN_POINT); + if (!inner_ring.empty()) { + geo.interior_rings()[valid_inner_ring++] = inner_ring; + } + } + geo.interior_rings().resize(valid_inner_ring); + } + } +} + +int ObGeoGridVisitor::visit(ObCartesianPolygon *geo) +{ + polygon_visit(*geo); + return OB_SUCCESS; +} + +int ObGeoGridVisitor::visit(ObCartesianMultipoint *geo) +{ + multi_point_visit(*geo, 1); + return OB_SUCCESS; +} + +int ObGeoGridVisitor::visit(ObCartesianMultilinestring *geo) +{ + int32_t valid_line = 0; + ObCartesianMultilinestring &line = *geo; + uint64_t sz = line.size(); + for (int32_t i = 0; i < sz; ++i) { + multi_point_visit(line[i], LINESTRING_MIN_POINT); + if (line[i].size() != 0) { + if (valid_line != i) { + line[valid_line] = line[i]; + } + ++valid_line; + } + } + if (valid_line) { + line.resize(valid_line); + } else { + line.clear(); + } + return OB_SUCCESS; +} + +int ObGeoGridVisitor::visit(ObCartesianMultipolygon *geo) +{ + int32_t valid_poly = 0; + ObCartesianMultipolygon &poly = *geo; + uint64_t sz = poly.size(); + for (int32_t i = 0; i < sz; ++i) { + polygon_visit(poly[i]); + if (poly[i].size() != 0) { + if (valid_poly != i) { + poly[valid_poly] = poly[i]; + } + ++valid_poly; + } + } + if (valid_poly) { + poly.resize(valid_poly); + } else { + poly.clear(); + } + return OB_SUCCESS; +} + +int ObGeoGridVisitor::visit(ObCartesianGeometrycollection *geo) +{ + int ret = OB_SUCCESS; + int32_t valid_geo = 0; + for (int32_t i = 0; i < geo->size() && OB_SUCC(ret); i++) { + if (OB_FAIL((*geo)[i].do_visit(*this))) { + LOG_WARN("failed to do tree item visit", K(ret)); + } else if (!(*geo)[i].is_empty()) { + if (valid_geo != i) { + (*geo)[valid_geo] = (*geo)[i]; + } + ++valid_geo; + } + } + if (valid_geo) { + geo->resize(valid_geo); + } else { + geo->clear(); + } + return ret; +} + +int ObGeoGridVisitor::finish(ObGeometry *geo) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_grid_visitor.h b/deps/oblib/src/lib/geo/ob_geo_grid_visitor.h new file mode 100644 index 0000000000..e7844157ec --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_grid_visitor.h @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_GEO_GRID_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_GEO_GRID_VISITOR_ +#include "lib/geo/ob_geo_visitor.h" +#include "lib/geo/ob_geo_common.h" +#include "lib/geo/ob_geo_utils.h" + +namespace oceanbase +{ +namespace common +{ +class ObGeoGridVisitor : public ObEmptyGeoVisitor +{ +public: + explicit ObGeoGridVisitor(const ObGeoGrid *grid, bool use_floor = false) + : last_x_(NAN), + last_y_(NAN), + grid_(grid), + use_floor_(use_floor) + {} + + virtual ~ObGeoGridVisitor() { } + + bool prepare(ObGeometry *geo) override; + // wkb + int visit(ObCartesianPoint *geo) override; + int visit(ObCartesianLineString *geo) override; + int visit(ObCartesianPolygon *geo) override; + int visit(ObCartesianMultipoint *geo) override; + int visit(ObCartesianMultilinestring *geo) override; + int visit(ObCartesianMultipolygon *geo) override; + int visit(ObCartesianGeometrycollection *geo) override; + + bool is_end(ObCartesianLineString *geo) override { UNUSED(geo); return true; } + bool is_end(ObCartesianPolygon *geo) override { UNUSED(geo); return true; } + bool is_end(ObCartesianMultipoint *geo) override { UNUSED(geo); return true; } + bool is_end(ObCartesianMultilinestring *geo) override { UNUSED(geo); return true; } + bool is_end(ObCartesianMultipolygon *geo) override { UNUSED(geo); return true; } + bool is_end(ObCartesianGeometrycollection *geo) override { UNUSED(geo); return true; } + + int finish(ObGeometry *geo) override; +private: + static const uint32_t RING_MIN_POINT = 4; + static const uint32_t LINESTRING_MIN_POINT = 2; + + template + void polygon_visit(POLYGON &geo); + template + void multi_point_visit(LINE &geo, int32_t min_point); + template + void point_visit(POINT *geo); + bool is_duplicate_point(double x, double y); + void reset_duplicate_point(); + + double last_x_; + double last_y_; + const ObGeoGrid *grid_; + bool use_floor_; + + DISALLOW_COPY_AND_ASSIGN(ObGeoGridVisitor); +}; +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_ibin.cpp b/deps/oblib/src/lib/geo/ob_geo_ibin.cpp index a7dde3c53c..1e19ad4826 100644 --- a/deps/oblib/src/lib/geo/ob_geo_ibin.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_ibin.cpp @@ -91,7 +91,7 @@ void ObIWkbGeomPoint::y(double d) bool ObIWkbGeomPolygon::is_empty_inner() const { const ObWkbGeomPolygon* poly = reinterpret_cast(val()); - return (poly->exterior_ring().size() == 0) && (poly->inner_rings().size() == 0); + return (poly->exterior_ring().size(static_cast(poly->get_bo())) == 0) && (poly->inner_rings().size() == 0); } int ObIWkbGeomCollection::get_sub(uint32_t idx, ObGeometry*& geo) const @@ -189,7 +189,7 @@ bool ObIWkbGeogPolygon::is_empty_inner() const const ObWkbGeogPolygon* poly = reinterpret_cast(val()); bool bret = true; if (OB_NOT_NULL(poly)) { - bret = (poly->exterior_ring().size() == 0) && (poly->inner_rings().size() == 0); + bret = (poly->exterior_ring().size(static_cast(poly->get_bo())) == 0) && (poly->inner_rings().size() == 0); } return bret; } diff --git a/deps/oblib/src/lib/geo/ob_geo_interior_point_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_interior_point_visitor.cpp new file mode 100644 index 0000000000..cd678e86a4 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_interior_point_visitor.cpp @@ -0,0 +1,468 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ +#define USING_LOG_PREFIX LIB +#include "lib/ob_errno.h" +#include "ob_geo_interior_point_visitor.h" +#include "ob_srs_info.h" +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_utils.h" + +namespace oceanbase +{ +namespace common +{ +int ObGeoInteriorPointVisitor::init(ObGeometry *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObGeoTypeUtil::check_empty(geo, is_geo_empty_))) { + LOG_WARN("fail to check geometry is empty", K(ret)); + } else { + ObGeoEvalCtx centroid_context(allocator_); + ObGeometry *res_geo = nullptr; + if (OB_FAIL(centroid_context.append_geo_arg(geo))) { + LOG_WARN("build geo gis context failed", K(ret)); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(centroid_context, res_geo))) { + if (ret == OB_ERR_BOOST_GEOMETRY_CENTROID_EXCEPTION) { + exist_centroid_ = false; + ret = OB_SUCCESS; + } else { + LOG_WARN("eval geo centroid failed", K(ret)); + } + } else { + centroid_pt_ = reinterpret_cast(res_geo); + } + } + + if (OB_SUCC(ret)) { + is_inited_ = true; + } + return ret; +} + +// support ObWkbGeomPoint/ObWkbGeomInnerPoint +template +double ObGeoInteriorPointVisitor::calculate_euclidean_distance(ObCartesianPoint &p1, PointType &p2) +{ + double x_dist = p1.x() - p2.template get<0>(); + double y_dist = p1.y() - p2.template get<1>(); + return sqrt(x_dist * x_dist + y_dist * y_dist); +} + +int ObGeoInteriorPointVisitor::assign_interior_point(double x, double y) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(interior_point_)) { + if (OB_ISNULL(interior_point_ = OB_NEWx(ObCartesianPoint, allocator_, x, y, srid_, allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for collection", K(ret)); + } + } else { + interior_point_->x(x); + interior_point_->y(y); + } + + return ret; +} + +int ObGeoInteriorPointVisitor::assign_interior_endpoint(double x, double y) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(interior_endpoint_)) { + if (OB_ISNULL(interior_endpoint_ = OB_NEWx(ObCartesianPoint, allocator_, x, y, srid_, allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for collection", K(ret)); + } + } else { + interior_endpoint_->x(x); + interior_endpoint_->y(y); + } + + return ret; +} + +int ObGeoInteriorPointVisitor::visit(ObIWkbGeomPoint *geo) +{ + int ret = OB_SUCCESS; + if (!is_inited_) { + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to get centroid point", K(ret)); + } + } + + if (OB_SUCC(ret) && !is_geo_empty_ && exist_centroid_ && (dimension_ == -1 || dimension_ == 0)) { + ObWkbGeomPoint *point = reinterpret_cast(geo->val()); + double dist = calculate_euclidean_distance(*centroid_pt_, *point); + if (dist < min_dist_) { + min_dist_ = dist; + if (OB_FAIL(assign_interior_point(geo->x(), geo->y()))) { + LOG_WARN("fail to assign interior point", K(ret), K(geo->x()), K(geo->y())); + } + } + } + return ret; +} + +int ObGeoInteriorPointVisitor::visit(ObIWkbGeomMultiPoint *geo) +{ + int ret = OB_SUCCESS; + if (!is_inited_) { + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to get centroid point", K(ret)); + } + } + + if (OB_SUCC(ret) && !is_geo_empty_ && exist_centroid_) { + const ObWkbGeomMultiPoint *line = reinterpret_cast(geo->val()); + ObWkbGeomMultiPoint::iterator iter = line->begin(); + for (; iter != line->end() && OB_SUCC(ret); iter++) { + double dist = calculate_euclidean_distance(*centroid_pt_, *iter); + if (dist < min_dist_) { + min_dist_ = dist; + if (OB_FAIL(assign_interior_point(iter->get<0>(), iter->get<1>()))) { + LOG_WARN("fail to assign interior point", K(ret), K(iter->get<0>()), K(iter->get<1>())); + } + } + } + } + return ret; +} + +int ObGeoInteriorPointVisitor::visit(ObIWkbGeomLineString *geo) +{ + int ret = OB_SUCCESS; + if (!is_inited_) { + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to get centroid point", K(ret)); + } + } + + if (OB_SUCC(ret) && !is_geo_empty_) { + const ObWkbGeomLineString *line = reinterpret_cast(geo->val()); + ObWkbGeomLineString::const_iterator iter = line->begin(); + ObWkbGeomLineString::const_iterator iter2 = line->begin(); + if (exist_centroid_) { + if (line->size() <= 2) { + if (OB_ISNULL(interior_point_)) { + // interior point is first point + double dist = calculate_euclidean_distance(*centroid_pt_, *iter); + if (dist < min_endpoint_dist_) { + min_endpoint_dist_ = dist; + if (OB_FAIL(assign_interior_endpoint(iter->get<0>(), iter->get<1>()))) { + LOG_WARN("fail to assign interior point", K(ret), K(iter->get<0>()), K(iter->get<1>())); + } + } + } + } else { + // skip first and last point + iter++; + iter2++; + iter2++; + for (; iter2 != line->end() && OB_SUCC(ret); iter++, iter2++) { + double dist = calculate_euclidean_distance(*centroid_pt_, *iter); + if (dist < min_dist_) { + min_dist_ = dist; + if (OB_FAIL(assign_interior_point(iter->get<0>(), iter->get<1>()))) { + LOG_WARN("fail to assign interior point", K(ret), K(iter->get<0>()), K(iter->get<1>())); + } + } + } + } + } else { + // only choose first and last point + // centroid_pt_ default POINT(0 0) when centroid not exist + double dist = calculate_euclidean_distance(*centroid_pt_, *iter); + if (dist < min_dist_) { + min_dist_ = dist; + if (OB_FAIL(assign_interior_point(iter->get<0>(), iter->get<1>()))) { + LOG_WARN("fail to assign interior point", K(ret), K(iter->get<0>()), K(iter->get<1>())); + } + } + if (line->size() > 1) { + ++iter2; + for (; iter2 != line->end() && OB_SUCC(ret); iter++, iter2++) { + // find last point + } + dist = calculate_euclidean_distance(*centroid_pt_, *iter); + if (dist < min_dist_) { + min_dist_ = dist; + if (OB_FAIL(assign_interior_point(iter->get<0>(), iter->get<1>()))) { + LOG_WARN("fail to assign interior point", K(ret), K(iter->get<0>()), K(iter->get<1>())); + } + } + } + } + } + return ret; +} + +int ObGeoInteriorPointVisitor::visit(ObIWkbGeomMultiLineString *geo) +{ + int ret = OB_SUCCESS; + // unused + if (!is_inited_) { + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to get centroid point", K(ret)); + } + } + + return ret; +} + +int ObGeoInteriorPointVisitor::inner_calculate_interior_y( + const ObWkbGeomLinearRing &ring, double centre_y, double &ymax, double &ymin) +{ + int ret = OB_SUCCESS; + ObWkbGeomLinearRing::iterator iter = ring.begin(); + for (; iter != ring.end() && OB_SUCC(ret); iter++) { + double y = iter->get<1>(); + if ((y > ymin) && (y <= centre_y)) { + ymin = y; + } else if ((y > centre_y) && (y < ymax)) { + ymax = y; + } + } + + return ret; +} + +int ObGeoInteriorPointVisitor::calculate_interior_y(ObIWkbGeomPolygon *geo, double &interior_y) +{ + int ret = OB_SUCCESS; + ObGeoEvalCtx box_ctx(allocator_); + ObGeogBox *gbox = nullptr; + const ObWkbGeomPolygon *polygon = reinterpret_cast(geo->val()); + ObWkbGeomLinearRing::iterator iter = polygon->exterior_ring().begin(); + double ymin = iter->get<1>(); + double ymax = iter->get<1>(); + for (iter++; iter != polygon->exterior_ring().end(); iter++) { + double y = iter->get<1>(); + if (y < ymin) { + ymin = y; + } + if (y > ymax) { + ymax = y; + } + } + double centre_y = ymin + (ymax - ymin) / 2; + if (OB_FAIL(inner_calculate_interior_y(polygon->exterior_ring(), centre_y, ymax, ymin))) { + LOG_WARN("failed to do geom polygon exterior ring visit", K(ret)); + } else { + const ObWkbGeomPolygonInnerRings &rings = polygon->inner_rings(); + ObWkbGeomPolygonInnerRings::const_iterator iter = rings.begin(); + for (; iter != rings.end() && OB_SUCC(ret); iter++) { + if (OB_FAIL(inner_calculate_interior_y(*iter, centre_y, ymax, ymin))) { + LOG_WARN("failed to do geom polygon inner ring visit", K(ret)); + } + } + } + + if (OB_SUCC(ret)) { + interior_y = ymin + (ymax - ymin) / 2; + } + return ret; +} + +bool ObGeoInteriorPointVisitor::is_crossing_line(double start_y, double end_y, double interior_y) +{ + bool bret = true; + if (start_y == end_y) { + bret = false; // horizontal line + } else if ((start_y > interior_y) && (end_y > interior_y)) { + bret = false; // above line + } else if ((start_y < interior_y) && (end_y < interior_y)) { + bret = false; // below line + } else if ((start_y == interior_y) && (end_y < interior_y)) { + bret = false; // downward line start at interior_y (below line) + } else if ((end_y == interior_y) && (start_y < interior_y)) { + bret = false; // upward line end at interior_y (below line) + } + return bret; +} + +int ObGeoInteriorPointVisitor::inner_calculate_crossing_points( + const ObWkbGeomLinearRing &ring, double interior_y, ObArray &crossing_points_x) +{ + int ret = OB_SUCCESS; + ObWkbGeomLinearRing::iterator iter = ring.begin(); + double ymin = iter->get<1>(); + double ymax = iter->get<1>(); + for (iter++; iter < ring.end(); iter++) { + if (iter->get<1>() < ymin) { + ymin = iter->get<1>(); + } + if (iter->get<1>() > ymax) { + ymax = iter->get<1>(); + } + } + if (interior_y >= ymin && interior_y <= ymax) { + ObWkbGeomLinearRing::iterator p0_iter = ring.begin(); // segment start point + ObWkbGeomLinearRing::iterator p1_iter = ring.begin(); // segment end point + p1_iter++; + uint32_t sz = ring.size() - 1; // to avoid calculate first segment twice + uint32_t i = 0; + for (; i < sz && OB_SUCC(ret); p0_iter++, p1_iter++, ++i) { + double y0 = p0_iter->get<1>(); + double y1 = p1_iter->get<1>(); + if (is_crossing_line(y0, y1, interior_y)) { + double x0 = p0_iter->get<0>(); + double x1 = p1_iter->get<0>(); + double x = 0.0; + if (x1 == x0) { + x = x0; + } else { + // check y1 != y0 in is_crossing_line + double percent = (interior_y - y0) / (y1 - y0); + x = x0 + percent * (x1 - x0); + } + if (OB_FAIL(crossing_points_x.push_back(x))) { + LOG_WARN("fail to push double data into array", K(ret), K(x)); + } + } + } + } + return ret; +} + +int ObGeoInteriorPointVisitor::calculate_crossing_points( + ObIWkbGeomPolygon *geo, double interior_y, ObArray &crossing_points_x) +{ + int ret = OB_SUCCESS; + const ObWkbGeomPolygon *polygon = reinterpret_cast(geo->val()); + if (OB_FAIL(inner_calculate_crossing_points(polygon->exterior_ring(), interior_y, crossing_points_x))) { + LOG_WARN("failed to do geom polygon exterior ring visit", K(ret)); + } else { + const ObWkbGeomPolygonInnerRings &rings = polygon->inner_rings(); + ObWkbGeomPolygonInnerRings::const_iterator iter = rings.begin(); + for (; iter != rings.end() && OB_SUCC(ret); iter++) { + if (OB_FAIL(inner_calculate_crossing_points(*iter, interior_y, crossing_points_x))) { + LOG_WARN("failed to do geom polygon inner ring visit", K(ret)); + } + } + } + return ret; +} + +int ObGeoInteriorPointVisitor::visit(ObIWkbGeomPolygon *geo) +{ + int ret = OB_SUCCESS; + if (!is_inited_) { + if (OB_FAIL(ObGeoTypeUtil::check_empty(geo, is_geo_empty_))) { + LOG_WARN("fail to check geometry is empty", K(ret)); + } else { + is_inited_ = true; + } + } + + if (OB_SUCC(ret) && !is_geo_empty_) { + double interior_y = 0; + ObArray crossing_points; + if (OB_FAIL(calculate_interior_y(geo, interior_y))) { + LOG_WARN("fail to calculate interior point's y coordinate", K(ret)); + } else if (OB_FAIL(calculate_crossing_points(geo, interior_y, crossing_points))) { + LOG_WARN("fail to calculae crossing points", K(ret)); + } else if (crossing_points.size() % 2) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("crossing_points size should be even", K(ret), K(crossing_points.size())); + } else { + double interior_x = 0; + std::sort(crossing_points.begin(), crossing_points.end()); + for (int64_t i = 0; OB_SUCC(ret) && i < crossing_points.size(); i += 2) { + double width = crossing_points[i + 1] - crossing_points[i]; + if (width != 0 && width > max_width_) { + max_width_ = width; + interior_x = crossing_points[i] + width / 2; + if (OB_FAIL(assign_interior_point(interior_x, interior_y))) { + LOG_WARN("fail to assign interior point", K(ret), K(interior_x), K(interior_y)); + } + } + } + + if (OB_SUCC(ret) && (max_width_ == -1)) { + // set default interior point, in case polygon has zero area + const ObWkbGeomPolygon *polygon = reinterpret_cast(geo->val()); + const ObWkbGeomInnerPoint &first_point = *polygon->exterior_ring().begin(); + if (OB_FAIL(assign_interior_point(first_point.get<0>(), first_point.get<1>()))) { + LOG_WARN("fail to assign interior point", K(ret), K(first_point.get<0>()), K(first_point.get<1>())); + } else { + max_width_ = 0.0; + } + } + } + } + return ret; +} + +int ObGeoInteriorPointVisitor::visit(ObIWkbGeomMultiPolygon *geo) +{ + int ret = OB_SUCCESS; + if (!is_inited_) { + if (OB_FAIL(ObGeoTypeUtil::check_empty(geo, is_geo_empty_))) { + LOG_WARN("fail to check geometry is empty", K(ret)); + } else { + is_inited_ = true; + } + } + return ret; +} + +int ObGeoInteriorPointVisitor::visit(ObIWkbGeomCollection *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObGeoTypeUtil::check_empty(geo, is_geo_empty_))) { + LOG_WARN("fail to check geometry is empty", K(ret)); + } else if (!is_geo_empty_) { + if (OB_FAIL(ObGeoTypeUtil::get_coll_dimension(geo, dimension_))) { + LOG_WARN("fail to calculate collection dimension_", K(ret)); + } else if (dimension_ == 0 || dimension_ == 1) { + ObGeoEvalCtx centroid_context(allocator_); + ObGeometry *res_geo = nullptr; + if (OB_FAIL(centroid_context.append_geo_arg(geo))) { + LOG_WARN("build geo gis context failed", K(ret)); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(centroid_context, res_geo))) { + if (ret == OB_ERR_BOOST_GEOMETRY_CENTROID_EXCEPTION) { + exist_centroid_ = false; + ret = OB_SUCCESS; + } else { + LOG_WARN("eval geo centroid failed", K(ret)); + } + } else { + centroid_pt_ = reinterpret_cast(res_geo); + } + if (OB_SUCC(ret)) { + is_inited_ = true; + } + } + } + return ret; +} + +int ObGeoInteriorPointVisitor::get_interior_point(ObGeometry *&interior_point) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(interior_point_)) { + if (OB_ISNULL(interior_endpoint_)) { + // return ObCartesianGeometrycollection EMPTY + if (OB_ISNULL(interior_point = OB_NEWx(ObCartesianGeometrycollection, allocator_, srid_, *allocator_))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for ObCartesianGeometrycollection", K(ret)); + } + } else { + interior_point = interior_endpoint_; + } + } else { + interior_point = interior_point_; + } + return ret; +} + +} // namespace common +} // namespace oceanbase diff --git a/deps/oblib/src/lib/geo/ob_geo_interior_point_visitor.h b/deps/oblib/src/lib/geo/ob_geo_interior_point_visitor.h new file mode 100644 index 0000000000..6ddd213b3b --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_interior_point_visitor.h @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_GEO_INTERIOR_POINT_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_GEO_INTERIOR_POINT_VISITOR_ +#include "lib/geo/ob_geo_visitor.h" + +namespace oceanbase +{ +namespace common +{ + +class ObGeoInteriorPointVisitor : public ObEmptyGeoVisitor +{ +public: + explicit ObGeoInteriorPointVisitor(ObIAllocator *allocator) + : allocator_(allocator), + interior_point_(nullptr), + min_dist_(DBL_MAX), + interior_endpoint_(nullptr), + min_endpoint_dist_(DBL_MAX), + srid_(0), + exist_centroid_(true), + centroid_pt_(nullptr), + max_width_(-1), + is_geo_empty_(true), + is_inited_(false), + dimension_(-1) + {} + ~ObGeoInteriorPointVisitor() + {} + bool prepare(ObGeometry *geo) + { + UNUSED(geo); + return true; + } + + bool prepare(ObIWkbGeomMultiPoint *geo) + { + UNUSED(geo); + return (dimension_ == -1 || dimension_ == 0); + } + + bool prepare(ObIWkbGeomLineString *geo) + { + UNUSED(geo); + return (dimension_ == -1 || dimension_ == 1); + } + + bool prepare(ObIWkbGeomMultiLineString *geo) + { + UNUSED(geo); + return (dimension_ == -1 || dimension_ == 1); + } + + bool prepare(ObIWkbGeomPolygon *geo) + { + UNUSED(geo); + return (dimension_ == -1 || dimension_ == 2); + } + + bool prepare(ObIWkbGeomMultiPolygon *geo) + { + UNUSED(geo); + return (dimension_ == -1 || dimension_ == 2); + } + + // wkb + int visit(ObIWkbGeomPoint *geo); + int visit(ObIWkbGeomLineString *geo); + int visit(ObIWkbGeomMultiPoint *geo); + int visit(ObIWkbGeomMultiLineString *geo); + int visit(ObIWkbGeomPolygon *geo); + int visit(ObIWkbGeomMultiPolygon *geo); + int visit(ObIWkbGeomCollection *geo); + + bool is_end(ObIWkbGeomPoint *geo) + { + UNUSED(geo); + return true; + } + bool is_end(ObIWkbGeomLineString *geo) + { + UNUSED(geo); + return true; + } + bool is_end(ObIWkbGeomMultiPoint *geo) + { + UNUSED(geo); + return true; + } + bool is_end(ObIWkbGeomPolygon *geo) + { + UNUSED(geo); + return true; + } + bool is_end(ObIWkbGeomCollection *geo) + { + UNUSED(geo); + return false; + } + + virtual int finish(ObGeometry *geo) override + { + UNUSED(geo); + return OB_SUCCESS; + } + + int get_interior_point(ObGeometry *&interior_point); + +private: + int init(ObGeometry *geo); + int assign_interior_point(double x, double y); + int assign_interior_endpoint(double x, double y); + template + double calculate_euclidean_distance(ObCartesianPoint &p1, PointType &p2); + int calculate_interior_y(ObIWkbGeomPolygon *geo, double &interior_y); + int inner_calculate_interior_y(const ObWkbGeomLinearRing &ring, double centre_y, double &ymax, double &ymin); + int calculate_crossing_points(ObIWkbGeomPolygon *geo, double interior_y, ObArray &crossing_points_x); + int inner_calculate_crossing_points( + const ObWkbGeomLinearRing &ring, double interior_y, ObArray &crossing_points_x); + bool is_crossing_line(double start_y, double end_y, double interior_y); + + ObIAllocator *allocator_; + ObCartesianPoint *interior_point_; + double min_dist_; // for point/multipoint/line/multiline + ObCartesianPoint *interior_endpoint_; + double min_endpoint_dist_; // for line/multiline + uint32_t srid_; + bool exist_centroid_; + ObCartesianPoint *centroid_pt_; + double max_width_; // for polygon/multipolygon + bool is_geo_empty_; + bool is_inited_; + int8_t dimension_; // for collection + DISALLOW_COPY_AND_ASSIGN(ObGeoInteriorPointVisitor); +}; + +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_latlong_check_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_latlong_check_visitor.cpp index 519336c196..fd3a989e6b 100644 --- a/deps/oblib/src/lib/geo/ob_geo_latlong_check_visitor.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_latlong_check_visitor.cpp @@ -17,59 +17,83 @@ namespace oceanbase { namespace common { -static double ob_normalize_latitude(double lat) +double ObGeoLatlongCheckVisitor::ob_normalize_latitude(double lat) { - if (lat > 360.0) { - lat = remainder(lat, 360.0); + bool modified = false; + const double TOLERANCE = 1e-10; // according to pg + if (lat > 90.0 && (lat - 90) <= TOLERANCE) { + lat = 90.0; + modified = true; + } else if (lat < -90.0 && (-90 - lat) <= TOLERANCE) { + lat = -90.0; + modified = true; } - if (lat < -360.0) { - lat = remainder(lat, -360.0); - } + if (!modified) { + if (lat > 360.0) { + lat = remainder(lat, 360.0); + } - if (lat > 180.0) { - lat = 180.0 - lat; - } + if (lat < -360.0) { + lat = remainder(lat, -360.0); + } - if (lat < -180.0) { - lat = -180.0 - lat; - } + if (lat > 180.0) { + lat = 180.0 - lat; + } - if (lat > 90.0) { - lat = 180.0 - lat; - } + if (lat < -180.0) { + lat = -180.0 - lat; + } - if (lat < -90.0) { - lat = -180.0 - lat; + if (lat > 90.0) { + lat = 180.0 - lat; + } + + if (lat < -90.0) { + lat = -180.0 - lat; + } } return lat; } -static double ob_normalize_longitude(double lon) +double ObGeoLatlongCheckVisitor::ob_normalize_longitude(double lon) { - if (lon > 360.0) { - lon = remainder(lon, 360.0); - } - - if (lon < -360.0) { - lon = remainder(lon, -360.0); - } - - if (lon > 180.0) { - lon = -360.0 + lon; - } - - if (lon < -180.0) { - lon = 360 + lon; - } - - if (lon == -180.0) { + bool modified = false; + const double TOLERANCE = 1e-10; // according to pg + if (lon > 180.0 && (lon - 180) <= TOLERANCE) { lon = 180.0; + modified = true; + } else if (lon < -180.0 && (-180 - lon) <= TOLERANCE) { + lon = -180.0; + modified = true; } - if (lon == -360.0) { - lon = 0.0; + if (!modified) { + if (lon > 360.0) { + lon = remainder(lon, 360.0); + } + + if (lon < -360.0) { + lon = remainder(lon, -360.0); + } + + if (lon > 180.0) { + lon = -360.0 + lon; + } + + if (lon < -180.0) { + lon = 360 + lon; + } + + if (lon == -180.0) { + lon = 180.0; + } + + if (lon == -360.0) { + lon = 0.0; + } } return lon; diff --git a/deps/oblib/src/lib/geo/ob_geo_latlong_check_visitor.h b/deps/oblib/src/lib/geo/ob_geo_latlong_check_visitor.h index e0e9166c35..979aad7862 100644 --- a/deps/oblib/src/lib/geo/ob_geo_latlong_check_visitor.h +++ b/deps/oblib/src/lib/geo/ob_geo_latlong_check_visitor.h @@ -37,6 +37,8 @@ public: template int calculate_point_range(Geo_type *geo); + static double ob_normalize_latitude(double lat); + static double ob_normalize_longitude(double lon); private: const ObSrsItem *srs_; bool changed_; diff --git a/deps/oblib/src/lib/geo/ob_geo_mvt.cpp b/deps/oblib/src/lib/geo/ob_geo_mvt.cpp new file mode 100644 index 0000000000..fe6c422440 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_mvt.cpp @@ -0,0 +1,510 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "ob_geo_mvt.h" +#include "share/ob_lob_access_utils.h" +#include "share/object/ob_obj_cast.h" +#include "share/rc/ob_tenant_base.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_mvt_encode_visitor.h" +#include "lib/json_type/ob_json_base.h" +#include "lib/json_type/ob_json_bin.h" + +namespace oceanbase { +namespace common { + +int mvt_agg_result::init(const ObString &lay_name, const ObString &geom_name, + const ObString &feat_id, const uint32_t extent) +{ + int ret = OB_SUCCESS; + lay_name_ = lay_name; + geom_name_ = geom_name; + feature_id_name_ = feat_id; + extent_ = extent; + vector_tile__tile__layer__init(&layer_); + layer_.version = 2; + layer_.name = lay_name_.ptr(); + + return ret; +} + +int mvt_agg_result::init_layer() +{ + int ret = OB_SUCCESS; + vector_tile__tile__layer__init(&layer_); + layer_.version = 2; + layer_.name = lay_name_.ptr(); + values_map_.create(DEFAULT_BUCKET_NUM, "MvtValues", "MvtValues", MTL_ID()); + layer_.extent = extent_; + return ret; +} + +int mvt_agg_result::generate_feature(ObObj *tmp_obj, uint32_t obj_cnt) +{ + int ret = OB_SUCCESS; + if (geom_idx_ >= obj_cnt) { + ret = OB_ERR_GIS_UNSUPPORTED_ARGUMENT; + LOG_WARN("can't find geom column in feature", K(ret), K(column_offset_), K(geom_idx_)); + } else if (tmp_obj[geom_idx_].is_null()) { + // geometry column is null. do nothing + } else if (!tmp_obj[geom_idx_].is_geometry()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid object type", K(ret), K(tmp_obj[geom_idx_])); + } else { + feature_ = static_cast(allocator_.alloc(sizeof(VectorTile__Tile__Feature))); + if (OB_ISNULL(feature_)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret)); + } else { + const ObObjMeta& meta = tmp_obj[geom_idx_].get_meta(); + ObString str = tmp_obj[geom_idx_].get_string(); + ObGeometry *geo = NULL; + vector_tile__tile__feature__init(feature_); + if (OB_FAIL(features_.push_back(feature_))) { + LOG_WARN("failed to push back feature", K(ret)); + } else if (meta.is_null()) { + str.reset(); + } else if (is_lob_storage(meta.get_type())) { + ObTextStringIter str_iter(meta.get_type(), meta.get_collation_type(), str, tmp_obj[geom_idx_].has_lob_header()); + if (OB_FAIL(str_iter.init(0, NULL, temp_allocator_))) { + LOG_WARN("Lob: init lob str iter failed ", K(ret), K(str_iter)); + } else if (OB_FAIL(str_iter.get_full_data(str))) { + LOG_WARN("Lob: str iter get full data failed ", K(ret), K(str_iter)); + } else if (OB_FAIL(ObGeoTypeUtil::construct_geometry(*temp_allocator_, str, NULL, geo, true))) { + LOG_WARN("failed to construct geometry", K(ret)); + } else if (ObGeoTypeUtil::is_3d_geo_type(geo->type()) + && OB_FAIL(ObGeoTypeUtil::convert_geometry_3D_to_2D(NULL, allocator_, geo, ObGeoBuildFlag::GEO_ALL_DISABLE, geo))) { + LOG_WARN("failed to convert 3d to 2d", K(ret)); + } else if (OB_FAIL(transform_geom(*geo))) { + LOG_WARN("failed to transform geometry", K(ret)); + } else if (OB_FAIL(transform_other_column(tmp_obj, obj_cnt))) { + LOG_WARN("failed to transform other column", K(ret)); + } else { + feature_->n_tags = tags_.size(); + feature_->tags = static_cast(allocator_.alloc(feature_->n_tags * sizeof(*(feature_->tags)))); + if (OB_ISNULL(feature_->tags) && tags_.size()) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret), K(tags_.size())); + } + for (uint32_t i = 0; i < tags_.size() && OB_SUCC(ret); i++) { + feature_->tags[i] = tags_.at(i); + } + tags_.clear(); + } + } + } + } + + return ret; +} + +int mvt_agg_result::transform_geom(const ObGeometry &geo) +{ + int ret = OB_SUCCESS; + switch(geo.type()) { + case ObGeoType::POINT : + case ObGeoType::MULTIPOINT : + feature_->type = VECTOR_TILE__TILE__GEOM_TYPE__POINT; + break; + case ObGeoType::LINESTRING : + case ObGeoType::MULTILINESTRING : + feature_->type = VECTOR_TILE__TILE__GEOM_TYPE__LINESTRING; + break; + case ObGeoType::POLYGON : + case ObGeoType::MULTIPOLYGON : + feature_->type = VECTOR_TILE__TILE__GEOM_TYPE__POLYGON; + break; + default : + ret = OB_ERR_UNEXPECTED_GEOMETRY_TYPE; + LOG_WARN("unexpected geometry type for st_area", K(ret)); + LOG_USER_ERROR(OB_ERR_UNEXPECTED_GEOMETRY_TYPE, ObGeoTypeUtil::get_geo_name_by_type(geo.type()), + ObGeoTypeUtil::get_geo_name_by_type(geo.type()), "_st_asmvt"); + } + if (OB_SUCC(ret)) { + ObGeoMvtEncodeVisitor visitor; + if (OB_FAIL(const_cast(geo).do_visit(visitor))) { + LOG_WARN("failed to do mvt encode visit", K(ret)); + } else { + ObVector &buf = visitor.get_encode_buffer(); + feature_->n_geometry = buf.size(); + feature_->geometry = static_cast(allocator_.alloc(sizeof(uint32_t) * feature_->n_geometry)); + if (OB_ISNULL(feature_->geometry)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret), K(feature_->n_geometry)); + } else { + for (uint32_t i = 0; i < feature_->n_geometry; i++) { + feature_->geometry[i] = buf.at(i); + } + } + } + } + return ret; +} + +int mvt_agg_result::get_key_id(ObString col_name, uint32_t &key_id) +{ + int ret = OB_SUCCESS; + key_id = UINT32_MAX; + for (uint32_t i = 0; i < keys_.size() && key_id == UINT32_MAX; i++) { + if (col_name.case_compare(keys_.at(i)) == 0) { + key_id = i; + } + } + if (key_id == UINT32_MAX) { + ret = OB_ERR_UNEXPECTED; + } + return ret; +} + +int mvt_agg_result::transform_json_column(ObObj &json) +{ + int ret = OB_SUCCESS; + ObString str; + ObTextStringIter str_iter(json.get_meta().get_type(), json.get_meta().get_collation_type(), json.get_string(), json.has_lob_header()); + if (OB_FAIL(str_iter.init(0, NULL, temp_allocator_))) { + LOG_WARN("Lob: init lob str iter failed ", K(ret), K(str_iter)); + } else if (OB_FAIL(str_iter.get_full_data(str))) { + LOG_WARN("Lob: str iter get full data failed ", K(ret), K(str_iter)); + } else { + ObArenaAllocator temp_allocator; + ObJsonBin j_bin(str.ptr(), str.length(), &temp_allocator); + ObIJsonBase *j_base = &j_bin; + if (OB_FAIL(j_bin.reset_iter())) { + COMMON_LOG(WARN, "fail to reset json bin iter", K(ret)); + } else if (j_base->json_type() == ObJsonNodeType::J_OBJECT) { + uint64_t count = j_base->element_count(); + for (uint64_t i = 0; OB_SUCC(ret) && i < count; i++) { + uint32_t key_id; + ObString key; + ObString key_name; + if (OB_FAIL(j_base->get_key(i, key))) { + LOG_WARN("fail to get key", K(ret), K(i)); + } else if (OB_FAIL(get_key_id(key, key_id))) { + if (OB_FAIL(ob_write_string(allocator_, key, key_name, true))) { + LOG_WARN("write string failed", K(ret), K(key)); + } else if (OB_FAIL(keys_.push_back(key_name))) { + LOG_WARN("failed to push back col name to keys", K(ret), K(i)); + } else { + key_id = keys_.size() - 1; + } + } + if (OB_SUCC(ret)) { + ObIJsonBase *jb_ptr = NULL; + ObJsonBin j_val(temp_allocator_); + jb_ptr = &j_val; + if (OB_FAIL(j_base->get_object_value(i, jb_ptr))) { + LOG_WARN("fail to get object value", K(ret), K(i)); + } else { // value + bool ignore_type = false; + ObTileValue tile_value; + VectorTile__Tile__Value value; + vector_tile__tile__value__init(&value); + ObJsonNodeType j_type = jb_ptr->json_type(); + switch(j_type) { + case ObJsonNodeType::J_BOOLEAN: { + bool v = jb_ptr->get_boolean(); + value.bool_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_BOOL_VALUE; + tile_value.ptr_ = &value.bool_value; + tile_value.len_ = sizeof(value.bool_value); + break; + } + case ObJsonNodeType::J_DOUBLE: { + double v = jb_ptr->get_double(); + value.double_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_DOUBLE_VALUE; + tile_value.ptr_ = &value.double_value; + tile_value.len_ = sizeof(value.double_value); + break; + } + case ObJsonNodeType::J_INT: { + int64_t v = jb_ptr->get_int(); + if (v >= 0) { + value.uint_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_UINT_VALUE; + tile_value.ptr_ = &value.uint_value; + tile_value.len_ = sizeof(value.uint_value); + } else { + value.int_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_SINT_VALUE; + tile_value.ptr_ = &value.int_value; + tile_value.len_ = sizeof(value.int_value); + } + break; + } + case ObJsonNodeType::J_UINT: { + int64_t v = jb_ptr->get_uint(); + value.uint_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_UINT_VALUE; + tile_value.ptr_ = &value.uint_value; + tile_value.len_ = sizeof(value.uint_value); + break; + } + case ObJsonNodeType::J_STRING: { + uint64_t data_len = jb_ptr->get_data_length(); + const char *data = jb_ptr->get_data(); + ObString str_val; + if (OB_FAIL(ob_write_string(allocator_, ObString(data_len, data), str_val, true))) { + LOG_WARN("failed to copy string ", K(ret), KP(data)); + } else { + value.string_value = str_val.ptr(); + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_STRING_VALUE; + tile_value.ptr_ = value.string_value; + tile_value.len_ = str_val.length(); + } + break; + } + default: + // ignore other type, do nothing + ignore_type = true; + break;; + } + if (OB_SUCC(ret) && !ignore_type) { + tile_value.value_ = value; + uint32_t tag_id; + if (OB_FAIL(values_map_.get_refactored(tile_value, tag_id))) { + LOG_WARN("failed to get key", K(ret)); + if (OB_HASH_NOT_EXIST == ret) { + tag_id = values_map_.size(); + if (OB_FAIL(values_map_.set_refactored(tile_value, tag_id))) { + LOG_WARN("failed to set key", K(ret)); + } + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(tags_.push_back(key_id))) { + LOG_WARN("failed to push back key id", K(ret), K(key_id), K(tag_id)); + } else if (OB_FAIL(tags_.push_back(tag_id))) { + LOG_WARN("failed to push back value id", K(ret), K(key_id), K(tag_id)); + } + } + } + } + } + } + } + } + return ret; +} + +int mvt_agg_result::transform_other_column(ObObj *tmp_obj, uint32_t obj_cnt) +{ + int ret = OB_SUCCESS; + for (uint32_t i = column_offset_; i < obj_cnt && OB_SUCC(ret); i += 2) { + ObObjTypeClass tc = tmp_obj[i].get_type_class(); + ObObjType type = tmp_obj[i].get_type(); + uint32_t key_id; + if (i == geom_idx_) { + // do nothing + } else if (i == feat_id_idx_) { + // feature id + if (ob_is_null(type)) { + // do nothing, ignore null + } else if (!ob_is_int_tc(type) && !ob_is_uint_tc(type)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid type for feature id", K(ret), K(type)); + } else { + int64_t v = tmp_obj[i].get_int(); + if (v >= 0) { + feature_->has_id = true; + feature_->id = v; + } + } + } else if (ob_is_json(type)) { + if (OB_FAIL(transform_json_column(tmp_obj[i]))) { + LOG_WARN("failed to transform json column", K(ret)); + } + } else if (tmp_obj[i].is_null() + || ob_is_enum_or_set_type(type)) { // enum/set type mvt encode isn't supported + // do nothing + } else if (OB_FAIL(get_key_id(tmp_obj[i + 1].get_string(), key_id))) { + LOG_WARN("failed to get column key id", K(ret)); + } else { + ObTileValue tile_value; + VectorTile__Tile__Value value; + vector_tile__tile__value__init(&value); + if (type == ObTinyIntType) { + // bool type + bool v = (0 == tmp_obj[i].get_int()) ? false : true; + value.bool_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_BOOL_VALUE; + tile_value.ptr_ = &value.bool_value; + tile_value.len_ = sizeof(value.bool_value); + } else if (ob_is_int_tc(type)) { + int64_t v = tmp_obj[i].get_int(); + if (v >= 0) { + value.uint_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_UINT_VALUE; + tile_value.ptr_ = &value.uint_value; + tile_value.len_ = sizeof(value.uint_value); + } else { + value.int_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_SINT_VALUE; + tile_value.ptr_ = &value.int_value; + tile_value.len_ = sizeof(value.int_value); + } + } else if (ob_is_uint_tc(type)) { + uint64_t v = tmp_obj[i].get_uint64(); + value.uint_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_UINT_VALUE; + tile_value.ptr_ = &value.uint_value; + tile_value.len_ = sizeof(value.uint_value); + } else if (ob_is_float_tc(type)) { + float v = tmp_obj[i].get_float(); + value.float_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_FLOAT_VALUE; + tile_value.ptr_ = &value.float_value; + tile_value.len_ = sizeof(value.float_value); + } else if (ob_is_double_tc(type)) { + double v = tmp_obj[i].get_double(); + value.double_value = v; + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_DOUBLE_VALUE; + tile_value.ptr_ = &value.double_value; + tile_value.len_ = sizeof(value.double_value); + } else if (ob_is_enum_or_set_type(type)) { + // do nothing, enum/set type mvt encode isn't supported + } else { + // other type cast to varchar + ObObj obj; + ObObj geo_hex; + ObString str; + ObCastCtx cast_ctx(temp_allocator_, NULL, CM_NONE, ObCharset::get_system_collation()); + if (OB_FAIL(ObObjCaster::to_type(ObVarcharType, cast_ctx, tmp_obj[i], obj))) { + LOG_WARN("failed to cast number to double type", K(ret)); + } else if (ob_is_geometry(type) && OB_FAIL(ObHexUtils::hex(ObString(obj.get_string().length(), obj.get_string().ptr()), + cast_ctx, geo_hex))) { + LOG_WARN("failed to cast geo to hex", K(ret)); + } else if (OB_FAIL(ob_write_string(allocator_, ob_is_geometry(type) ? geo_hex.get_string() : obj.get_string(), str, true))) { + LOG_WARN("failed to copy c string", K(ret)); + } else { + value.string_value = str.ptr(); + value.test_oneof_case = VECTOR_TILE__TILE__VALUE__TEST_ONEOF_STRING_VALUE; + tile_value.ptr_ = value.string_value; + tile_value.len_ = str.length(); + } + } + if (OB_SUCC(ret)) { + tile_value.value_ = value; + uint32_t tag_id; + if (OB_FAIL(values_map_.get_refactored(tile_value, tag_id))) { + if (OB_HASH_NOT_EXIST == ret) { + tag_id = values_map_.size(); + if (OB_FAIL(values_map_.set_refactored(tile_value, tag_id))) { + LOG_WARN("failed to set key", K(ret)); + } + } else { + LOG_WARN("failed to get key", K(ret)); + } + } + if (OB_SUCC(ret)) { + if (OB_FAIL(tags_.push_back(key_id))) { + LOG_WARN("failed to push back key id", K(ret), K(key_id), K(tag_id)); + } else if (OB_FAIL(tags_.push_back(tag_id))) { + LOG_WARN("failed to push back value id", K(ret), K(key_id), K(tag_id)); + } + } + } + } + } + + return ret; +} + +int mvt_agg_result::mvt_pack(ObString &blob_res) +{ + int ret = OB_SUCCESS; + if (tile_ == NULL) { + tile_ = static_cast(allocator_.alloc(sizeof(VectorTile__Tile))); + if (OB_ISNULL(tile_)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret)); + } else { + vector_tile__tile__init(tile_); + tile_->layers = static_cast(allocator_.alloc(sizeof(VectorTile__Tile__Layer *))); + if (OB_ISNULL(tile_->layers)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret)); + } else { + tile_->layers[0] = &layer_; + tile_->n_layers = 1; + layer_.features = static_cast(allocator_.alloc(sizeof(VectorTile__Tile__Feature *) * features_.size())); + if (OB_ISNULL(layer_.features) && features_.size()) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret), K(features_.size())); + } else { + for (uint32_t i = 0; i < features_.size(); i++) { + layer_.features[i] = features_.at(i); + } + layer_.n_features = features_.size(); + } + } + } + } + if (OB_SUCC(ret)) { + // add keys to layer + layer_.n_keys = keys_.size(); + layer_.keys = static_cast(allocator_.alloc(sizeof(char *) * keys_.size())); + if (OB_ISNULL(layer_.keys) && keys_.size()) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret)); + } + for (uint32_t i = 0; i < keys_.size() && OB_SUCC(ret); i++) { + layer_.keys[i] = keys_.at(i).ptr(); + } + + if (OB_SUCC(ret)) { + // add values to layer + layer_.n_values = values_map_.size(); + layer_.values = static_cast(allocator_.alloc(sizeof(*layer_.values) * values_map_.size())); + if (OB_ISNULL(layer_.values) && !values_map_.empty()) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret)); + } + AttributeMap::iterator lt = values_map_.begin(); + while (OB_SUCC(ret) && lt != values_map_.end()) { + uint32_t i = lt->second; + layer_.values[i] = &(lt->first.value_); + ++lt; + } + } + + if (OB_SUCC(ret)) { + size_t total_len = vector_tile__tile__get_packed_size(tile_); + uint8_t *buf = static_cast(allocator_.alloc(total_len)); + if (OB_ISNULL(buf)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret)); + } else { + vector_tile__tile__pack(tile_, buf); + blob_res.assign_ptr(reinterpret_cast(buf), total_len); + } + } + } + return ret; + +} + +bool mvt_agg_result::is_upper_char_exist(const ObString &str) +{ + bool res = false; + const char *ptr = str.ptr(); + for (int32_t i = 0; i < str.length() && !res; i++) { + if (isupper(static_cast(ptr[i]))) { + res = true; + } + } + return res; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_mvt.h b/deps/oblib/src/lib/geo/ob_geo_mvt.h new file mode 100644 index 0000000000..cbed437089 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_mvt.h @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_MVT_ +#define OCEANBASE_LIB_GEO_MVT_ + +#include "ob_geo.h" +#include "lib/string/ob_string.h" +#include "lib/hash/ob_hashmap.h" +#include "lib/container/ob_iarray.h" +#include "lib/allocator/ob_allocator.h" +#include "ob_vector_tile.pb-c.h" + +namespace oceanbase +{ +namespace common +{ + +typedef struct _ObTileValue { + VectorTile__Tile__Value value_; + void *ptr_; + int32_t len_; + inline uint64_t hash() const + { + uint64_t hash_val = 0; + hash_val = murmurhash(ptr_, len_, hash_val); + return hash_val; + } + + inline int hash(uint64_t &res) const + { + res = cal_hash(0); + return OB_SUCCESS; + } + inline uint64_t cal_hash(uint64_t seed) const + { + uint64_t hash_val = seed; + if (OB_LIKELY(NULL != ptr_) && OB_LIKELY(len_ > 0)) { + hash_val = murmurhash(ptr_, len_, hash_val); + } + return hash_val; + } + + inline int hash(uint64_t &hash_val, uint64_t seed) const + { + hash_val = cal_hash(seed); + return OB_SUCCESS; + } + + inline bool operator==(const _ObTileValue &other) const + { + bool bret = false; + if (ptr_ == other.ptr_ && len_ == other.len_) { + bret = true; + } else if (len_ == other.len_) { + bret = memcmp(ptr_, other.ptr_, len_) == 0; + } + return bret; + } +} ObTileValue; + +typedef common::hash::ObHashMap AttributeMap; +class mvt_agg_result +{ +public: + mvt_agg_result(common::ObIAllocator &alloc) : allocator_(alloc), + inited_(false), + lay_name_("default"), + geom_name_(), + geom_idx_(UINT32_MAX), + feature_id_name_(), + feat_id_idx_(UINT32_MAX), + feature_(nullptr), + layer_(), + tile_(nullptr), + column_cnt_(UINT32_MAX), + extent_(4096), + feature_capacity_(FEATURE_CAPACITY_INIT), + column_offset_(0) {} + virtual ~mvt_agg_result() { values_map_.destroy(); } + int init(const ObString &lay_name, const ObString &geom_name, + const ObString &feat_id, const uint32_t extent); + inline bool is_inited() { return inited_; } + inline const common::ObString& get_geom_name() const { return geom_name_; } + inline common::ObString& get_geom_name() { return geom_name_; } + int init_layer(); + int generate_feature(ObObj *tmp_obj, uint32_t obj_cnt); + int transform_geom(const ObGeometry &geo); + int transform_other_column(ObObj *tmp_obj, uint32_t obj_cnt); + int transform_json_column(ObObj &json); + int mvt_pack(ObString &blob_res); + void set_tmp_allocator(common::ObIAllocator *temp_allocator) { temp_allocator_ = temp_allocator;} + static bool is_upper_char_exist(const ObString &str); +private: + int get_key_id(ObString col_name, uint32_t &key_id); + +public: + + static const uint32_t FEATURE_CAPACITY_INIT = 50; + static const int64_t DEFAULT_BUCKET_NUM = 10243L; + common::ObIAllocator &allocator_; + // for single row iterate allocator; + common::ObIAllocator *temp_allocator_; + bool inited_; + common::ObString lay_name_; + common::ObString geom_name_; + // feature geometry index + uint32_t geom_idx_; + common::ObString feature_id_name_; + // feature id column index + uint32_t feat_id_idx_; + VectorTile__Tile__Feature *feature_; + ObVector features_; + VectorTile__Tile__Layer layer_; + VectorTile__Tile *tile_; + ObVector keys_; + AttributeMap values_map_; + uint32_t column_cnt_; + uint32_t extent_; + uint32_t feature_capacity_; + uint32_t column_offset_; + ObVector tags_; +}; + +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_mvt_encode_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_mvt_encode_visitor.cpp new file mode 100644 index 0000000000..c467833a5d --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_mvt_encode_visitor.cpp @@ -0,0 +1,110 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "ob_geo_mvt_encode_visitor.h" + +namespace oceanbase { +namespace common { + +int ObGeoMvtEncodeVisitor::visit(ObIWkbGeomPoint *geo) +{ + int ret = OB_SUCCESS; + int32_t x = static_cast(geo->x()) - curr_x_; + int32_t y = static_cast(geo->y()) - curr_y_; + if (type_ == ObMVTType::MVT_POINT) { + if (point_idx_ == 0 && OB_FAIL(encode_buffer_.push_back(encode_command(ObMVTCommand::CMD_MOVE_TO, point_num_ == 0 ? 1 : point_num_)))) { + LOG_WARN("failed to push back move to cmd", K(ret)); + } else if (OB_FAIL(encode_buffer_.push_back(encode_param(x)))) { + LOG_WARN("failed to push back x value", K(ret)); + } else if (OB_FAIL(encode_buffer_.push_back(encode_param(y)))) { + LOG_WARN("failed to push back y value", K(ret)); + } else { + curr_x_ = static_cast(geo->x()); + curr_y_ = static_cast(geo->y()); + } + } else if (type_ == ObMVTType::MVT_LINE || type_ == ObMVTType::MVT_RING) { + if (type_ == ObMVTType::MVT_RING && point_idx_ + 1 == point_num_) { + if (OB_FAIL(encode_buffer_.push_back(encode_command(ObMVTCommand::CMD_CLOSE_PATH, 1)))) { + LOG_WARN("failed to push back move to cmd", K(ret)); + } + } else { + if (value_offset_ < line_to_offset_) { + encode_buffer_[value_offset_++] = encode_param(x); + encode_buffer_[value_offset_++] = encode_param(y); + } else if (OB_FAIL(encode_buffer_.push_back(encode_param(x)))) { + LOG_WARN("failed to push back x value", K(ret)); + } else if (OB_FAIL(encode_buffer_.push_back(encode_param(y)))) { + LOG_WARN("failed to push back y value", K(ret)); + } + curr_x_ = static_cast(geo->x()); + curr_y_ = static_cast(geo->y()); + } + } + if (OB_SUCC(ret)) { + point_idx_++; + } + return ret; +} +int ObGeoMvtEncodeVisitor::visit(ObIWkbGeomMultiPoint *geo) +{ + int ret = OB_SUCCESS; + type_ = ObMVTType::MVT_POINT; + point_num_ = geo->size(); + return ret; +} +int ObGeoMvtEncodeVisitor::visit(ObIWkbGeomLineString *geo) +{ + int ret = OB_SUCCESS; + point_num_ = geo->size(); + type_ = ObMVTType::MVT_LINE; + move_to_offset_ = encode_buffer_.size(); + if (OB_FAIL(encode_buffer_.push_back(encode_command(ObMVTCommand::CMD_MOVE_TO, 1)))) { + LOG_WARN("failed to push back move to cmd", K(ret)); + } else if (OB_FAIL(encode_buffer_.push_back(UINT32_MAX))) { + LOG_WARN("failed to push back value", K(ret)); + } else if (OB_FAIL(encode_buffer_.push_back(UINT32_MAX))) { + LOG_WARN("failed to push back value", K(ret)); + } else if (OB_FAIL(encode_buffer_.push_back(encode_command(ObMVTCommand::CMD_LINE_TO, point_num_ - 1)))) { + LOG_WARN("failed to push back line to cmd", K(ret)); + } else { + line_to_offset_ = encode_buffer_.size() - 1; + value_offset_ = move_to_offset_ + 1; + point_idx_ = 0; + } + return ret; +} + +int ObGeoMvtEncodeVisitor::visit(ObIWkbGeomLinearRing *geo) +{ + int ret = OB_SUCCESS; + type_ = ObMVTType::MVT_RING; + point_num_ = geo->size(); + move_to_offset_ = encode_buffer_.size(); + if (OB_FAIL(encode_buffer_.push_back(encode_command(ObMVTCommand::CMD_MOVE_TO, 1)))) { + LOG_WARN("failed to push back move to cmd", K(ret)); + } else if (OB_FAIL(encode_buffer_.push_back(UINT32_MAX))) { + LOG_WARN("failed to push back value", K(ret)); + } else if (OB_FAIL(encode_buffer_.push_back(UINT32_MAX))) { + LOG_WARN("failed to push back value", K(ret)); + } else if (OB_FAIL(encode_buffer_.push_back(encode_command(ObMVTCommand::CMD_LINE_TO, point_num_ - 2)))) { // exclude start/end point + LOG_WARN("failed to push back line to cmd", K(ret)); + } else { + line_to_offset_ = encode_buffer_.size() - 1; + value_offset_ = move_to_offset_ + 1; + point_idx_ = 0; + } + return ret; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_mvt_encode_visitor.h b/deps/oblib/src/lib/geo/ob_geo_mvt_encode_visitor.h new file mode 100644 index 0000000000..0a2372e6f3 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_mvt_encode_visitor.h @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ +#ifndef OCEANBASE_LIB_GEO_OB_MVT_ENCODE_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_MVT_ENCODE_VISITOR_ + +#include "lib/geo/ob_geo_visitor.h" +namespace oceanbase +{ +namespace common +{ + +enum class ObMVTType { + MVT_POINT = 0, + MVT_LINE = 1, + MVT_RING = 2, + MVT_MAX = 3, +}; + +enum class ObMVTCommand +{ + CMD_MOVE_TO = 1, + CMD_LINE_TO = 2, + CMD_CLOSE_PATH = 7, +}; + +class ObGeoMvtEncodeVisitor : public ObEmptyGeoVisitor +{ +public: + ObGeoMvtEncodeVisitor() : type_(ObMVTType::MVT_POINT), + move_to_offset_(UINT32_MAX), line_to_offset_(UINT32_MAX), value_offset_(UINT32_MAX), + point_num_(0), point_idx_(0), + curr_x_(0), curr_y_(0) {} + virtual ~ObGeoMvtEncodeVisitor() {} + bool prepare(ObGeometry *geo) { UNUSED(geo); return true; } + int visit(ObIWkbGeomPoint *geo); + int visit(ObIWkbGeomMultiPoint *geo); + int visit(ObIWkbGeomLineString *geo); + int visit(ObIWkbGeomLinearRing *geo); + int visit(ObIWkbGeometry *geo) { UNUSED(geo); return OB_SUCCESS; } + inline ObVector &get_encode_buffer() { return encode_buffer_; } +private: + inline uint32_t encode_command(ObMVTCommand id, uint32_t count) { return (static_cast(id) & 0x7) | (count << 3); } + inline uint32_t encode_param(int32_t value) { return (value << 1) ^ (value >> 31); } + ObMVTType type_; + ObVector encode_buffer_; + uint32_t move_to_offset_; + uint32_t line_to_offset_; + uint32_t value_offset_; + uint32_t point_num_; + uint32_t point_idx_; + int32_t curr_x_; + int32_t curr_y_; +}; + +} // namespace common +} // namespace oceanbase + +#endif // OCEANBASE_LIB_GEO_OB_MVT_ENCODE_VISITOR_ \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_simplify_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_simplify_visitor.cpp new file mode 100644 index 0000000000..f222475bd0 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_simplify_visitor.cpp @@ -0,0 +1,313 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "ob_geo_simplify_visitor.h" +#include "lib/ob_errno.h" +#include "lib/container/ob_se_array.h" +#include "lib/geo/ob_geo_utils.h" + +namespace oceanbase +{ +namespace common +{ +bool ObGeoSimplifyVisitor::prepare(ObGeometry *geo) +{ + bool bret = true; + if (OB_ISNULL(geo) || !geo->is_tree()) { + bret = false; + } + return bret; +} + +int ObGeoSimplifyVisitor::visit(ObCartesianPoint *geo) +{ + // do not simplify point + return OB_SUCCESS; +} + +template +void ObGeoSimplifyVisitor::find_split_point( + LINE &line, int32_t l, int32_t r, double max_distance, int32_t &split_idx) +{ + split_idx = l; + if ((r - l) >= 2) { + ObWkbGeomInnerPoint &first_pt = line[l]; + ObWkbGeomInnerPoint &last_pt = line[r]; + double ab_distance = ObGeoTypeUtil::distance_point_squre(first_pt, last_pt); + if (ab_distance < DBL_EPSILON) { + // p1 == p2, only calculate distance between first_pr and other point + for (int32_t i = l + 1; i < r; ++i) { + double distance = ObGeoTypeUtil::distance_point_squre(first_pt, line[i]); + if (distance > max_distance) { + max_distance = distance; + split_idx = i; + } + } + } else { + max_distance *= ab_distance; + double ba_x = last_pt.get<0>() - first_pt.get<0>(); + double ba_y = last_pt.get<1>() - first_pt.get<1>(); + double distance = 0.0; + for (int32_t i = l + 1; i < r; ++i) { + ObWkbGeomInnerPoint &cur_pt = line[i]; + double ca_x = cur_pt.get<0>() - first_pt.get<0>(); + double ca_y = cur_pt.get<1>() - first_pt.get<1>(); + double dot_ac_ab = ca_x * ba_x + ca_y * ba_y; + if (dot_ac_ab <= 0.0) { + distance = ObGeoTypeUtil::distance_point_squre(first_pt, cur_pt) * ab_distance; + } else if (dot_ac_ab >= ab_distance) { + distance = ObGeoTypeUtil::distance_point_squre(last_pt, cur_pt) * ab_distance; + } else { + double s = ca_x * ba_y - ca_y * ba_x; + distance = s * s; + } + + if (distance > max_distance) { + max_distance = distance; + split_idx = i; + } + } + } + } +} + +template +void ObGeoSimplifyVisitor::quick_simplify(LINE &line, ObArray &kept_idx, int32_t &kept_sz, + int32_t min_point, int32_t l, int32_t r, double tolerance) +{ + if (l < r) { + double cur_tol = kept_sz >= min_point ? tolerance : -1.0; + int32_t split_idx = l; + find_split_point(line, l, r, cur_tol, split_idx); + if (split_idx != l) { + kept_idx[split_idx] = true; + ++kept_sz; + quick_simplify(line, kept_idx, kept_sz, min_point, l, split_idx, tolerance); + quick_simplify(line, kept_idx, kept_sz, min_point, split_idx, r, tolerance); + } + } +} + +template +int ObGeoSimplifyVisitor::multi_point_visit(LINE &geo, int32_t min_point) +{ + int ret = OB_SUCCESS; + int32_t sz = geo.size(); + if (sz < 3 || sz <= min_point) { + // do not simplify + } else if (tolerance_ == 0 && min_point <= 2) { + // O(n) simple version with tolerance 0 + int32_t kept_idx = 0; // keep first point + int32_t last_idx = sz - 1; + ObWkbGeomInnerPoint *kept_pt = &geo[kept_idx]; + for (int32_t i = 1; i < last_idx; ++i) { + ObWkbGeomInnerPoint *cur_pt = &geo[i]; + ObWkbGeomInnerPoint *next_pt = &geo[i + 1]; + // if straight geo has point kept_pt(a) -> cur_pt(c) -> next_pt(b) + // then remove cur_pt(c), simplify as kept_pt(a) -> next_pt(b) + double ba_x = next_pt->get<0>() - kept_pt->get<0>(); + double ba_y = next_pt->get<1>() - kept_pt->get<1>(); + double ba_length = ba_x * ba_x + ba_y * ba_y; + + double ca_x = cur_pt->get<0>() - kept_pt->get<0>(); + double ca_y = cur_pt->get<1>() - kept_pt->get<1>(); + double ca_ba = ca_x * ba_x + ca_y * ba_y; + double diff = ca_x * ba_y - ca_y * ba_x; + if (ca_ba < 0 || ca_ba > ba_length || diff != 0) { + ++kept_idx; + kept_pt = cur_pt; + if (kept_idx != i) { + geo[kept_idx] = *cur_pt; + } + } + } + ++kept_idx; + if (kept_idx != last_idx) { + // keep last point + geo[kept_idx] = geo[last_idx]; + geo.resize(kept_idx + 1); + } + } else { + ObArray kept_idx; + if (OB_FAIL(kept_idx.prepare_allocate(sz))) { + LOG_WARN("fail to alloc memory", K(ret), K(sz)); + } else { + // must keep first and last point (kept_idx default false) + kept_idx[0] = true; + kept_idx[sz - 1] = true; + int32_t kept_sz = 2; + + // similar quick sort + int32_t left = 0; + int32_t right = sz - 1; + quick_simplify(geo, kept_idx, kept_sz, min_point, left, right, tolerance_ * tolerance_); + int32_t valid_idx = 0; + int32_t last_idx = sz - 1; + for (int32_t i = 1; i < last_idx; ++i) { + if (kept_idx[i]) { + ++valid_idx; + if (valid_idx != i) { + geo[valid_idx] = geo[i]; + } + } + } + if (valid_idx != (last_idx - 1)) { + geo[++valid_idx] = geo[last_idx]; + geo.resize(valid_idx + 1); + } + } + } + return ret; +} + +int ObGeoSimplifyVisitor::visit(ObCartesianLineString *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(multi_point_visit(*geo, LINESTRING_MIN_POINT))) { + LOG_WARN("fail to do multi point visit", K(ret)); + } else if (geo->size() == 1) { + if (keep_collapsed_) { + if (OB_FAIL(geo->push_back(geo->front()))) { + LOG_WARN("fail to push back geometry", K(ret), K(geo->size())); + } + } else { + geo->clear(); + } + } else if (geo->size() == 2 && !keep_collapsed_ && (*geo)[0].equals((*geo)[1])) { + geo->clear(); + } + return ret; +} + +template +int ObGeoSimplifyVisitor::polygon_visit(POLYGON &geo) +{ + int ret = OB_SUCCESS; + if (geo.size() > 0) { + RING &ext_ring = geo.exterior_ring(); + uint32_t min_point = keep_collapsed_ ? RING_MIN_POINT : 0; + if (OB_FAIL(multi_point_visit(ext_ring, min_point))) { + LOG_WARN("fail to do multi point visit", K(ret)); + } else if (ext_ring.size() < RING_MIN_POINT) { + // if ext ring is invalid, then total polygon is invalid + ext_ring.clear(); + geo.interior_rings().clear(); + } else if (geo.inner_ring_size() > 0) { + uint64_t inner_sz = geo.inner_ring_size(); + int32_t valid_inner_ring = 0; + for (uint32_t i = 0; OB_SUCC(ret) && i < inner_sz; ++i) { + RING &inner_ring = geo.inner_ring(i); + if (OB_FAIL(multi_point_visit(inner_ring, min_point))) { + LOG_WARN("fail to do multi point visit", K(ret)); + } else if (inner_ring.size() >= RING_MIN_POINT) { + if (valid_inner_ring != i) { + geo.interior_rings()[valid_inner_ring] = inner_ring; + } + ++valid_inner_ring; + } + } + geo.interior_rings().resize(valid_inner_ring); + } + } + return ret; +} + +int ObGeoSimplifyVisitor::visit(ObCartesianPolygon *geo) +{ + return polygon_visit(*geo); +} + +int ObGeoSimplifyVisitor::visit(ObCartesianMultipoint *geo) +{ + // do not simplify + return OB_SUCCESS; +} + +int ObGeoSimplifyVisitor::visit(ObCartesianMultilinestring *geo) +{ + int ret = OB_SUCCESS; + int32_t valid_line = 0; + ObCartesianMultilinestring &line = *geo; + uint64_t sz = line.size(); + for (int32_t i = 0; i < sz && OB_SUCC(ret); ++i) { + if (OB_FAIL(multi_point_visit(line[i], LINESTRING_MIN_POINT))) { + LOG_WARN("fail to do multi point visit", K(ret), K(i), K(sz)); + } else if (line[i].size() != 0) { + if (valid_line != i) { + line[valid_line] = line[i]; + } + ++valid_line; + } + } + if (valid_line) { + line.resize(valid_line); + } else { + line.clear(); + } + return ret; +} + +int ObGeoSimplifyVisitor::visit(ObCartesianMultipolygon *geo) +{ + int ret = OB_SUCCESS; + int32_t valid_poly = 0; + ObCartesianMultipolygon &poly = *geo; + uint64_t sz = poly.size(); + for (int32_t i = 0; i < sz && OB_SUCC(ret); ++i) { + if (OB_FAIL((polygon_visit(poly[i])))) { + LOG_WARN("fail to do polygon visit", K(ret)); + } else if (poly[i].size() != 0) { + if (valid_poly != i) { + poly[valid_poly] = poly[i]; + } + ++valid_poly; + } + } + if (valid_poly) { + poly.resize(valid_poly); + } else { + poly.clear(); + } + return ret; +} + +int ObGeoSimplifyVisitor::visit(ObCartesianGeometrycollection *geo) +{ + int ret = OB_SUCCESS; + int32_t valid_geo = 0; + for (int32_t i = 0; i < geo->size() && OB_SUCC(ret); i++) { + if (OB_FAIL((*geo)[i].do_visit(*this))) { + LOG_WARN("failed to do tree item visit", K(ret)); + } else if (!(*geo)[i].is_empty()) { + if (valid_geo != i) { + (*geo)[valid_geo] = (*geo)[i]; + } + ++valid_geo; + } + } + if (valid_geo) { + geo->resize(valid_geo); + } else { + geo->clear(); + } + return ret; +} + +int ObGeoSimplifyVisitor::finish(ObGeometry *geo) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_simplify_visitor.h b/deps/oblib/src/lib/geo/ob_geo_simplify_visitor.h new file mode 100644 index 0000000000..b6274a63da --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_geo_simplify_visitor.h @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_GEO_SIMPLIFY_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_GEO_SIMPLIFY_VISITOR_ +#include "lib/geo/ob_geo_visitor.h" +#include "lib/geo/ob_geo_common.h" +#include "lib/geo/ob_geo_utils.h" + +namespace oceanbase +{ +namespace common +{ +class ObGeoSimplifyVisitor : public ObEmptyGeoVisitor +{ +public: + explicit ObGeoSimplifyVisitor(double tolerance = 0.0, bool keep_collapsed = false) + : tolerance_(tolerance), keep_collapsed_(keep_collapsed) + {} + + virtual ~ObGeoSimplifyVisitor() + {} + + bool prepare(ObGeometry *geo) override; + int visit(ObCartesianPoint *geo) override; + int visit(ObCartesianLineString *geo) override; + int visit(ObCartesianPolygon *geo) override; + int visit(ObCartesianMultipoint *geo) override; + int visit(ObCartesianMultilinestring *geo) override; + int visit(ObCartesianMultipolygon *geo) override; + int visit(ObCartesianGeometrycollection *geo) override; + + bool is_end(ObGeometry *geo) override + { + UNUSED(geo); + return true; + } + + int finish(ObGeometry *geo) override; + +private: + static const uint32_t RING_MIN_POINT = 4; + static const uint32_t LINESTRING_MIN_POINT = 2; + + template + int polygon_visit(POLYGON &geo); + template + int multi_point_visit(LINE &geo, int32_t min_point); + template + void quick_simplify(LINE &line, ObArray &kept_idx, int32_t &kept_sz, int32_t min_point, int32_t l, + int32_t r, double tolerance); + template + void find_split_point(LINE &line, int32_t l, int32_t r, double max_distance, int32_t &split_idx); + + double tolerance_; + bool keep_collapsed_; + DISALLOW_COPY_AND_ASSIGN(ObGeoSimplifyVisitor); +}; +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_geo_to_wkt_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_to_wkt_visitor.cpp index 16adf36aaf..83bc6c03ae 100644 --- a/deps/oblib/src/lib/geo/ob_geo_to_wkt_visitor.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_to_wkt_visitor.cpp @@ -30,7 +30,8 @@ const double NOSCI_MAX_DOUBLE = 1E15; int ObGeoToWktVisitor::append_double_with_prec(char *buff, const int32_t buff_size, uint64_t &out_len, - double value) + double value, + int16_t scale) { const int64_t number_str_size = 256; const int64_t number_val_size = number::ObNumber::MAX_BYTE_LEN; @@ -80,7 +81,7 @@ int ObGeoToWktVisitor::append_double_with_prec(char *buff, } else if (OB_FAIL(number_value.format(number_str, number_str_size, new_decimal_len, - static_cast(scale_)))) { + scale))) { LOG_WARN("failed to format number to string", K(ret)); } else if (new_decimal_len == 1 && number_str[0] == '0' && number_value.is_negative()) { // -0.4 round to 0 => -0 @@ -89,11 +90,17 @@ int ObGeoToWktVisitor::append_double_with_prec(char *buff, new_decimal_len = 2; } else if (number_str[new_decimal_len - 1] == '0') { // remove padding 1.00000 => 1, 1.00001000 -> 1.0001 - for (; (new_decimal_len > 1) && (number_str[new_decimal_len - 1] == '0'); new_decimal_len--) { + int64_t non_zero_pos = new_decimal_len; + for (; (non_zero_pos > 1) && (number_str[non_zero_pos - 1] == '0'); non_zero_pos--) { /* do nothing */ } - if (number_str[new_decimal_len - 1] == '.') { - new_decimal_len--; + // check if has '.', prevent 10 -> 1 + int64_t dot_pos = non_zero_pos; + for (; (dot_pos > 1) && (number_str[dot_pos - 1] != '.'); dot_pos--) { + /* do nothing */ + } + if (number_str[dot_pos - 1] == '.') { + new_decimal_len = number_str[non_zero_pos - 1] == '.' ? (non_zero_pos - 1) : non_zero_pos; } } @@ -113,48 +120,54 @@ int ObGeoToWktVisitor::append_double_with_prec(char *buff, return ret; } +// need to reserve buff before +int ObGeoToWktVisitor::convert_double_to_str(char* buff, uint64_t buff_size, double val, bool has_scale, + int16_t scale, bool is_oracle_mode, uint64_t &out_len) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(buff)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("buffer ptr is NULL", K(ret)); + } else if (buff_size < MAX_DIGITS_IN_DOUBLE) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("buffer size is not enough", K(ret), K(buff_size)); + } else if (has_scale) { + if (is_oracle_mode) { + if (OB_FAIL(append_double_oracle(buff, MAX_DIGITS_IN_DOUBLE, out_len, val))) { + LOG_WARN("fail to append double to buffer with precsion", K(ret), K(val)); + } + } else if (OB_FAIL(append_double_with_prec(buff, MAX_DIGITS_IN_DOUBLE, out_len, val, scale))) { + LOG_WARN("fail to append double to buffer with precsion", K(ret), K(val)); + } + } else { + out_len = ob_gcvt(val, ob_gcvt_arg_type::OB_GCVT_ARG_DOUBLE, buff_size, buff, NULL); + if (out_len == 0) { + ret = OB_SIZE_OVERFLOW; + LOG_WARN("fail to convert double to string", K(ret), K(val), K(buff_size)); + } + } + return ret; +} + int ObGeoToWktVisitor::appendInnerPoint(double x, double y) { // [x][ ][y] INIT_SUCC(ret); - char* start = buffer_.ptr() + buffer_.length(); + int16_t scale = static_cast(scale_); uint64_t len_x = 0; - if (has_scale_) { - if (OB_FAIL(append_double_with_prec(start, MAX_DIGITS_IN_DOUBLE, len_x, x))) { - LOG_WARN("fail to append double to buffer with precsion", K(ret), K(x)); - } - } else { - len_x = ob_gcvt(x, ob_gcvt_arg_type::OB_GCVT_ARG_DOUBLE, buffer_.remain(), start, NULL); - if (len_x == 0) { - ret = OB_SIZE_OVERFLOW; - LOG_WARN("fail to convert double to string", K(ret), K(x), K(y), K(buffer_.length()), K(buffer_.remain())); - } - } - if (OB_FAIL(ret)) { - // do nothing + uint64_t len_y = 0; + char *buf_ptr = buffer_.ptr() + buffer_.length(); + if (OB_FAIL(convert_double_to_str(buf_ptr, buffer_.remain(), x, has_scale_, scale, is_oracle_mode_, len_x))) { + LOG_WARN("fail to append x to buffer", K(ret), K(x)); } else if (OB_FAIL(buffer_.set_length(buffer_.length() + len_x))) { - LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length()), K(len_x)); + LOG_WARN("fail to set buffer len", K(ret), K(buffer_.length()), K(len_x)); } else if (OB_FAIL(buffer_.append(" "))) { - LOG_WARN("fail to append buffer_", K(ret)); - } else { - start = buffer_.ptr() + buffer_.length(); - uint64_t len_y = 0; - if (has_scale_) { - if (OB_FAIL(append_double_with_prec(start, MAX_DIGITS_IN_DOUBLE, len_y, y))) { - LOG_WARN("fail to append double to buffer with precsion", K(ret), K(y)); - } - } else { - len_y = ob_gcvt(y, ob_gcvt_arg_type::OB_GCVT_ARG_DOUBLE, buffer_.remain(), start, NULL); - if (len_y == 0) { - ret = OB_SIZE_OVERFLOW; - LOG_WARN("fail to convert double to string", K(ret), K(x), K(y), K(buffer_.length()), K(buffer_.remain())); - } - } - if (OB_FAIL(ret)) { - // do nothing - } else if (OB_FAIL(buffer_.set_length(buffer_.length() + len_y))) { - LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length()), K(len_y)); - } + LOG_WARN("fail to append space", K(ret)); + } else if (FALSE_IT(buf_ptr = buffer_.ptr() + buffer_.length())) { + } else if (OB_FAIL(convert_double_to_str(buf_ptr, buffer_.remain(), y ,has_scale_, scale, is_oracle_mode_, len_y))) { + LOG_WARN("fail to append y to buffer", K(ret), K(y)); + } else if (OB_FAIL(buffer_.set_length(buffer_.length() + len_y))) { + LOG_WARN("fail to set buffer y len", K(ret), K(buffer_.length()), K(len_y)); } return ret; } @@ -165,12 +178,10 @@ int ObGeoToWktVisitor::appendPoint(T_IBIN *geo) INIT_SUCC(ret); const char *type_name = ObGeoTypeUtil::get_geo_name_by_type(geo->type()); uint64_t reserve_len = MAX_DIGITS_IN_DOUBLE * 2 + 3; - reserve_len += in_multi_visit_ ? 0 : strlen(type_name); - reserve_len += (in_multi_visit_ || in_colloction_visit()) ? 1 : 0; // [type_name][(][x][ ][y][)] if (OB_FAIL(buffer_.reserve(reserve_len))) { LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); - } else if (!in_multi_visit_ && OB_FAIL(buffer_.append(type_name))) { + } else if (!in_multi_visit_ && OB_FAIL(appendTypeNameWithMode(geo))) { LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); } else if (OB_FAIL(buffer_.append("("))) { LOG_WARN("fail to append buffer_", K(ret)); @@ -178,7 +189,7 @@ int ObGeoToWktVisitor::appendPoint(T_IBIN *geo) LOG_WARN("fail to appendInnerPoint", K(ret), K(geo->x()), K(geo->y())); } else if (OB_FAIL(buffer_.append(")"))) { LOG_WARN("fail to append buffer_", K(ret)); - } else if ((in_multi_visit_ || in_colloction_visit()) && OB_FAIL(buffer_.append(","))) { + } else if ((in_multi_visit_ || in_colloction_visit()) && OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } return ret; @@ -189,14 +200,13 @@ int ObGeoToWktVisitor::appendLine(T_IBIN *geo) { INIT_SUCC(ret); uint64_t size = geo->size(); - uint64_t reserve_len = (MAX_DIGITS_IN_DOUBLE * 2 + 1 + 1) * size; + uint64_t reserve_len = (MAX_DIGITS_IN_DOUBLE * 2 + 1) * size; const char *type_name = ObGeoTypeUtil::get_geo_name_by_type(geo->type()); - reserve_len += in_multi_visit_ ? 0 : (strlen(type_name) + 2); - reserve_len += (in_multi_visit_ || in_colloction_visit()) ? 1 : 0; + reserve_len += in_multi_visit_ ? 0 : 2; // [type_name][(][x1][ ][y1][,][x2][ ][y2][)] if (OB_FAIL(buffer_.reserve(reserve_len))) { LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); - } else if (!in_multi_visit_ && OB_FAIL(buffer_.append(type_name))) { + } else if (!in_multi_visit_ && OB_FAIL(appendTypeNameWithMode(geo))) { LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); } else if (OB_FAIL(buffer_.append("("))) { LOG_WARN("fail to append buffer_", K(ret)); @@ -206,16 +216,16 @@ int ObGeoToWktVisitor::appendLine(T_IBIN *geo) for ( ; OB_SUCC(ret) && iter != line->end(); iter++) { if (OB_FAIL(appendInnerPoint(iter->template get<0>(), iter->template get<1>()))) { LOG_WARN("fail to appendInnerPoint", K(ret), K(iter->template get<0>()), K(iter->template get<1>())); - } else if (OB_FAIL(buffer_.append(","))) { + } else if (OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } } if (OB_FAIL(ret)) { - } else if (OB_FAIL(buffer_.set_length(buffer_.length() - 1))) { + } else if (OB_FAIL(buffer_.set_length(buffer_.length() - comma_length_))) { LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); } else if (OB_FAIL(buffer_.append(")"))) { LOG_WARN("fail to append buffer_", K(ret)); - } else if ((in_multi_visit_ || in_colloction_visit()) && OB_FAIL(buffer_.append(","))) { + } else if ((in_multi_visit_ || in_colloction_visit()) && OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } } @@ -229,15 +239,13 @@ int ObGeoToWktVisitor::appendPolygon(T_IBIN *geo) INIT_SUCC(ret); const char *type_name = ObGeoTypeUtil::get_geo_name_by_type(geo->type()); uint64_t reserve_len = 2; - reserve_len += in_multi_visit_ ? 0 : strlen(type_name); - reserve_len += (in_multi_visit_ || in_colloction_visit()) ? 1 : 0; // [type_name][(][(][x1][ ][y1][,][x2][ ][y2][,][x3][ ][y3][)][)] if (geo->length() < WKB_COMMON_WKB_HEADER_LEN) { ret = OB_ERR_GIS_INVALID_DATA; LOG_WARN("invalid wkb length", K(ret), K(geo->length())); } else if (OB_FAIL(buffer_.reserve(reserve_len))) { LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); - } else if (!in_multi_visit_ && OB_FAIL(buffer_.append(type_name))) { + } else if (!in_multi_visit_ && OB_FAIL(appendTypeNameWithMode(geo))) { LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); } else if (OB_FAIL(buffer_.append("("))) { LOG_WARN("fail to append buffer_", K(ret)); @@ -256,16 +264,16 @@ int ObGeoToWktVisitor::appendPolygon(T_IBIN *geo) for (; OB_SUCC(ret) && iter != exterior.end(); ++iter) { if (OB_FAIL(appendInnerPoint(iter->template get<0>(), iter->template get<1>()))) { LOG_WARN("fail to appendInnerPoint", K(ret), K(iter->template get<0>()), K(iter->template get<1>())); - } else if (OB_FAIL(buffer_.append(","))) { + } else if (OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } } if (OB_FAIL(ret)) { - } else if (OB_FAIL(buffer_.set_length(buffer_.length() - 1))) { + } else if (OB_FAIL(buffer_.set_length(buffer_.length() - comma_length_))) { LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); } else if (OB_FAIL(buffer_.append(")"))) { LOG_WARN("fail to append buffer_", K(ret)); - } else if (OB_FAIL(buffer_.append(","))) { + } else if (OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } } @@ -273,7 +281,7 @@ int ObGeoToWktVisitor::appendPolygon(T_IBIN *geo) typename T_BIN_INNER_RING::iterator iterInnerRing = inner_rings.begin(); for (; OB_SUCC(ret) && iterInnerRing != inner_rings.end(); ++iterInnerRing) { uint32_t size = iterInnerRing->size(); - uint64_t ring_len = 1 + (MAX_DIGITS_IN_DOUBLE * 2 + 1 + 1) * size + 1; + uint64_t ring_len = 1 + (MAX_DIGITS_IN_DOUBLE * 2 + 1) * size + 1; typename T_BIN_RING::iterator iter = (*iterInnerRing).begin(); if (OB_FAIL(buffer_.reserve(ring_len))) { LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); @@ -283,25 +291,25 @@ int ObGeoToWktVisitor::appendPolygon(T_IBIN *geo) for (; OB_SUCC(ret) && iter != (*iterInnerRing).end(); ++iter) { if (OB_FAIL(appendInnerPoint(iter->template get<0>(), iter->template get<1>()))) { LOG_WARN("fail to appendInnerPoint", K(ret), K(iter->template get<0>()), K(iter->template get<1>())); - } else if (OB_FAIL(buffer_.append(","))) { + } else if (OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } } if (OB_FAIL(ret)) { - } else if (OB_FAIL(buffer_.set_length(buffer_.length() - 1))) { + } else if (OB_FAIL(buffer_.set_length(buffer_.length() - comma_length_))) { LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); } else if (OB_FAIL(buffer_.append(")"))) { LOG_WARN("fail to append buffer_", K(ret)); - } else if (OB_FAIL(buffer_.append(","))) { + } else if (OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } } if (OB_FAIL(ret)) { - } else if (OB_FAIL(buffer_.set_length(buffer_.length() - 1))) { + } else if (OB_FAIL(buffer_.set_length(buffer_.length() - comma_length_))) { LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); } else if (OB_FAIL(buffer_.append(")"))) { LOG_WARN("fail to append buffer_", K(ret)); - } else if ((in_multi_visit_ || in_colloction_visit()) && OB_FAIL(buffer_.append(","))) { + } else if ((in_multi_visit_ || in_colloction_visit()) && OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } } @@ -314,11 +322,11 @@ int ObGeoToWktVisitor::appendMultiPrefix(T_IBIN *geo) { INIT_SUCC(ret); const char *type_name = ObGeoTypeUtil::get_geo_name_by_type(geo->type()); - uint64_t reserve_len = strlen(type_name) + 2; + uint64_t reserve_len = 2; // [type_name][(][x][ ][y][)] if (OB_FAIL(buffer_.reserve(reserve_len))) { LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); - } else if (OB_FAIL(buffer_.append(type_name))) { + } else if (OB_FAIL(appendTypeNameWithMode(geo))) { LOG_WARN("fail to append buffer_", K(ret), K(type_name)); } else if (OB_FAIL(buffer_.append("("))) { LOG_WARN("fail to append buffer_", K(ret)); @@ -329,11 +337,11 @@ int ObGeoToWktVisitor::appendMultiPrefix(T_IBIN *geo) int ObGeoToWktVisitor::appendMultiSuffix() { INIT_SUCC(ret); - if (OB_FAIL(buffer_.set_length(buffer_.length() - 1))) { + if (OB_FAIL(buffer_.set_length(buffer_.length() - comma_length_))) { LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); } else if (OB_FAIL(buffer_.append(")"))) { LOG_WARN("fail to append buffer_", K(ret)); - } else if ((in_colloction_visit()) && OB_FAIL(buffer_.append(","))) { + } else if ((in_colloction_visit()) && OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } return ret; @@ -346,11 +354,11 @@ int ObGeoToWktVisitor::appendCollectionPrefix(T_IBIN *geo) INIT_SUCC(ret); const char *type_name = ObGeoTypeUtil::get_geo_name_by_type(geo->type()); bool is_empty = (geo->size() == 0); - uint64_t reserve_len = strlen(type_name) + 2; + uint64_t reserve_len = 2; // [type_name][(][x][ ][y][)] if (OB_FAIL(buffer_.reserve(reserve_len))) { LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); - } else if (OB_FAIL(buffer_.append(type_name))) { + } else if (OB_FAIL(appendTypeNameWithMode(geo))) { LOG_WARN("fail to append buffer_", K(ret), K(type_name)); } else if (is_empty && OB_FAIL(buffer_.append(" EMPTY"))) { LOG_WARN("fail to append buffer_", K(ret)); @@ -366,7 +374,7 @@ int ObGeoToWktVisitor::appendCollectionSuffix(T_IBIN *geo) INIT_SUCC(ret); bool is_empty = (geo->size() == 0); if (!is_empty) { - if (buffer_.ptr()[buffer_.length() - 1] == ',' && OB_FAIL(buffer_.set_length(buffer_.length() - 1))) { + if (buffer_.ptr()[buffer_.length() - comma_length_] == ',' && OB_FAIL(buffer_.set_length(buffer_.length() - comma_length_))) { LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); } else if (OB_FAIL(buffer_.append(")"))) { LOG_WARN("fail to append buffer_", K(ret)); @@ -374,7 +382,7 @@ int ObGeoToWktVisitor::appendCollectionSuffix(T_IBIN *geo) } colloction_level_--; if (OB_FAIL(ret)) { - } else if ((in_colloction_visit()) && OB_FAIL(buffer_.append(","))) { + } else if ((in_colloction_visit()) && OB_FAIL(appendCommaWithMode())) { LOG_WARN("fail to append buffer_", K(ret)); } return ret; @@ -634,7 +642,9 @@ int ObGeoToWktVisitor::init(uint32_t srid, int64_t maxdecimaldigits) LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); } else if (OB_FAIL(buffer_.append("SRID="))) { LOG_WARN("fail to append buffer_", K(ret)); - } else if (OB_FAIL(buffer_.append(ffi.ptr(), ffi.length()))) { + } else if (srid == UINT32_MAX && OB_FAIL(buffer_.append("NULL"))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if (srid != UINT32_MAX && OB_FAIL(buffer_.append(ffi.ptr(), ffi.length()))) { LOG_WARN("fail to append buffer_", K(ret), K(ffi.length())); } else if (OB_FAIL(buffer_.append(";"))) { LOG_WARN("fail to append buffer_", K(ret)); @@ -645,8 +655,64 @@ int ObGeoToWktVisitor::init(uint32_t srid, int64_t maxdecimaldigits) scale_ = maxdecimaldigits; has_scale_ = true; } + + comma_length_ = is_oracle_mode_ ? 2 : 1; return ret; } +int ObGeoToWktVisitor::appendCommaWithMode() { + int ret = OB_SUCCESS; + // oracle [,][ ] + // mysql [,] + uint64_t reserve_len = is_oracle_mode_ ? 2 : 1; + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(","))) { + LOG_WARN("fail to append buffer_", K(ret), K(is_oracle_mode_)); + } else if (is_oracle_mode_ && OB_FAIL(buffer_.append(" "))) { + LOG_WARN("fail to append buffer_", K(ret), K(is_oracle_mode_)); + } + + return ret; +} + +template +int ObGeoToWktVisitor::appendTypeNameWithMode(T_IBIN *geo) { + int ret = OB_SUCCESS; + // oracle [typename][ ] + // mysql [typename] + const char *type_name = ObGeoTypeUtil::get_geo_name_by_type(geo->type()); + uint64_t reserve_len = strlen(type_name); + reserve_len += is_oracle_mode_ ? 1 : 0; + + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(type_name))) { + LOG_WARN("fail to append buffer_", K(ret), K(type_name)); + } else if (is_oracle_mode_ && OB_FAIL(buffer_.append(" "))) { + LOG_WARN("fail to append buffer_", K(ret), K(is_oracle_mode_)); + } + return ret; +} + +int ObGeoToWktVisitor::append_double_oracle(char *buff, + const int32_t buff_size, + uint64_t &out_len, + double value) +{ + int ret = OB_SUCCESS; + char number_buf[256] = {0}; + double abs_value = fabs(value); + out_len = snprintf(number_buf, 256, "%.15g", value); + if (out_len < 0 || out_len > buff_size) { + ret = OB_BUF_NOT_ENOUGH; + LOG_WARN("fail to val to string", K(ret), K(value)); + } else { + MEMCPY(buff, number_buf, out_len); + } + return ret; +} + + } // namespace common } // namespace oceanbase diff --git a/deps/oblib/src/lib/geo/ob_geo_to_wkt_visitor.h b/deps/oblib/src/lib/geo/ob_geo_to_wkt_visitor.h index afbe3b11f5..9ed7e3ecb9 100644 --- a/deps/oblib/src/lib/geo/ob_geo_to_wkt_visitor.h +++ b/deps/oblib/src/lib/geo/ob_geo_to_wkt_visitor.h @@ -28,7 +28,9 @@ public: : buffer_(allocator), has_scale_(false), in_multi_visit_(false), - colloction_level_(0) {} + colloction_level_(0), + is_oracle_mode_(lib::is_oracle_mode()), + comma_length_(1) {} ~ObGeoToWktVisitor() {} bool prepare(ObGeometry *geo) { UNUSED(geo); return true; } bool prepare(ObIWkbGeogMultiPoint *geo); @@ -83,8 +85,6 @@ private: typename T_BIN_RING, typename T_BIN_INNER_RING> int appendPolygon(T_IBIN *geo); int appendInnerPoint(double x, double y); - int append_double_with_prec(char *buff, const int32_t buff_size, uint64_t &out_len, double value); - template int appendMultiPrefix(T_IBIN *geo); int appendMultiSuffix(); @@ -93,12 +93,23 @@ private: template int appendCollectionSuffix(T_IBIN *geo); bool in_colloction_visit() { return colloction_level_ > 0; } + int appendCommaWithMode(); + template + int appendTypeNameWithMode(T_IBIN *geo); + +public: + static int convert_double_to_str(char* buff, uint64_t buff_size, double val, bool has_scale, + int16_t scale, bool is_oracle_mode, uint64_t &out_len); + static int append_double_oracle(char *buff, const int32_t buff_size, uint64_t &out_len, double value); + static int append_double_with_prec(char *buff, const int32_t buff_size, uint64_t &out_len, double value, int16_t scale); ObGeoStringBuffer buffer_; bool has_scale_; int64_t scale_; bool in_multi_visit_; int colloction_level_; + bool is_oracle_mode_; + uint64_t comma_length_; DISALLOW_COPY_AND_ASSIGN(ObGeoToWktVisitor); }; diff --git a/deps/oblib/src/lib/geo/ob_geo_tree.h b/deps/oblib/src/lib/geo/ob_geo_tree.h index e2bd123b46..323348e65d 100644 --- a/deps/oblib/src/lib/geo/ob_geo_tree.h +++ b/deps/oblib/src/lib/geo/ob_geo_tree.h @@ -172,6 +172,7 @@ public: iterator end() { return vec_.end(); } const_iterator end() const { return const_iterator(&*(const_cast *>(&vec_))->end()); } // ObArray& get_vec_() const { return vec_; } + int remove(int64_t idx) { return vec_.remove(idx); } private: common::ObArray vec_; @@ -849,6 +850,7 @@ public: const_iterator begin() const { return lines_.begin(); } iterator end() { return lines_.end(); } const_iterator end() const { return lines_.end(); } + int remove(int64_t idx) { return lines_.remove(idx); } TO_STRING_KV("type", "ObCartesianMultilinestring", "size", size()); @@ -1149,6 +1151,7 @@ public: typedef ObCartesianMultipolygon sub_mp_type; typedef ObCartesianMultipoint sub_mpt_type; typedef ObCartesianMultilinestring sub_ml_type; + typedef ObCartesianPoint sub_pt_type; public: ObCartesianGeometrycollection(uint32_t srid, ObIAllocator &allocator) @@ -1160,7 +1163,7 @@ public: : ObGeometrycollection(), mode_arena_(DEFAULT_PAGE_SIZE_GEO, page_allocator_), geoms_(&mode_arena_, common::ObModIds::OB_MODULE_PAGE_ALLOCATOR) {} - ~ObCartesianGeometrycollection() {} + ~ObCartesianGeometrycollection() { geoms_.clear(); } ObGeoCRS crs() const override { return ObGeoCRS::Cartesian; } // visitor interface int do_visit(ObIGeoVisitor &visitor); @@ -1210,6 +1213,7 @@ public: typedef ObGeographMultipolygon sub_mp_type; typedef ObGeographMultipoint sub_mpt_type; typedef ObGeographMultilinestring sub_ml_type; + typedef ObGeographPoint sub_pt_type; public: ObGeographGeometrycollection(uint32_t srid, ObIAllocator &allocator) @@ -1221,7 +1225,7 @@ public: : ObGeometrycollection(), mode_arena_(DEFAULT_PAGE_SIZE_GEO, page_allocator_), geoms_(&mode_arena_, common::ObModIds::OB_MODULE_PAGE_ALLOCATOR) {} - ~ObGeographGeometrycollection() {} + ~ObGeographGeometrycollection() { geoms_.clear(); } ObGeoCRS crs() const override { return ObGeoCRS::Geographic; } // visitor interface int do_visit(ObIGeoVisitor &visitor); diff --git a/deps/oblib/src/lib/geo/ob_geo_utils.cpp b/deps/oblib/src/lib/geo/ob_geo_utils.cpp index 9c197fe845..90d7cc5bc0 100644 --- a/deps/oblib/src/lib/geo/ob_geo_utils.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_utils.cpp @@ -30,12 +30,23 @@ #include "lib/geo/ob_geo_wkb_check_visitor.h" #include "lib/geo/ob_geo_normalize_visitor.h" #include "lib/geo/ob_geo_coordinate_range_visitor.h" +#include "lib/geo/ob_sdo_geo_object.h" +#include "lib/oblog/ob_log_module.h" +#include "lib/udt/ob_udt_type.h" +#include "lib/geo/ob_sdo_geo_func_to_wkb.h" +#include "lib/geo/ob_wkb_byte_order_visitor.h" +#include "lib/utility/ob_print_utils.h" +#include "lib/geo/ob_geo_3d.h" +#include "lib/geo/ob_geo_check_empty_visitor.h" +#include "lib/geo/ob_geo_box_clip_visitor.h" +#include "lib/geo/ob_geo_affine_visitor.h" +#include "lib/geo/ob_geo_simplify_visitor.h" +#include "lib/geo/ob_geo_grid_visitor.h" namespace oceanbase { namespace common { - // 这里只考虑进行非multi类型的比对,multi类型需额外处理 bool ObGeoTypeUtil::is_geo1_dimension_higher_than_geo2(ObGeoType type1, ObGeoType type2) { @@ -124,19 +135,33 @@ ObGeoType ObGeoTypeUtil::get_geo_type_by_name(ObString &name) if (0 == name.case_compare("point")) { geo_type = ObGeoType::POINT; + } else if (0 == name.case_compare("pointz") || 0 == name.case_compare("point z")) { + geo_type = ObGeoType::POINTZ; } else if (0 == name.case_compare("linestring")) { geo_type = ObGeoType::LINESTRING; + } else if (0 == name.case_compare("linestringz") || 0 == name.case_compare("linestring z")) { + geo_type = ObGeoType::LINESTRINGZ; } else if (0 == name.case_compare("polygon")) { geo_type = ObGeoType::POLYGON; + } else if (0 == name.case_compare("polygonz") || 0 == name.case_compare("polygon z")) { + geo_type = ObGeoType::POLYGONZ; } else if (0 == name.case_compare("multipoint")) { geo_type = ObGeoType::MULTIPOINT; + } else if (0 == name.case_compare("multipointz") || 0 == name.case_compare("multipoint z")) { + geo_type = ObGeoType::MULTIPOINTZ; } else if (0 == name.case_compare("multilinestring")) { geo_type = ObGeoType::MULTILINESTRING; + } else if (0 == name.case_compare("multilinestringz") || 0 == name.case_compare("multilinestring z")) { + geo_type = ObGeoType::MULTILINESTRINGZ; } else if (0 == name.case_compare("multipolygon")) { geo_type = ObGeoType::MULTIPOLYGON; + } else if (0 == name.case_compare("multipolygonz") || 0 == name.case_compare("multipolygon z")) { + geo_type = ObGeoType::MULTIPOLYGONZ; } else if (0 == name.case_compare("geometrycollection") || 0 == name.case_compare("geomcollection")) { geo_type = ObGeoType::GEOMETRYCOLLECTION; + } else if (0 == name.case_compare("geometrycollectionz") || 0 == name.case_compare("geometrycollection z")) { + geo_type = ObGeoType::GEOMETRYCOLLECTIONZ; } else if (0 == name.case_compare("geometry")) { geo_type = ObGeoType::GEOMETRY; } else { @@ -154,30 +179,105 @@ const char *ObGeoTypeUtil::get_geo_name_by_type(ObGeoType type) type_name = "POINT"; break; } + case ObGeoType::POINTZ:{ + type_name = "POINT Z"; + break; + } case ObGeoType::LINESTRING:{ type_name = "LINESTRING"; break; } + case ObGeoType::LINESTRINGZ:{ + type_name = "LINESTRING Z"; + break; + } case ObGeoType::POLYGON:{ type_name = "POLYGON"; break; } + case ObGeoType::POLYGONZ:{ + type_name = "POLYGON Z"; + break; + } case ObGeoType::MULTIPOINT:{ type_name = "MULTIPOINT"; break; } + case ObGeoType::MULTIPOINTZ:{ + type_name = "MULTIPOINT Z"; + break; + } case ObGeoType::MULTILINESTRING:{ type_name = "MULTILINESTRING"; break; } + case ObGeoType::MULTILINESTRINGZ:{ + type_name = "MULTILINESTRING Z"; + break; + } case ObGeoType::MULTIPOLYGON:{ type_name = "MULTIPOLYGON"; break; + } + case ObGeoType::MULTIPOLYGONZ:{ + type_name = "MULTIPOLYGON Z"; + break; } case ObGeoType::GEOMETRYCOLLECTION:{ type_name = "GEOMETRYCOLLECTION"; break; } + case ObGeoType::GEOMETRYCOLLECTIONZ:{ + type_name = "GEOMETRYCOLLECTION Z"; + break; + } + default:{ + LOG_WARN_RET(OB_INVALID_ARGUMENT, "unknown geometry type", K(type)); + break; + } + } + return type_name; +} + +const char *ObGeoTypeUtil::get_geo_name_by_type_oracle(ObGeoType type) +{ + const char *type_name = "UNKNOWN"; + switch (type) { + case ObGeoType::POINT: + case ObGeoType::POINTZ:{ + type_name = "POINT"; + break; + } + case ObGeoType::LINESTRING: + case ObGeoType::LINESTRINGZ:{ + type_name = "LINESTRING"; + break; + } + case ObGeoType::POLYGON: + case ObGeoType::POLYGONZ:{ + type_name = "POLYGON"; + break; + } + case ObGeoType::MULTIPOINT: + case ObGeoType::MULTIPOINTZ:{ + type_name = "MULTIPOINT"; + break; + } + case ObGeoType::MULTILINESTRING: + case ObGeoType::MULTILINESTRINGZ:{ + type_name = "MULTILINESTRING"; + break; + } + case ObGeoType::MULTIPOLYGON: + case ObGeoType::MULTIPOLYGONZ:{ + type_name = "MULTIPOLYGON"; + break; + } + case ObGeoType::GEOMETRYCOLLECTION: + case ObGeoType::GEOMETRYCOLLECTIONZ:{ + type_name = "GEOMETRYCOLLECTION"; + break; + } default:{ LOG_WARN_RET(OB_INVALID_ARGUMENT, "unknown geometry type", K(type)); break; @@ -186,6 +286,48 @@ const char *ObGeoTypeUtil::get_geo_name_by_type(ObGeoType type) return type_name; } +int ObGeoTypeUtil::get_st_geo_name_by_type(ObGeoType type, ObString &res) +{ + int ret = OB_SUCCESS; + res = "UNKNOWN"; + switch (type) { + case ObGeoType::POINT: { + res = "ST_Point"; + break; + } + case ObGeoType::LINESTRING: { + res = "ST_LineString"; + break; + } + case ObGeoType::POLYGON: { + res = "ST_Polygon"; + break; + } + case ObGeoType::MULTIPOINT: { + res = "ST_MultiPoint"; + break; + } + case ObGeoType::MULTILINESTRING: { + res = "ST_MultiLineString"; + break; + } + case ObGeoType::MULTIPOLYGON: { + res = "ST_MultiPolygon"; + break; + } + case ObGeoType::GEOMETRYCOLLECTION: { + res = "ST_GeometryCollection"; + break; + } + default: { + ret = OB_ERR_INVALID_GEOMETRY_TYPE; + LOG_WARN("unknown geometry type", K(ret), K(type)); + break; + } + } + return ret; +} + int ObGeoTypeUtil::create_geo_by_type(ObIAllocator &allocator, ObGeoType geo_type, bool is_geographical, @@ -195,26 +337,38 @@ int ObGeoTypeUtil::create_geo_by_type(ObIAllocator &allocator, { int ret = OB_SUCCESS; - if(is_geo_bin) { - if (is_geographical) { - ret = create_geo_bin_by_type(allocator, geo_type, geo, srid); + if (is_2d_geo_type(geo_type)) { + if(is_geo_bin) { + if (is_geographical) { + ret = create_geo_bin_by_type(allocator, geo_type, geo, srid); + } else { + ret = create_geo_bin_by_type(allocator, geo_type, geo, srid); + } } else { - ret = create_geo_bin_by_type(allocator, geo_type, geo, srid); + if (is_geographical) { + ret = create_geo_tree_by_type(allocator, geo_type, geo, srid); + } else { + ret = create_geo_tree_by_type(allocator, geo_type, geo, srid); + } + } + } else if (is_3d_geo_type(geo_type)) { + if (OB_ISNULL(geo = OB_NEWx(ObGeometry3D, (&allocator), srid, (&allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create 3d geo object", K(ret), K(geo_type)); + } else { + ObGeoCRS crs = is_geographical ? ObGeoCRS::Geographic : ObGeoCRS::Cartesian; + static_cast(geo)->set_crs(crs); } } else { - if (is_geographical) { - ret = create_geo_tree_by_type(allocator, geo_type, geo, srid); - } else { - ret = create_geo_tree_by_type(allocator, geo_type, geo, srid); - } + ret = OB_ERR_INVALID_GEOMETRY_TYPE; } if (OB_FAIL(ret)) { @@ -229,7 +383,8 @@ int ObGeoTypeUtil::create_geo_by_wkb(ObIAllocator &allocator, const ObSrsItem *srs, ObGeometry *&geo, bool need_check, /* = true */ - bool need_copy /* = true */) + bool need_copy, /* = true */ + bool allow_3d /* = false */) { int ret = OB_SUCCESS; @@ -241,6 +396,9 @@ int ObGeoTypeUtil::create_geo_by_wkb(ObIAllocator &allocator, ObGeoCRS crs = ObGeoCRS::Cartesian; if (OB_FAIL(ObGeoTypeUtil::get_header_info_from_wkb(swkb, header))) { LOG_WARN("fail to get swkb header info from swkb", K(ret), K(swkb)); + } else if (!allow_3d && is_3d_geo_type(header.type_)) { + ret = OB_ERR_INVALID_GEOMETRY_TYPE; + LOG_WARN("3d geo type is not allow", K(ret), K(header.type_)); } else if (OB_NOT_NULL(srs)) { crs = (srs->srs_type() == ObSrsType::PROJECTED_SRS) ? ObGeoCRS::Cartesian : ObGeoCRS::Geographic; @@ -273,14 +431,21 @@ int ObGeoTypeUtil::create_geo_by_wkb(ObIAllocator &allocator, if (OB_FAIL(ret)) { // do nothing } else if (need_check) { - ObGeoWkbCheckVisitor wkb_check(wkb, header.bo_, false); - ObIWkbGeometry *geo_bin = static_cast(geo); - if (OB_FAIL(geo->do_visit(wkb_check))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("fail to check swkb by swkb checker", K(ret), K(swkb), K(header), K(crs)); - } else if (geo->length() + offset != swkb.length()) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("invalid swkb length", K(ret), K(geo->length()), K(swkb.length()), K(offset)); + if (ObGeoTypeUtil::is_3d_geo_type(geo->type())) { + ObGeometry3D *geo_3d = static_cast(geo); + if (OB_FAIL(geo_3d->check_wkb_valid())) { + LOG_WARN("check wkb is invalid", K(ret)); + } + } else { + ObGeoWkbCheckVisitor wkb_check(wkb, header.bo_, false); + ObIWkbGeometry *geo_bin = static_cast(geo); + if (OB_FAIL(geo->do_visit(wkb_check))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("fail to check swkb by swkb checker", K(ret), K(swkb), K(header), K(crs)); + } else if (geo->length() + offset != swkb.length()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid swkb length", K(ret), K(geo->length()), K(swkb.length()), K(offset)); + } } } } @@ -289,14 +454,71 @@ int ObGeoTypeUtil::create_geo_by_wkb(ObIAllocator &allocator, return ret; } +int ObGeoTypeUtil::convert_geometry_3D_to_2D( + const ObSrsItem *srs, ObIAllocator &allocator, ObGeometry *g3d, uint8_t build_flag, ObGeometry *&geo) +{ + // 3d to 2d geo + int ret = OB_SUCCESS; + if (is_3d_geo_type(g3d->type())) { + ObGeoCRS crs = ObGeoCRS::Cartesian; + if (OB_NOT_NULL(srs)) { + crs = (srs->srs_type() == ObSrsType::PROJECTED_SRS) ? + ObGeoCRS::Cartesian : ObGeoCRS::Geographic; + } + ObString wkb_data; + ObGeometry3D *geo_3d = static_cast(g3d); + if (OB_FAIL(geo_3d->to_2d_geo(allocator, geo))) { + LOG_WARN("fail to convert 3d to 2d geo", K(ret), K(geo_3d->type())); + } else { + // geo has been transform to 2d + wkb_data.assign_ptr(geo->val(), geo->length()); + } + if (OB_SUCC(ret)) { + ObGeoWkbByteOrder bo = static_cast(*(wkb_data.ptr())); + bool need_check_ring = build_flag & ObGeoBuildFlag::GEO_CHECK_RING; + ObGeoWkbCheckVisitor wkb_check(wkb_data, bo, need_check_ring); + if (OB_FAIL(geo->do_visit(wkb_check))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid swkb", K(g3d->type()), K(g3d->get_srid()), K(crs)); + } + if (OB_SUCC(ret) && (build_flag & ObGeoBuildFlag::GEO_CORRECT) && + OB_FAIL(correct_polygon(allocator, srs, wkb_check.is_ring_closed(), *geo))) { + LOG_WARN("correct geo failed", K(ret), K(geo)); + } + } + } + return ret; +} + +int ObGeoTypeUtil::normalize_geometry(ObGeometry &geo, const ObSrsItem *srs) +{ + int ret = OB_SUCCESS; + uint32_t zoom_in_value = 0; + if (is_3d_geo_type(geo.type())) { + ObGeometry3D *geo_3d = static_cast(&geo); + if (OB_FAIL(geo_3d->normalize(srs, zoom_in_value))) { + LOG_WARN("fail to check coordinate range", K(ret)); + } + } else { + ObGeoNormalizeVisitor normalize_visitor(srs); + if (OB_FAIL(geo.do_visit(normalize_visitor))) { + LOG_WARN("normalize geo failed", K(ret)); + } else { + zoom_in_value = normalize_visitor.get_zoom_in_value(); + } + } + if (OB_SUCC(ret)) { + geo.set_zoom_in_value(zoom_in_value); + } + return ret; +} + int ObGeoTypeUtil::build_geometry(ObIAllocator &allocator, const ObString &swkb, ObGeometry *&geo, const ObSrsItem *srs, ObGeoErrLogInfo &log_info, - const bool need_normalize, /* = true */ - const bool need_check_ring, /* = false */ - const bool need_correct /* = true */) + uint8_t build_flag /* = ObGeoBuildFlag::DEFAULT */) { int ret = OB_SUCCESS; ObGeoWkbHeader header; @@ -310,12 +532,19 @@ int ObGeoTypeUtil::build_geometry(ObIAllocator &allocator, if (OB_FAIL(ObGeoTypeUtil::get_header_info_from_wkb(swkb, header))) { ret = OB_ERR_GIS_INVALID_DATA; LOG_WARN("get swkb header info from swkb failed", K(swkb), K(ret)); - } else if (ObGeoWkbByteOrder::BigEndian != header.bo_ && ObGeoWkbByteOrder::LittleEndian != header.bo_) { + } else if (ObGeoWkbByteOrder::LittleEndian != header.bo_) { ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("invalid byte order", K(swkb), K(ret)); - } else if (ObGeoType::GEOMETRY > header.type_ || ObGeoType::GEOTYPEMAX < header.type_) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("invalid geo type", K(ret), K(header.type_)); + LOG_WARN("invalid byte order", K(ret), K(header.bo_)); + } else if (ObGeoType::GEOMETRY > header.type_ || ObGeoType::GEOMETRYCOLLECTION < header.type_) { + if ((build_flag & ObGeoBuildFlag::GEO_ALLOW_3D) && is_3d_geo_type(header.type_)) { + // skip + } else { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid geo type", K(ret), K(header.type_)); + } + } + bool is_ring_closed = true; + if (OB_FAIL(ret)) { } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_type(allocator, header.type_, ObGeoCRS::Geographic == crs, @@ -334,34 +563,45 @@ int ObGeoTypeUtil::build_geometry(ObIAllocator &allocator, LOG_WARN("Failed to copy swkb memory", K(ret)); } else { geo->set_data(wkb_data); - ObGeoWkbCheckVisitor wkb_check(wkb, header.bo_, need_check_ring); - if (OB_FAIL(geo->do_visit(wkb_check))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("invalid swkb", K(swkb), K(header.type_), K(header.srid_), K(crs)); - } else if (geo->length() + offset != swkb.length()) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("invalid swkb length", K(ret), K(geo->length()), K(swkb.length()), K(offset)); - } else if (need_normalize && ObGeoCRS::Geographic == crs) { - ObGeoNormalizeVisitor normalize_visitor(srs); - if (OB_FAIL(geo->do_visit(normalize_visitor))) { - LOG_WARN("normalize geo failed", K(ret)); + if (!is_3d_geo_type(header.type_)) { + bool need_check_ring = build_flag & ObGeoBuildFlag::GEO_CHECK_RING; + ObGeoWkbCheckVisitor wkb_check(wkb_data, header.bo_, need_check_ring); + if (OB_FAIL(geo->do_visit(wkb_check))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid swkb", K(swkb), K(header.type_), K(header.srid_), K(crs)); + } else if (geo->length() + offset != swkb.length()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid swkb length", K(ret), K(geo->length()), K(swkb.length()), K(offset)); } else { - geo->set_zoom_in_value(normalize_visitor.get_zoom_in_value()); + is_ring_closed = wkb_check.is_ring_closed(); } - } - - if (OB_SUCC(ret) && need_correct && OB_FAIL(correct_polygon(allocator, srs, - wkb_check.is_ring_closed(), *geo))) { - LOG_WARN("correct geo failed", K(ret), K(geo)); + } else if (build_flag & GEO_RESERVE_3D) { + // do not convert to 2D geometry + } else if (OB_FAIL(convert_geometry_3D_to_2D(srs, allocator, geo, build_flag, geo))) { + // will do wkb check and polygon correct in convert_geometry_3D_to_2D + LOG_WARN("fail to convert 3D geometry to 2D", K(ret)); } } } - + // both 3D and 2D are available + if (OB_SUCC(ret) && (build_flag & ObGeoBuildFlag::GEO_NORMALIZE) && ObGeoCRS::Geographic == crs) { + if (OB_FAIL(normalize_geometry(*geo, srs))) { + LOG_WARN("fail to normalize geometry", K(ret)); + } + } + // only for 2D geometry + if (OB_SUCC(ret) && !is_3d_geo_type(geo->type()) && (build_flag & ObGeoBuildFlag::GEO_CORRECT)) { + if (OB_FAIL(correct_polygon(allocator, srs, is_ring_closed, *geo))) { + LOG_WARN("correct geo failed", K(ret), K(geo)); + } + } // check coordinate range if (OB_SUCC(ret) && ObGeoCRS::Geographic == crs) { - if (need_normalize && OB_FAIL(check_coordinate_range(srs, geo, log_info, true, true))) { + if (!(build_flag & ObGeoBuildFlag::GEO_CHECK_RANGE)) { + // do nothing + } else if ((build_flag & ObGeoBuildFlag::GEO_NORMALIZE) && OB_FAIL(check_coordinate_range(srs, geo, log_info, true, true))) { LOG_WARN("failed to check coordinate range", K(ret)); - } else if (!need_normalize && OB_FAIL(check_coordinate_range(srs, geo, log_info, true))) { + } else if (!(build_flag & ObGeoBuildFlag::GEO_NORMALIZE) && OB_FAIL(check_coordinate_range(srs, geo, log_info, true))) { LOG_WARN("failed to check coordinate range", K(ret)); } } @@ -382,7 +622,7 @@ int ObGeoTypeUtil::construct_geometry(ObIAllocator &allocator, const int64_t len = swkb.length(); const char *data = swkb.ptr(); ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::INVALID; - ObGeoType type = ObGeoType::GEOTYPEMAX; + ObGeoType type = ObGeoType::GEO3DTYPEMAX; ObString wkb; uint32_t offset = 0; if (OB_FAIL(ObGeoTypeUtil::get_wkb_from_swkb(swkb, wkb, offset))) { @@ -395,7 +635,7 @@ int ObGeoTypeUtil::construct_geometry(ObIAllocator &allocator, LOG_WARN("invalid byte order", K(ret), K(bo)); } else if (FALSE_IT(type = static_cast(ObGeoWkbByteOrderUtil::read( data + offset + WKB_GEO_BO_SIZE, bo)))) { - } else if (ObGeoType::POINT > type || ObGeoType::GEOTYPEMAX < type) { + } else if (!is_2d_geo_type(type) && !is_3d_geo_type(type)) { ret = OB_ERR_GIS_INVALID_DATA; LOG_WARN("invalid geo type", K(ret), K(type)); } else { @@ -434,6 +674,11 @@ int ObGeoTypeUtil::construct_geometry(ObIAllocator &allocator, if (OB_FAIL(ret)) { // do nothing + } else if (is_3d_geo_type(geo->type())) { + ObGeometry3D *geo_3d = static_cast(geo); + if (OB_FAIL(geo_3d->check_wkb_valid())) { + LOG_WARN("fail to check geo 3d is valid", K(ret)); + } } else { ObGeoWkbCheckVisitor wkb_check(wkb, bo, false); ObIWkbGeometry *geo_bin = static_cast(geo); @@ -486,45 +731,60 @@ int ObGeoTypeUtil::check_coordinate_range(const ObSrsItem *srs, const bool is_normalized /* = false */) { int ret = OB_SUCCESS; - ObGeoCoordinateRangeVisitor range_visitor(srs, is_normalized); + ObGeoCoordRangeResult result; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (is_3d_geo_type(geo->type())) { + ObGeometry3D *geo_3d = static_cast(geo); + if (OB_FAIL(geo_3d->check_3d_coordinate_range(srs, is_normalized, result))) { + LOG_WARN("fail to check coordinate range", K(ret)); + } + } else { + ObGeoCoordinateRangeVisitor range_visitor(srs, is_normalized); + if (OB_FAIL(geo->do_visit(range_visitor))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("failed to reverse geometry coordinate", K(ret)); + } else { + range_visitor.get_coord_range_result(result); + } + } - if (OB_FAIL(geo->do_visit(range_visitor))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("failed to reverse geometry coordinate", K(ret)); - } else if (range_visitor.is_longtitude_out_of_range()) { + if (OB_FAIL(ret)) { + } else if (result.is_long_out_range_) { // handle log user error message if (OB_FAIL(srs->longtitude_convert_from_radians(-M_PI, log_info.min_long_val_))) { LOG_WARN("failed to convert longitude from radians", K(ret)); } else if (OB_FAIL(srs->longtitude_convert_from_radians(M_PI, log_info.max_long_val_))) { LOG_WARN("failed to convert longitude from radians", K(ret)); } else { - log_info.value_out_of_range_ = range_visitor.value_out_of_range(); + log_info.value_out_of_range_ = result.value_out_range_; if (is_param) { ret = OB_ERR_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE; LOG_WARN("parameter geometry longitude is out of range", "longitude value", - range_visitor.value_out_of_range()); + result.value_out_range_); } else { ret = OB_ERR_LONGITUDE_OUT_OF_RANGE; LOG_WARN("geometry longitude is out of range", "longitude value", - range_visitor.value_out_of_range()); + result.value_out_range_); } } - } else if (range_visitor.is_latitude_out_of_range()) { + } else if (result.is_lati_out_range_) { // handle log user error message if (OB_FAIL(srs->latitude_convert_from_radians(-M_PI_2, log_info.min_lat_val_))) { LOG_WARN("failed to convert latitude from radians", K(ret)); } else if (OB_FAIL(srs->latitude_convert_from_radians(M_PI_2, log_info.max_lat_val_))) { LOG_WARN("failed to convert latitude from radians", K(ret)); } else { - log_info.value_out_of_range_ = range_visitor.value_out_of_range(); + log_info.value_out_of_range_ = result.value_out_range_; if (is_param) { ret = OB_ERR_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE; LOG_WARN("parameter geometry latitude is out of range", "latitude value", - range_visitor.value_out_of_range()); + result.value_out_range_); } else { ret = OB_ERR_LATITUDE_OUT_OF_RANGE; LOG_WARN("geometry latitude is out of range", "latitude value", - range_visitor.value_out_of_range()); + result.value_out_range_); } } } @@ -545,9 +805,9 @@ int ObGeoTypeUtil::get_buffered_geo(ObArenaAllocator *allocator, ObGeometry *geo = NULL; ObGeometry *res_geo = NULL; buf_strat.distance_val_ = distance; - - if (OB_FAIL(ObGeoTypeUtil::create_geo_by_wkb(*allocator, wkb_str, srs, geo, false))) { - LOG_WARN("failed to create geo by wkb", K(ret)); + ObGeoErrLogInfo log_info; + if (OB_FAIL(ObGeoTypeUtil::build_geometry(*allocator, wkb_str, geo, srs, log_info, ObGeoBuildFlag::GEO_ALLOW_3D))) { + LOG_WARN("fail to build geometry", K(ret)); } else if (OB_FAIL(gis_context.append_geo_arg(geo))) { LOG_WARN("failed to append geo arg to gis context", K(ret), K(gis_context.get_geo_count())); } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, correct_result))) { @@ -741,6 +1001,30 @@ int ObGeoTypeUtil::get_wkb_from_swkb(const ObString &swkb, ObString &wkb, uint32 return ret; } +double ObGeoTypeUtil::round_double(double x, int32_t dec, bool truncate) +{ + double dret = 0.0; + double pow_val = std::pow(10, static_cast(std::abs(dec))); + double val_mul_tmp = x * pow_val; + if (dec < 0 && std::isinf(pow_val)) { + dret = 0.0; + } else if (dec >= 0 && std::isinf(val_mul_tmp)) { + dret = x; + } else { + double val_div_tmp = x / pow_val; + if (truncate) { + if (x < 0) { + dret = dec < 0 ? std::ceil(val_div_tmp) * pow_val : std::ceil(val_mul_tmp) / pow_val; + } else { + dret = dec < 0 ? std::floor(val_div_tmp) * pow_val : std::floor(val_mul_tmp) / pow_val; + } + } else { + dret = dec < 0 ? std::rint(val_div_tmp) * pow_val : std::rint(val_mul_tmp) / pow_val; + } + } + return dret; +} + // ObGeoBoxUtil double ObGeoBoxUtil::vector_dot_product(const ObPoint3d &p3d1, const ObPoint3d &p3d2) { @@ -768,11 +1052,6 @@ void ObGeoBoxUtil::vector_minus(const ObPoint3d &p3d1, const ObPoint3d &p3d2, Ob res.z = p3d1.z - p3d2.z; } -bool ObGeoBoxUtil::is_float_equal(double left, double right) -{ - return fabs(left - right) <= FP_TOLERANCE; -} - bool ObGeoBoxUtil::is_same_point3d(const ObPoint3d &p3d1, const ObPoint3d &p3d2) { bool res = true; @@ -866,7 +1145,7 @@ int ObGeoBoxUtil::caculate_line_box(ObPoint3d &start, ObPoint3d &end, ObGeogBox box.ymax = start.y; box.zmin = start.z; box.zmax = start.z; - point_box_uion(end, box); + point_box_union(end, box); if (is_same_point3d(start, end)) { // do nothing @@ -905,7 +1184,7 @@ int ObGeoBoxUtil::caculate_line_box(ObPoint3d &start, ObPoint3d &end, ObGeogBox p3d.x = p2d_tmp.x * start.x + p2d_tmp.y * point3d.x; p3d.y = p2d_tmp.x * start.y + p2d_tmp.y * point3d.y; p3d.z = p2d_tmp.x * start.z + p2d_tmp.y * point3d.z; - point_box_uion(p3d, box); + point_box_union(p3d, box); } } } @@ -935,7 +1214,7 @@ void ObGeoBoxUtil::ob_geo_box_check_poles(ObGeogBox &box) do_set_poles(box.ymin, box.ymax, box.zmin, box.zmax, box.xmin, box.xmax); } -void ObGeoBoxUtil::point_box_uion(ObPoint3d &point, ObGeogBox &box) +void ObGeoBoxUtil::point_box_union(ObPoint3d &point, ObGeogBox &box) { box.xmin = OB_MIN(point.x, box.xmin); box.ymin = OB_MIN(point.y, box.ymin); @@ -945,7 +1224,7 @@ void ObGeoBoxUtil::point_box_uion(ObPoint3d &point, ObGeogBox &box) box.zmax = OB_MAX(point.z, box.zmax); } -void ObGeoBoxUtil::box_uion(ObGeogBox &box_tmp, ObGeogBox &box) +void ObGeoBoxUtil::box_union(const ObGeogBox &box_tmp, ObGeogBox &box) { box.xmin = OB_MIN(box_tmp.xmin, box.xmin); box.ymin = OB_MIN(box_tmp.ymin, box.ymin); @@ -1110,7 +1389,7 @@ int ObGeoBoxUtil::get_geog_poly_box(const ObWkbGeogPolygon &poly, ObGeogBox &box if (OB_FAIL(get_geog_line_box(*iter, box_tmp))) { LOG_WARN("failed to caculate line box", K(ret)); } else { - box_uion(box_tmp, box); + box_union(box_tmp, box); } } ob_geo_box_check_poles(box); @@ -1118,6 +1397,122 @@ int ObGeoBoxUtil::get_geog_poly_box(const ObWkbGeogPolygon &poly, ObGeogBox &box return ret; } +bool ObGeoBoxUtil::boxes_overlaps(const ObGeogBox &box1, const ObGeogBox &box2) { + bool bret = true; + if (box1.xmax < box2.xmin || box1.ymax < box2.ymin || + box1.xmin > box2.xmax || box1.ymin > box2.ymax) { + bret = false; + } + return bret; +} + +bool ObGeoBoxUtil::boxes_contains(const ObGeogBox &box1, const ObGeogBox &box2) +{ + bool bret = true; + if (box1.xmax < box2.xmax || box1.ymax < box2.ymax || + box1.xmin > box2.xmin || box1.ymin > box2.ymin) { + bret = false; + } + return bret; +} + +void ObGeoBoxUtil::get_point2d_from_geom_point(const ObWkbGeomInnerPoint &point, ObPoint2d &p2d) +{ + p2d.x = point.get<0>(); + p2d.y = point.get<1>(); +} + +int ObGeoBoxUtil::clip_by_box(ObGeometry &geo_in, ObIAllocator &allocator, const ObGeogBox &gbox, ObGeometry *&geo_out, bool is_called_in_pg_expr) +{ + int ret = OB_SUCCESS; + ObArenaAllocator tmp_allocator; + ObGeoEvalCtx box_ctx(&tmp_allocator); + box_ctx.set_is_called_in_pg_expr(is_called_in_pg_expr); // clip only used in PG expr currently + ObGeogBox *gbox_in = nullptr; + ObGeometry *geo_tree = nullptr; + ObGeometry *geo_bin = nullptr; + if (geo_in.is_tree()) { + geo_tree = &geo_in; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(allocator, geo_tree, geo_bin, nullptr))) { + LOG_WARN("fail to do tree to bin", K(ret)); + } + } else { + geo_bin = &geo_in; + ObGeoToTreeVisitor tree_visitor(&allocator); + if (OB_FAIL(geo_in.do_visit(tree_visitor))) { + LOG_WARN("fail to do tree visitor", K(ret)); + } else { + geo_tree = tree_visitor.get_geometry(); + } + } + if (OB_ISNULL(geo_tree) || OB_ISNULL(geo_bin)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for geometry", K(ret)); + } + // calculate 2d box of geo2, then convert the box to a rectangle geo + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(box_ctx.append_geo_arg(geo_bin))) { + LOG_WARN("build gis context failed", K(ret), K(box_ctx.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(box_ctx, gbox_in))) { + LOG_WARN("failed to do box functor failed", K(ret)); + } else if (boxes_contains(gbox, *gbox_in)) { + geo_out = &geo_in; + } else if (!boxes_overlaps(*gbox_in, gbox)) { + geo_out = OB_NEWx(ObCartesianGeometrycollection, &allocator, geo_in.get_srid(), allocator); + if (OB_ISNULL(geo_out)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory for geometry", K(ret)); + } + } else if (!ObGeoBoxUtil::is_box_valid(gbox)) { + geo_out = nullptr; + } else { + ObGeoBoxClipVisitor clip_visitor(gbox, allocator); + if (OB_FAIL(geo_tree->do_visit(clip_visitor))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + // pg behavior: return null + ret = OB_SUCCESS; + geo_out = nullptr; + } else { + LOG_WARN("fail to do tree visitor", K(ret)); + } + } else if (OB_FAIL(clip_visitor.get_geometry(geo_out))) { + LOG_WARN("fail to get geometry", K(ret)); + } else { + geo_out->set_srid(geo_in.get_srid()); + } + } + return ret; +} + +bool ObGeoBoxUtil::is_box_valid(const ObGeogBox &box) +{ + return !is_float_equal(box.xmin, box.xmax) && !is_float_equal(box.ymin, box.ymax); +} + +int ObGeoBoxUtil::get_geom_poly_box(const ObWkbGeomPolygon &poly, bool not_calc_inner_ring, ObGeogBox &res) +{ + int ret = OB_SUCCESS; + if (poly.size() <= 0) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("empty polygon has not box", K(ret), K(poly.size())); + } else if (OB_FAIL(get_geom_line_box(poly.exterior_ring(), res))) { + LOG_WARN("fail to get poly box", K(ret)); + } else if (!not_calc_inner_ring) { + const ObWkbGeomPolygonInnerRings &inners = poly.inner_rings(); + ObWkbGeomPolygonInnerRings::const_iterator iter = inners.begin(); + for (; OB_SUCC(ret) && iter != inners.end(); ++iter) { + ObGeogBox tmp_box; + if (OB_FAIL(get_geom_line_box(*iter, tmp_box))) { + LOG_WARN("fail to get poly box", K(ret)); + } else { + box_union(tmp_box, res); + } + } + } + return ret; +} + // 1. geometry类型可以存储所有其他空间类型; // 2. POINT, LINESTRING, 和 POLYGON只能存储各自对应的类型(由表达式校验); // 3. GEOMETRYCOLLECTION可以存储任何类型的对象的集合, @@ -1125,14 +1520,14 @@ int ObGeoBoxUtil::get_geog_poly_box(const ObWkbGeogPolygon &poly, ObGeogBox &box int ObGeoTypeUtil::check_geo_type(const ObGeoType column_type, const ObString &wkb_str) { int ret = OB_SUCCESS; - ObGeoType inser_type = ObGeoType::GEOTYPEMAX; + ObGeoType inser_type = ObGeoType::GEO3DTYPEMAX; if (wkb_str.empty()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("wkb str is empty", K(ret), K(wkb_str)); } else if (OB_FAIL(ObGeoTypeUtil::get_type_from_wkb(wkb_str, inser_type))) { LOG_WARN("fail to get geo type by wkb", K(ret), K(wkb_str)); - } else if (column_type >= ObGeoType::GEOTYPEMAX || inser_type >= ObGeoType::GEOTYPEMAX) { + } else if (column_type >= ObGeoType::GEOTYPEMAX || inser_type >= ObGeoType::GEO3DTYPEMAX) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid geo type", K(ret), K(column_type), K(inser_type)); } else if (ObGeoType::GEOMETRY == column_type) { @@ -1215,15 +1610,24 @@ int ObGeoTypeUtil::geo_to_ewkt(const ObString &swkb, } else if (geo->length() + offset != swkb.length()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid wkb", K(ret), K(geo->length()), K(swkb.length()), K(offset)); - } else if (OB_FAIL(wkt_visitor.init(header.srid_, max_decimal_digits))) { - LOG_WARN("failed to init wkt_visitor with srid_", K(ret), K(header.srid_)); - } else if (OB_FAIL(geo->do_visit(wkt_visitor))) { - LOG_WARN("failed to transform geo to wkt", K(ret)); - } else { - wkt_visitor.get_wkt(ewkt); - LOG_DEBUG("eval ob geometry type to ewkt", K(ewkt)); } - + if (OB_FAIL(ret)) { + // do nothing + } else if (is_3d_geo_type(geo->type())) { + ObGeometry3D *geo_3d = static_cast(geo); + if (OB_FAIL(geo_3d->to_wkt(allocator, ewkt, header.srid_))) { + LOG_WARN("fail to transform ewkt from 3d-wkb", K(ret)); + } + } else { + if (OB_FAIL(wkt_visitor.init(header.srid_, max_decimal_digits))) { + LOG_WARN("failed to init wkt_visitor with srid_", K(ret), K(header.srid_)); + } else if (OB_FAIL(geo->do_visit(wkt_visitor))) { + LOG_WARN("failed to transform geo to wkt", K(ret)); + } else { + wkt_visitor.get_wkt(ewkt); + LOG_DEBUG("eval ob geometry type to ewkt", K(ewkt)); + } + } return ret; } @@ -1684,5 +2088,636 @@ int ObGeoTypeUtil::eval_point_box_intersects(const ObSrsItem *srs_item, return ret; } -} // namespace common -} // namespace oceanbase +int ObGeoTypeUtil::geo_type_in_collection(uint64_t etype, uint64_t interpretation, ObGeoType &type) +{ + INIT_SUCC(ret); + type = ObGeoType::GEOMETRY; + + switch (etype) { + case 1: { + if (interpretation == 1) { + type = ObGeoType::POINT; + } else if (interpretation > 1) { + type = ObGeoType::MULTIPOINT; + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("the type is not supported", K(ret), K(interpretation), K(etype)); + } + break; + } + + case 2: { + if (interpretation == 1) { + type = ObGeoType::LINESTRING; + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("the type is not supported", K(ret), K(interpretation), K(etype)); + } + break; + } + + case 1003: { + if (interpretation == 1 || interpretation == 3) { + type = ObGeoType::POLYGON; + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("the type is not supported", K(ret), K(interpretation), K(etype)); + } + break; + } + + case 2003: { + if (interpretation == 1 || interpretation == 3) { + type = ObGeoType::POLYGON; + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("the type is not supported", K(ret), K(interpretation), K(etype)); + } + break; + } + + default: { + ret = OB_NOT_SUPPORTED; + LOG_WARN("the type is not supported", K(ret), K(interpretation), K(etype)); + break; + } + } + + return ret; +} + +int ObGeoTypeUtil::get_num_by_gtype(ObGeoType geo_type, uint64_t &num) +{ + int ret = OB_SUCCESS; + switch (geo_type) { + case ObGeoType::POINT : + num = 2001; + break; + case ObGeoType::POINTZ : + num = 3001; + break; + case ObGeoType::LINESTRING : + num = 2002; + break; + case ObGeoType::LINESTRINGZ : + num = 3002; + break; + case ObGeoType::POLYGON : + num = 2003; + break; + case ObGeoType::POLYGONZ : + num = 3003; + break; + case ObGeoType::MULTIPOINT : + num = 2005; + break; + case ObGeoType::MULTIPOINTZ : + num = 3005; + break; + case ObGeoType::MULTILINESTRING : + num = 2006; + break; + case ObGeoType::MULTILINESTRINGZ : + num = 3006; + break; + case ObGeoType::MULTIPOLYGON : + num = 2007; + break; + case ObGeoType::MULTIPOLYGONZ : + num = 3007; + break; + case ObGeoType::GEOMETRYCOLLECTION : + num = 2004; + break; + case ObGeoType::GEOMETRYCOLLECTIONZ : + num = 3004; + break; + default : + ret = OB_INVALID_ARGUMENT; + LOG_WARN("get num by gtype failed", K(ret), K(geo_type)); + } + return ret; +} + +int ObGeoTypeUtil::append_point(double x, double y, ObWkbBuffer &wkb_buf) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(wkb_buf.append(x))) { + LOG_WARN("fail to append x to point wkb buf", K(ret), K(x)); + } else if (OB_FAIL(wkb_buf.append(y))) { + LOG_WARN("fail to append y to point wkb buf", K(ret), K(y)); + } + return ret; +} + +int ObGeoTypeUtil::get_gtype_by_num(uint64_t num, ObGeoType &geo_type) +{ + int ret = OB_SUCCESS; + geo_type = ObGeoType::GEOTYPEMAX; + if (2001 == num || 3001 == num) { + geo_type = (2001 == num) ? ObGeoType::POINT : ObGeoType::POINTZ; + } else if (2002 == num || 3002 == num) { + geo_type = (2002 == num) ? ObGeoType::LINESTRING : ObGeoType::LINESTRINGZ; + } else if (2003 == num || 3003 == num) { + geo_type = (2003 == num) ? ObGeoType::POLYGON : ObGeoType::POLYGONZ; + } else if (2004 == num || 3004 == num) { + geo_type =(2004 == num) ? ObGeoType::GEOMETRYCOLLECTION : ObGeoType::GEOMETRYCOLLECTIONZ; + } else if (2005 == num || 3005 == num) { + geo_type = (2005 == num) ? ObGeoType::MULTIPOINT : ObGeoType::MULTIPOINTZ; + } else if (2006 == num || 3006 == num) { + geo_type = (2006 == num) ? ObGeoType::MULTILINESTRING : ObGeoType::MULTILINESTRINGZ; + } else if (2007 == num || 3007 == num) { + geo_type = (2007 == num) ? ObGeoType::MULTIPOLYGON : ObGeoType::MULTIPOLYGONZ; + } else { + ret = OB_ERR_INVALID_GTYPE_IN_SDO_GEROMETRY; + LOG_WARN("get type by num failed", K(ret), K(geo_type)); + } + + return ret; +} + +int ObGeoTypeUtil::rectangle_to_swkb(double xmin, double ymin, double xmax, double ymax, ObGeoSrid srid, bool with_version, ObWkbBuffer &wkb_buf) +{ + int ret = OB_SUCCESS; + const uint32_t RING_NUM = 1; + const uint32_t RING_POINT_NUM = 5; + if (OB_FAIL(wkb_buf.append(srid))) { + LOG_WARN("fail to append srid to polygon wkb buf", K(ret), K(srid)); + } else if (with_version && OB_FAIL(wkb_buf.append(static_cast(ENCODE_GEO_VERSION(GEO_VESION_1))))) { + // must have version info, or it will fail in ob_datum_cast + LOG_WARN("fail to append version to point wkb buf", K(ret)); + } else if (OB_FAIL(wkb_buf.append(static_cast(ObGeoWkbByteOrder::LittleEndian)))) { + LOG_WARN("fail to append little endian byte order to point wkb buf", K(ret)); + } else if (OB_FAIL(wkb_buf.append(static_cast(ObGeoType::POLYGON)))) { + LOG_WARN("fail to append geo type to polygon wkb buf", K(ret)); + } else if (OB_FAIL(wkb_buf.append(static_cast(RING_NUM)))) { + LOG_WARN("fail to append ring num to polygon wkb buf", K(ret)); + } else if (OB_FAIL(wkb_buf.append(static_cast(RING_POINT_NUM)))) { + LOG_WARN("fail to append ring point num to polygon wkb buf", K(ret)); + } else if (OB_FAIL(append_point(xmin, ymin, wkb_buf))) { + LOG_WARN("fail to append point to polygon wkb buf", K(ret), K(xmin), K(ymin)); + } else if (OB_FAIL(append_point(xmin, ymax, wkb_buf))) { + LOG_WARN("fail to append point to polygon wkb buf", K(ret), K(xmax), K(ymin)); + } else if (OB_FAIL(append_point(xmax, ymax, wkb_buf))) { + LOG_WARN("fail to append point to polygon wkb buf", K(ret), K(xmax), K(ymax)); + } else if (OB_FAIL(append_point(xmax, ymin, wkb_buf))) { + LOG_WARN("fail to append point to polygon wkb buf", K(ret), K(xmin), K(ymax)); + } else if (OB_FAIL(append_point(xmin, ymin, wkb_buf))) { + LOG_WARN("fail to append point to polygon wkb buf", K(ret), K(xmin), K(ymin)); + } + + return ret; +} + +int ObGeoTypeUtil::wkb_to_sdo_geo(const ObString &swkb, ObSdoGeoObject &sdo_geo, bool with_srid) +{ + int ret = OB_SUCCESS; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::INVALID; + ObGeoType gtype = ObGeoType::GEOMETRY; + ObArenaAllocator tmp_allocator; + uint32_t srid_offset = with_srid ? WKB_GEO_SRID_SIZE : 0; + ObString wkb = swkb; + if (with_srid) { + if (wkb.length() < (WKB_GEO_SRID_SIZE + WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid wkb length", K(wkb.length())); + } else { + wkb.assign_ptr(wkb.ptr() + srid_offset, wkb.length() - srid_offset); + } + } + // read bo and gtype + if (OB_FAIL(ret)) { + // do nothing + } else if (wkb.length() < (WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid wkb length", K(wkb.length())); + } else if (FALSE_IT(bo = static_cast(*(wkb.ptr())))) { + } else if ((bo != ObGeoWkbByteOrder::LittleEndian) && (bo != ObGeoWkbByteOrder::BigEndian)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("Byte order can only be either LITTLE_ENDIAN (encoded as 1) or BIG_ENDIAN (encoded as 0)", + K(ret), K(bo)); + } else { + const char *ptr = (const char *)(wkb.ptr() + WKB_GEO_BO_SIZE); + gtype = static_cast(ObGeoWkbByteOrderUtil::read(ptr, bo)); + } + + if (OB_FAIL(ret)) { + // do nothing + } else if (gtype >= ObGeoType::POINTZ && gtype <= ObGeoType::GEOMETRYCOLLECTIONZ) { + // 3d wkb + ObGeometry3D geo_3d; + geo_3d.set_data(wkb); + if (OB_FAIL(geo_3d.check_wkb_valid())) { + LOG_WARN("invalid 3d wkb", K(ret)); + } else if (OB_FAIL(geo_3d.to_sdo_geometry(sdo_geo))) { + LOG_WARN("failed to transform 3d geo to sdo geometry", K(ret)); + } + } else if (gtype >= ObGeoType::POINT && gtype <= ObGeoType::GEOMETRYCOLLECTION) { + // 2d wkb + ObGeometry *geo = NULL; + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_type(tmp_allocator, gtype, false, true, geo))) { + LOG_WARN("failed to create geo by wkb", K(ret), K(gtype)); + } else { + geo->set_data(wkb); + ObGeoWkbCheckVisitor wkb_check(wkb, bo, false); + if (OB_FAIL(geo->do_visit(wkb_check))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("fail to check wkb by wkb checker", K(ret), K(wkb)); + } else if (gtype >= ObGeoType::MULTIPOINT || bo == ObGeoWkbByteOrder::BigEndian) { + // bugfix: + // transform to LittleEndian + ObWkbByteOrderVisitor be_visitor(&tmp_allocator, ObGeoWkbByteOrder::LittleEndian); + if (OB_FAIL(geo->do_visit(be_visitor))) { + LOG_WARN("fail to transform big endian to little endian", K(ret)); + } else { + wkb = be_visitor.get_wkb(); + geo->set_data(wkb); + } + } + } + + if (OB_SUCC(ret)) { + ObIWkbGeometry *geo_bin = static_cast(geo); + ObWkbToSdoGeoVisitor sdo_visitor; + if (OB_FAIL(sdo_visitor.init(&sdo_geo))) { + LOG_WARN("failed to init sdo_visitor", K(ret)); + } else if (OB_FAIL(geo->do_visit(sdo_visitor))) { + LOG_WARN("failed to transform geo to sdo geometry", K(ret)); + } + } + } else { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("Unknown WKB label", K(ret), K(gtype)); + } + if (OB_SUCC(ret) && with_srid) { + uint32_t srid = ObGeoWkbByteOrderUtil::read(swkb.ptr(), bo); + sdo_geo.set_srid(srid); + } + return ret; +} + +int ObGeoTypeUtil::wkt_to_sdo_geo(const ObString &wkt, ObSdoGeoObject &sdo_geo) +{ + int ret = OB_SUCCESS; + ObArenaAllocator tmp_allocator; + ObGeometry *geo = NULL; + ObString wkb; + + // wkt -> geo -> wkb -> sdo_geo + // both geom and geog are ok + if (OB_FAIL(ObWktParser::parse_wkt(tmp_allocator, wkt, geo, true, false))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("failed to parse wkt", K(ret)); + } else if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geo after parse_wkt", K(ret), K(wkt)); + } else if (FALSE_IT(wkb.assign_ptr(geo->val(), geo->length()))) { + } else { + if (OB_FAIL(ObGeoTypeUtil::wkb_to_sdo_geo(wkb, sdo_geo))) { + LOG_WARN("fail to transfer wkb to sdo_geoetry", K(ret), K(wkb.length())); + } + } + + return ret; +} + +int ObGeoTypeUtil::number_to_double(const number::ObNumber &num_val, double &res) +{ + int ret = OB_SUCCESS; + char buf[MAX_DOUBLE_PRINT_SIZE] = {0}; + int64_t pos = 0; + if (OB_FAIL(num_val.format(buf, sizeof(buf), pos, -1))) { + LOG_WARN("fail to format number", K(ret), K(num_val)); + } else { + char *endptr = NULL; + int err = 0; + double val = ObCharset::strntod(buf, pos, &endptr, &err); + if (EOVERFLOW == err && (-DBL_MAX == res || DBL_MAX == res)) { + ret = OB_DATA_OUT_OF_RANGE; + LOG_WARN("faild to cast string to double, cause data is out of range", + K(ret), K(val), K(pos), K(num_val)); + } else { + res = val; + } + } + return ret; +} + +template +int ObGeoTypeUtil::get_number_obj_from_map(const QualifiedMap &map, const ObString &key, NumberObjType type, bool &is_null_result, RetType &res) +{ + int ret = OB_SUCCESS; + ObObj *const *obj_ptr; + ObObj *obj; + is_null_result = false; + + if (OB_ISNULL(obj_ptr = map.get(key))) { + is_null_result = true; + } else if (FALSE_IT(obj = *obj_ptr)) { + } else if (OB_ISNULL(obj)) { + is_null_result = true; + } else if (!obj->is_number()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("obj should be number type", K(ret), K(key), K(obj->get_type())); + } else if (type == NumberObjType::DOUBLE) { + double d_num = 0.0; + if (OB_FAIL(number_to_double(obj->get_number(), d_num))) { + LOG_WARN("fail to cast number to double", K(ret), K(key), K(d_num)); + } else { + res = d_num; + } + } else { + uint64_t i_num; + if (!obj->get_number().is_valid_uint64(i_num)) { + LOG_WARN("invalid srs type in sdo_geometry", K(ret), K(key), K(i_num)); + } else { + res = i_num; + } + } + + return ret; +} + +template +int ObGeoTypeUtil::get_varry_obj_from_map(const QualifiedMap &map, const ObString &key, const ObObjMeta &num_meta, NumberObjType type, ArrayType &array) +{ + int ret = OB_SUCCESS; + ObObj *const *obj_ptr; + ObObj *obj; + if (OB_ISNULL(obj_ptr = map.get(key))) { + // do nothing + } else if (FALSE_IT(obj = *obj_ptr)) { + } else if (OB_ISNULL(obj)) { + // do nothing + } else if (!obj->is_collection_sql_type()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("obj should be collection sql type", K(ret), K(obj->get_type())); + } else { + ObString varray_data = obj->get_string(); + ObLobLocatorV2 lob_locator(varray_data, true); + if (OB_FAIL(lob_locator.get_inrow_data(varray_data))) { + COMMON_LOG(WARN, "Lob: get lob inrow data failed", K(ret)); + } else if (varray_data.empty()) { + } else { + ObSqlUDT varray_handler; + varray_handler.set_data(varray_data); + uint64_t element_count = varray_handler.get_varray_element_count(); + ObString ser_element_data; + for (int64_t i = 0; OB_SUCC(ret) && i < element_count; i++) { + if (OB_FAIL(varray_handler.access_attribute(i, ser_element_data, true))) { + LOG_WARN("fail to access attribute buffer", K(ret)); + } else if (ser_element_data.empty()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("number in sdo_elem_info should not be null", K(ret)); + } else { + ObObj obj; + obj.set_meta_type(num_meta); + int64_t pos = 0; + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj, + ser_element_data.ptr(), + ser_element_data.length(), + pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(ser_element_data)); + } else if (type == NumberObjType::UINT64) { + uint64_t num; + if (!obj.get_number().is_valid_uint64(num)) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("is_valid_uint64 failed", K(ret), K(num)); + } else if (OB_FAIL(array.push_back(num))) { + LOG_WARN("fail to push item into array", K(ret), K(num)); + } + } else { + double d_num; + if (OB_FAIL(number_to_double(obj.get_number(), d_num))) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("is_valid_uint64 failed", K(ret), K(d_num)); + } else if (OB_FAIL(array.push_back(d_num))) { + LOG_WARN("fail to push item into array", K(ret), K(d_num)); + } + } + } + } + } + } + return ret; +} + +int ObGeoTypeUtil::sql_geo_obj_to_ewkt(const QualifiedMap &map, ObIAllocator &allocator, ObString &ewkt) +{ + int ret = OB_SUCCESS; + ObSdoGeoObject sdo_geometry; + bool is_null_result = false; + + uint64_t gtype_num; + ObGeoType gtype; + if (OB_FAIL(get_number_obj_from_map(map, "SDO_GTYPE", NumberObjType::UINT64, is_null_result, gtype_num)) || is_null_result) { + LOG_WARN("fail to get not null sdo_gtype", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::get_gtype_by_num(gtype_num, gtype))) { + LOG_WARN("fail to get_gtype_by_num", K(ret), K(gtype_num), K(gtype)); + } else { + sdo_geometry.set_gtype(gtype); + } + + uint64_t srid_tmp; + uint32_t srid; + bool srid_is_null = true; + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(get_number_obj_from_map(map, "SDO_SRID", NumberObjType::UINT64, srid_is_null, srid_tmp))) { + LOG_WARN("fail to get SDO_SRID", K(ret)); + } else if (!srid_is_null) { + if (srid_tmp > UINT32_MAX) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("srid is out of range", K(ret)); + } else { + srid = srid_tmp; + sdo_geometry.set_srid(srid); + } + } + + ObSdoPoint &point = sdo_geometry.get_point(); + double d_num; + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(get_number_obj_from_map(map, "SDO_POINT.X", NumberObjType::DOUBLE, is_null_result, d_num))) { + LOG_WARN("fail to get not null SDO_POINT.X", K(ret)); + } else if (is_null_result) { + // do nothing + } else if (FALSE_IT(point.set_x(d_num))) { + } else if (OB_FAIL(get_number_obj_from_map(map, "SDO_POINT.Y", NumberObjType::DOUBLE, is_null_result, d_num)) || is_null_result) { + LOG_WARN("fail to get not null SDO_POINT.Y", K(ret)); + } else if (FALSE_IT(point.set_y(d_num))) { + } else if (OB_FAIL(get_number_obj_from_map(map, "SDO_POINT.Z", NumberObjType::DOUBLE, is_null_result, d_num))) { + LOG_WARN("fail to get not null SDO_POINT.Z", K(ret)); + } else if (!is_null_result) { + point.set_z(d_num); + } + + ObArray &elem_info = sdo_geometry.get_elem_info(); + ObArray &ordinates = sdo_geometry.get_ordinates(); + if (OB_SUCC(ret)) { + const ObObjMeta &num_meta = (*map.get("SDO_GTYPE"))->get_meta(); + if (OB_FAIL(get_varry_obj_from_map(map, "SDO_ELEM_INFO", num_meta, NumberObjType::UINT64, elem_info))) { + LOG_WARN("fail to get SDO_ELEM_INFO from obj", K(ret), K(elem_info.size())); + } else if (OB_FAIL(get_varry_obj_from_map(map, "SDO_ORDINATES", num_meta, NumberObjType::DOUBLE, ordinates))) { + LOG_WARN("fail to get SDO_ORDINATES from obj", K(ret), K(ordinates.size())); + } + } + + if (OB_SUCC(ret)) { + ObSdoGeoToWkb trans(&allocator); + ObString swkb; + const int64_t WKT_DOUBLE_SCALE = 14; + if (OB_FAIL(trans.translate(&sdo_geometry, swkb, true, ObGeoWkbByteOrder::LittleEndian))) { + LOG_WARN("fail to transfer sdo_geometry to wkb", K(ret), K(swkb)); + } else if (OB_FAIL(ObGeoTypeUtil::geo_to_ewkt(swkb, ewkt, allocator, WKT_DOUBLE_SCALE))) { + LOG_WARN("fail to get ewkt from swkb", K(ret), K(swkb)); + } + } + + return ret; +} + +bool ObGeoTypeUtil::is_3d_geo_type(ObGeoType geo_type) { + return geo_type == ObGeoType::POINTZ || geo_type == ObGeoType::LINESTRINGZ || + geo_type == ObGeoType::POLYGONZ || geo_type == ObGeoType::MULTIPOINTZ || + geo_type == ObGeoType::MULTILINESTRINGZ || geo_type == ObGeoType::MULTIPOLYGONZ || + geo_type == ObGeoType::GEOMETRYCOLLECTIONZ; +} + +bool ObGeoTypeUtil::is_2d_geo_type(ObGeoType geo_type) { + return geo_type == ObGeoType::POINT || geo_type == ObGeoType::LINESTRING || + geo_type == ObGeoType::POLYGON || geo_type == ObGeoType::MULTIPOINT || + geo_type == ObGeoType::MULTILINESTRING || geo_type == ObGeoType::MULTIPOLYGON || + geo_type == ObGeoType::GEOMETRYCOLLECTION; +} + +int ObGeoTypeUtil::get_coll_dimension(ObIWkbGeomCollection *geo, int8_t &dimension) +{ + int ret = OB_SUCCESS; + const ObWkbGeomCollection *collection = reinterpret_cast(geo->val()); + ObWkbGeomCollection::iterator iter = collection->begin(); + uint64_t total_len = collection->length(); + uint64_t pos = WKB_COMMON_WKB_HEADER_LEN; + for (; iter != collection->end() && OB_SUCC(ret); iter++) { + typename ObWkbGeomCollection::const_pointer sub_ptr = iter.operator->(); + if (pos + WKB_GEO_TYPE_SIZE + WKB_GEO_BO_SIZE > total_len) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid wkb geo", K(ret), K(total_len), K(pos)); + } else { + ObGeoType sub_type = collection->get_sub_type(sub_ptr); + switch (sub_type) { + case ObGeoType::POINT: + case ObGeoType::MULTIPOINT: { + dimension = dimension >= 0 ? dimension : 0; + break; + } + case ObGeoType::LINESTRING: + case ObGeoType::MULTILINESTRING: { + dimension = dimension >= 1 ? dimension : 1; + break; + } + case ObGeoType::POLYGON: + case ObGeoType::MULTIPOLYGON: { + dimension = dimension >= 2 ? dimension : 2; + break; + } + case ObGeoType::GEOMETRYCOLLECTION: { + const ObWkbGeomCollection *subgc = reinterpret_cast(sub_ptr); + ObIWkbGeomCollection sub_collection; + ObString data(total_len - pos, reinterpret_cast(subgc)); + sub_collection.set_data(data); + if (OB_FAIL(get_coll_dimension(&sub_collection, dimension))) { + LOG_WARN("failed to do wkb geom sub collection visit", K(ret)); + } else { + pos += sub_collection.length(); + } + break; + } + default: { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid geo type", K(ret), K(sub_type)); + break; + } + } + } + } + return ret; +} + +double ObGeoTypeUtil::distance_point_squre(const ObWkbGeomInnerPoint& p1, const ObWkbGeomInnerPoint& p2) +{ + double x = p1.get<0>() - p2.get<0>(); + double y = p1.get<1>() - p2.get<1>(); + return x * x + y * y; +} + +int ObGeoTypeUtil::check_empty(ObGeometry *geo, bool &is_empty) +{ + INIT_SUCC(ret); + is_empty = false; + if (is_3d_geo_type(geo->type())) { + ObGeometry3D *geo3D = reinterpret_cast(geo); + if (OB_FAIL(geo3D->check_empty(is_empty))) { + LOG_WARN("fail to check 3D geometry empty", K(ret)); + } + } else { + ObGeoCheckEmptyVisitor check_empty_visitor; + if (OB_FAIL(geo->do_visit(check_empty_visitor))) { + LOG_WARN("check empty geo failed", K(ret)); + } else { + is_empty = check_empty_visitor.get_result(); + } + } + return ret; +} + +int ObGeoMVTUtil::affine_transformation(ObGeometry *geo, const ObAffineMatrix &affine) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("geometry can not be null", K(ret)); + } else { + ObGeoAffineVisitor affine_visitor(&affine); + if (OB_FAIL(geo->do_visit(affine_visitor))) { + LOG_WARN("fail to do affine visitor", K(ret)); + } + } + return ret; +} + +int ObGeoMVTUtil::snap_to_grid(ObGeometry *geo, const ObGeoGrid &grid, bool use_floor) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("geometry can not be null", K(ret)); + } else { + ObGeoGridVisitor grid_visitor(&grid, use_floor); + if (OB_FAIL(geo->do_visit(grid_visitor))) { + LOG_WARN("fail to do affine visitor", K(ret)); + } + } + return ret; +} + +int ObGeoMVTUtil::simplify_geometry(ObGeometry *geo, double tolerance, bool keep_collapsed) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("geometry can not be null", K(ret)); + } else { + ObGeoSimplifyVisitor simplify_visitor(tolerance, keep_collapsed); + if (OB_FAIL(geo->do_visit(simplify_visitor))) { + LOG_WARN("fail to do affine visitor", K(ret)); + } + } + return ret; +} + +} // namespace common +} // namespace oceanbase diff --git a/deps/oblib/src/lib/geo/ob_geo_utils.h b/deps/oblib/src/lib/geo/ob_geo_utils.h index ed22e862a1..953f6d39ef 100644 --- a/deps/oblib/src/lib/geo/ob_geo_utils.h +++ b/deps/oblib/src/lib/geo/ob_geo_utils.h @@ -19,17 +19,42 @@ #include "lib/geo/ob_geo_ibin.h" #include "lib/geo/ob_srs_info.h" #include "lib/geo/ob_s2adapter.h" +#include "lib/geo/ob_wkb_to_sdo_geo_visitor.h" +#include "lib/geo/ob_wkt_parser.h" +#include "lib/hash/ob_hashmap.h" +#include "lib/number/ob_number_v2.h" +#include "common/object/ob_object.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" namespace oceanbase { namespace common { +typedef common::hash::ObHashMap QualifiedMap; +enum class NumberObjType { + DOUBLE, + UINT64 +}; + +enum ObGeoBuildFlag: uint8_t { + GEO_ALL_DISABLE = 0x00, + GEO_NORMALIZE = 0x01, + GEO_CHECK_RING = 0x02, + GEO_CORRECT = 0x04, + GEO_ALLOW_3D = 0x08, + GEO_CHECK_RANGE = 0x10, + GEO_RESERVE_3D = 0x20, // do not convert 3D Geometry to 2D + GEO_DEFAULT = GEO_NORMALIZE | GEO_CORRECT | GEO_CHECK_RANGE, + GEO_ALLOW_3D_DEFAULT = GEO_DEFAULT | GEO_ALLOW_3D, +}; + class ObGeoTypeUtil { public: static const uint32_t EWKB_SRID_FLAG = 0x20000000; static const uint32_t EWKB_M_FLAG = 0x40000000; static const uint32_t EWKB_Z_FLAG = 0x80000000; + static const uint32_t WKB_3D_TYPE_OFFSET = 1000; static int create_geo_by_type(ObIAllocator &allocator, ObGeoType geo_type, bool is_geographical, @@ -41,15 +66,14 @@ public: const ObSrsItem *srs, ObGeometry *&geo, bool need_check = true, - bool need_copy = true); + bool need_copy = true, + bool allow_3d = false); static int build_geometry(ObIAllocator &allocator, const ObString &wkb, ObGeometry *&geo, const ObSrsItem *srs, ObGeoErrLogInfo &log_info, - const bool need_normlize = true, - const bool need_check_ring = false, - const bool need_correct = true); + uint8_t build_flag = ObGeoBuildFlag::GEO_DEFAULT); static int construct_geometry(ObIAllocator &allocator, const ObString &wkb, const ObSrsItem *srs, @@ -70,7 +94,9 @@ public: const ObSrsItem *srs, ObString &res_wkb); static ObGeoType get_geo_type_by_name(ObString &name); + static int get_gtype_by_num(uint64_t num, ObGeoType &geo_type); static const char *get_geo_name_by_type(ObGeoType type); + static const char *get_geo_name_by_type_oracle(ObGeoType type); static int get_header_info_from_wkb(const ObString &wkb, ObGeoWkbHeader &header); static int get_type_srid_from_wkb(const ObString &wkb, @@ -119,7 +145,27 @@ public: ObS2Cellids &cellids, ObString &mbr_val); static int get_wkb_from_swkb(const ObString &swkb, ObString &wkb, uint32_t &offset); + static int wkb_to_sdo_geo(const ObString &swkb, ObSdoGeoObject &geo, bool with_srid = false); + static int get_num_by_gtype(ObGeoType geo_type, uint64_t &num); + static int geo_type_in_collection(uint64_t etype, uint64_t interpretation, ObGeoType &type); + static int wkt_to_sdo_geo(const ObString &wkt, ObSdoGeoObject &sdo_geo); + static int sql_geo_obj_to_ewkt(const QualifiedMap &map, common::ObIAllocator &allocator, common::ObString &ewkt); + static int number_to_double(const number::ObNumber &num, double &res); + static bool is_3d_geo_type(ObGeoType geo_type); + static bool is_2d_geo_type(ObGeoType geo_type); + static int rectangle_to_swkb(double xmin, double ymin, double xmax, double ymax, ObGeoSrid srid, bool with_version, ObWkbBuffer &wkb_buf); + static int check_empty(ObGeometry *geo, bool &is_empty); + static int get_st_geo_name_by_type(ObGeoType type, ObString &res); + static int get_coll_dimension(ObIWkbGeomCollection *geo, int8_t &dimension); + static int convert_geometry_3D_to_2D(const ObSrsItem *srs, ObIAllocator &allocator, ObGeometry *g3d, + uint8_t build_flag, ObGeometry *&geo); + static int normalize_geometry(ObGeometry &geo, const ObSrsItem *srs); + static double round_double(double x, int32_t dec, bool truncate); + static double distance_point_squre(const ObWkbGeomInnerPoint& p1, const ObWkbGeomInnerPoint& p2); static int add_geo_version(ObIAllocator &allocator, const ObString &src, ObString &res_wkb); + // only check if polygon is a line or it's valid points are lesser than 4. + template + static int is_polygon_valid_simple(const ObGeometry *geo, bool &res); private: template static int create_geo_bin_by_type(ObIAllocator &allocator, @@ -139,8 +185,19 @@ private: uint32_t &offset); static int collection_close_ring(ObIAllocator &allocator, const ObString &wkb_in, ObGeoStringBuffer &res, uint32_t &geo_len); + template + static int get_number_obj_from_map(const QualifiedMap &map, const common::ObString &key, NumberObjType type, + bool &is_null_result, RetType &res); + template + static int get_varry_obj_from_map(const QualifiedMap &map, const common::ObString &key, + const common::ObObjMeta &num_meta, NumberObjType type, ArrayType &array); + static int append_point(double x, double y, ObWkbBuffer &wkb_buf); + template + static bool is_valid_ring_simple(const RingTree &ring); + DISALLOW_COPY_AND_ASSIGN(ObGeoTypeUtil); }; +// also used for geom (Cartesian) type typedef struct { double xmin; @@ -186,13 +243,13 @@ public: template static int get_geog_line_box(const GeometryType &line, ObGeogBox &box); static int get_geog_poly_box(const ObWkbGeogPolygon &poly, ObGeogBox &box); + static int get_geom_poly_box(const ObWkbGeomPolygon &poly, bool not_calc_inner_ring, ObGeogBox &res); static int caculate_line_box(ObPoint3d &start, ObPoint3d &end, ObGeogBox &box); static void get_box_center(const ObGeogBox &box, ObPoint2d ¢er); - static bool is_float_equal(double left, double right); static bool is_same_point3d(const ObPoint3d &p3d1, const ObPoint3d &p3d2); static bool is_completely_opposite(const ObPoint3d &p1, const ObPoint3d &p2); - static void point_box_uion(ObPoint3d &point, ObGeogBox &box); - static void box_uion(ObGeogBox &box_tmp, ObGeogBox &box); + static void point_box_union(ObPoint3d &point, ObGeogBox &box); + static void box_union(const ObGeogBox &box_tmp, ObGeogBox &box); static void convert_ll_to_cartesian3d(const ObWkbGeogInnerPoint &point, ObPoint3d &p3d); static double vector_dot_product(const ObPoint3d &p3d1, const ObPoint3d &p3d2); static void vector_cross_product(const ObPoint3d &p3d1, const ObPoint3d &p3d2, ObPoint3d &res); @@ -210,8 +267,68 @@ public: static void do_set_poles(const double &xmin, const double &xmax, const double &ymin, const double &ymax, double &zmin, double &zmax); + static void get_point2d_from_geom_point(const ObWkbGeomInnerPoint &point, ObPoint2d &p2d); + template + static int get_geom_line_box(const GeometryType &line, ObGeogBox &box); + static int clip_by_box(ObGeometry &geo_in, ObIAllocator &allocator, const ObGeogBox &box, ObGeometry *&geo_out, bool is_called_in_pg_expr); + static bool boxes_overlaps(const ObGeogBox &box1, const ObGeogBox &box2); + static bool boxes_contains(const ObGeogBox &box1, const ObGeogBox &box2); + template + static int fast_box(const GeometryType *g, ObGeogBox &box, bool &has_fast_box); + static inline bool is_float_equal(double left, double right) { return fabs(left - right) <= OB_GEO_TOLERANCE; } + static inline bool is_float_neq(double left, double right) { return fabs(left - right) > OB_GEO_TOLERANCE; } + static inline bool is_float_lt(double left, double right) { return (left + OB_GEO_TOLERANCE) < right; } + static inline bool is_float_lteq(double left, double right) { return (left - OB_GEO_TOLERANCE) <= right; } + static inline bool is_float_gt(double left, double right) { return (left - OB_GEO_TOLERANCE) > right; } + static inline bool is_float_gteq(double left, double right) { return (left + OB_GEO_TOLERANCE) >= right; } + static inline bool is_float_zero(double ft) { return fabs(ft) <= OB_GEO_TOLERANCE; } + static bool is_box_valid(const ObGeogBox &box); - static constexpr double FP_TOLERANCE = 5e-14; + static constexpr double OB_GEO_TOLERANCE = 5e-14; +}; + +/* +/ x_fac1 y_fac1 z_fac1 x_off \ / x \ +| x_fac2 y_fac2 z_fac2 y_off | | y | +| x_fac3 y_fac3 z_fac3 z_off | | z | +\ 0 0 0 1 / \ 1 / +*/ +typedef struct +{ + double x_fac1; + double y_fac1; + double z_fac1; + double x_fac2; + double y_fac2; + double z_fac2; + double x_fac3; + double y_fac3; + double z_fac3; + double x_off; + double y_off; + double z_off; +} ObAffineMatrix; +typedef struct +{ + // point of grid (x_ip, y_ip, z_ip) + double x_ip; + double y_ip; + double z_ip; + // length of grid + double x_size; + double y_size; + double z_size; +} ObGeoGrid; + +class ObGeoMVTUtil +{ +public: + // affine geometry in place + static int affine_transformation(ObGeometry *geo, const ObAffineMatrix &affine); + // snap to grid (aligned) + static int snap_to_grid(ObGeometry *geo, const ObGeoGrid &grid, bool use_floor); + static int simplify_geometry(ObGeometry *geo, double tolerance = 0.0, bool keep_collapsed = false); + DISALLOW_COPY_AND_ASSIGN(ObGeoMVTUtil); }; template @@ -235,7 +352,7 @@ int ObGeoBoxUtil::get_geog_line_box(const GeometryType &line, ObGeogBox &box) start = true; box = box_tmp; } else { - box_uion(box_tmp, box); + box_union(box_tmp, box); } p3d1 = p3d2; } @@ -355,6 +472,206 @@ int ObGeoTypeUtil::create_geo_tree_by_type(ObIAllocator &allocator, return ret; } +// only support PLINESTRING/MULTILINESTRING in catesian bin (ObWkbGeom) +template +int ObGeoBoxUtil::fast_box(const GeometryType *g, ObGeogBox &box, bool &has_fast_box) +{ + int ret = OB_SUCCESS; + has_fast_box = true; + switch (g->type()) { + case ObGeoType::POINT: { + const ObWkbGeomPoint *pt = reinterpret_cast(g); + if (OB_ISNULL(pt)) { + ret = OB_ERR_GIS_INVALID_DATA; + OB_LOG(WARN, "invalid null geometry", K(ret)); + } else { + box.xmin = box.xmax = pt->get<0>(); + box.ymin = box.ymax = pt->get<1>(); + } + break; + } + case ObGeoType::MULTIPOINT: { + const ObWkbGeomMultiPoint *pts = reinterpret_cast(g); + if (OB_ISNULL(pts)) { + ret = OB_ERR_GIS_INVALID_DATA; + OB_LOG(WARN, "invalid null geometry", K(ret)); + } else if (pts->size() != 1) { + has_fast_box = false; + } else { + ObWkbGeomMultiPoint::iterator iter = pts->begin(); + box.xmin = box.xmax = iter->get<0>(); + box.ymin = box.ymax = iter->get<1>(); + } + break; + } + case ObGeoType::LINESTRING: { + const ObWkbGeomLineString *line = reinterpret_cast(g); + if (OB_ISNULL(line)) { + ret = OB_ERR_GIS_INVALID_DATA; + OB_LOG(WARN, "invalid null geometry", K(ret)); + } else if (line->size() != 2) { + has_fast_box = false; + } else { + ObWkbGeomLineString::iterator iter = line->begin(); + ObPoint2d pt; + get_point2d_from_geom_point(*iter, pt); + box.xmin = box.xmax = pt.x; + box.ymin = box.ymax = pt.y; + ++iter; + get_point2d_from_geom_point(*iter, pt); + box.xmin = OB_MIN(box.xmin, pt.x); + box.xmax = OB_MAX(box.xmax, pt.x); + box.ymin = OB_MIN(box.ymin, pt.y); + box.ymax = OB_MAX(box.ymax, pt.y); + } + break; + } + case ObGeoType::MULTILINESTRING: { + const ObWkbGeomMultiLineString *line = reinterpret_cast(g); + if (OB_ISNULL(line)) { + ret = OB_ERR_GIS_INVALID_DATA; + OB_LOG(WARN, "invalid null geometry", K(ret)); + } else if (line->size() != 1) { + has_fast_box = false; + } else { + ObWkbGeomMultiLineString::iterator iter = line->begin(); + ret = fast_box(iter.operator->(), box, has_fast_box); + } + break; + } + default: { + // can not calculate fast box, but not a error + has_fast_box = false; + } + } + return ret; +} + +template +int ObGeoBoxUtil::get_geom_line_box(const GeometryType &line, ObGeogBox &box) +{ + int ret = OB_SUCCESS; + typename GeometryType::iterator iter = line.begin(); + ObPoint2d point; + get_point2d_from_geom_point(*iter, point); + box.xmax = point.x; + box.xmin = point.x; + box.ymax = point.y; + box.ymin = point.y; + for (++iter; OB_SUCC(ret) && iter != line.end(); ++iter) { + get_point2d_from_geom_point(*iter, point); + box.xmin = OB_MIN(point.x, box.xmin); + box.xmax = OB_MAX(point.x, box.xmax); + box.ymin = OB_MIN(point.y, box.ymin); + box.ymax = OB_MAX(point.y, box.ymax); + } + + return ret; +} + +template +bool ObGeoTypeUtil::is_valid_ring_simple(const RingTree &ring) +{ + // const ObCartesianLinearring &ring + bool is_valid = true; + int64_t sz = ring.size(); + if (sz < 3) { + is_valid = false; + } else { + int32_t min_pos = 0; + // find the point closest to the bottom left + for (uint32_t i = 1; i < sz; ++i) { + if (ring[i].template get<0>() < ring[min_pos].template get<0>()) { + min_pos = i; + } else if (ring[i].template get<0>() == ring[min_pos].template get<0>() + && ring[i].template get<1>() < ring[min_pos].template get<1>()) { + min_pos = i; + } + } + int64_t prev_pos = min_pos - 1; + if (min_pos == sz - 1) { + is_valid = false; + } else if (min_pos == 0) { + if (ring[sz - 1].template get<0>() == ring[min_pos].template get<0>() + && ring[sz - 1].template get<1>() == ring[min_pos].template get<1>()) { + prev_pos = sz - 2; + while (prev_pos >= 0 && ring[prev_pos].template get<0>() == ring[min_pos].template get<0>() + && ring[prev_pos].template get<1>() == ring[min_pos].template get<1>()) { + --prev_pos; + } + if (prev_pos < 0) { + is_valid = false; + } + } + } + if (is_valid) { + int64_t post_pos = min_pos + 1; + while (post_pos < sz && ring[post_pos].template get<0>() == ring[min_pos].template get<0>() + && ring[post_pos].template get<1>() == ring[min_pos].template get<1>()) { + ++post_pos; + } + if (post_pos == sz) { + is_valid = false; + } else { + double x1 = ring[min_pos].template get<0>() - ring[prev_pos].template get<0>(); + double y1 = ring[min_pos].template get<1>() - ring[prev_pos].template get<1>(); + double x2 = ring[post_pos].template get<0>() - ring[min_pos].template get<0>(); + double y2 = ring[post_pos].template get<1>() - ring[min_pos].template get<1>(); + double sign = x1 * y2 - x2 * y1; + if (sign == 0) { + is_valid = false; + } + } + } + } + + return is_valid; +} + +template +int ObGeoTypeUtil::is_polygon_valid_simple(const ObGeometry *geo, bool &res) +{ + int ret = OB_SUCCESS; + res = true; + const ObGeometry *geo_tree = nullptr; + ObArenaAllocator tmp_allocator; + if (!geo->is_tree()) { + ObGeoToTreeVisitor tree_visit(&tmp_allocator); + if (OB_FAIL(const_cast(geo)->do_visit(tree_visit))) { + OB_LOG(WARN, "fail to do tree visitor", K(ret)); + } else { + geo_tree = tree_visit.get_geometry(); + } + } else { + geo_tree = geo; + } + if (OB_FAIL(ret)) { + } else if (geo_tree->type() == ObGeoType::POLYGON) { + const PyTree &poly = reinterpret_cast(*geo_tree); + res = is_valid_ring_simple(poly.exterior_ring()); + for (int32_t i = 0; res && i < poly.inner_ring_size(); ++i) { + res = is_valid_ring_simple(poly.inner_ring(i)); + } + } else if (geo_tree->type() == ObGeoType::MULTIPOLYGON) { + const MpyTree &mpy = *reinterpret_cast(geo_tree); + for (int32_t i = 0; i < mpy.size() && res; ++i) { + res = is_valid_ring_simple(mpy[i].exterior_ring()); + for (int32_t j = 0; res && j < mpy[i].inner_ring_size(); ++j) { + res = is_valid_ring_simple(mpy[i].inner_ring(j)); + } + } + } else if (geo_tree->type() == ObGeoType::GEOMETRYCOLLECTION) { + const CollTree &coll = reinterpret_cast(*geo_tree); + for (int32_t i = 0; i < coll.size() && OB_SUCC(ret) && res; i++) { + if (OB_FAIL((is_polygon_valid_simple(&coll[i], res)))) { + OB_LOG(WARN, "failed to do tree item visit", K(ret)); + } + } + } + return ret; +} + + } // namespace common } // namespace oceanbase diff --git a/deps/oblib/src/lib/geo/ob_geo_wkb_check_visitor.cpp b/deps/oblib/src/lib/geo/ob_geo_wkb_check_visitor.cpp index 9dbb7c24aa..3c45eda628 100644 --- a/deps/oblib/src/lib/geo/ob_geo_wkb_check_visitor.cpp +++ b/deps/oblib/src/lib/geo/ob_geo_wkb_check_visitor.cpp @@ -18,7 +18,7 @@ namespace common { template -int ObGeoWkbCheckVisitor::check_common_header(T *geo, ObGeoType geo_type, ObGeoWkbByteOrder &bo) +int ObGeoWkbCheckVisitor::check_common_header(T *geo, ObGeoType geo_type, ObGeoWkbByteOrder bo) { // [bo][type][num] int ret = OB_SUCCESS; @@ -27,9 +27,10 @@ int ObGeoWkbCheckVisitor::check_common_header(T *geo, ObGeoType geo_type, ObGeoW LOG_WARN("invaid wkb geo", K(ret), K(wkb_.length()), K(pos_), K(geo_type)); } else { bo = static_cast(*(wkb_.ptr() + pos_)); - if (ObGeoWkbByteOrder::BigEndian != bo && ObGeoWkbByteOrder::LittleEndian != bo) { + if ((ObGeoWkbByteOrder::BigEndian != bo && ObGeoWkbByteOrder::LittleEndian != bo) + || (bo != bo_ && !lib::is_oracle_mode())) { // different byte order in wkb isn't supported in mysql mode ret = OB_INVALID_DATA; - LOG_WARN("invalid byte order", K(ret), K(pos_), K(geo_type), K(wkb_)); + LOG_WARN("invalid byte order", K(ret), K(pos_), K(geo_type), K(wkb_), K(bo), K(bo_)); } else { pos_ += WKB_GEO_BO_SIZE; ObGeoType type = static_cast(ObGeoWkbByteOrderUtil::read((wkb_.ptr() + pos_), bo)); @@ -38,6 +39,7 @@ int ObGeoWkbCheckVisitor::check_common_header(T *geo, ObGeoType geo_type, ObGeoW LOG_WARN("invalid geo type", K(ret), K(pos_), K(type), K(geo_type), K(wkb_)); } else { pos_ += WKB_GEO_TYPE_SIZE; + bo_ = bo; // for bigendian, liitle endian mixed } } } @@ -49,17 +51,17 @@ int ObGeoWkbCheckVisitor::check_line_string(T *geo) { // [bo][type][num][X][Y][...] int ret = OB_SUCCESS; - ObGeoWkbByteOrder bo; - if (OB_FAIL(check_common_header(geo, ObGeoType::LINESTRING, bo))) { + if (OB_FAIL(check_common_header(geo, ObGeoType::LINESTRING, bo_))) { LOG_WARN("invaid wkb linestring", K(ret), K(wkb_.length()), K(pos_), K(ObGeoType::LINESTRING)); } else { - uint32_t po_num = ObGeoWkbByteOrderUtil::read((wkb_.ptr() + pos_), bo); - if (po_num > MAX_N_POINTS) { + uint32_t po_num = ObGeoWkbByteOrderUtil::read((wkb_.ptr() + pos_), bo_); + int32_t len = wkb_.length() - pos_; + if ((po_num > MAX_N_POINTS) || (po_num < 2)) { ret = OB_INVALID_DATA; LOG_WARN("invalid point number", K(ret), K(pos_), K(po_num), K(ObGeoType::LINESTRING), K(wkb_)); - } else if (po_num < 2) { + } else if (po_num * WKB_POINT_DATA_SIZE > len) { ret = OB_INVALID_DATA; - LOG_WARN("invalid point number", K(ret), K(pos_), K(po_num), K(ObGeoType::LINESTRING), K(wkb_)); + LOG_WARN("invalid wkb length", K(ret), K(pos_), K(po_num), K(wkb_.length()), K(ObGeoType::LINESTRING)); } else { pos_ += WKB_GEO_ELEMENT_NUM_SIZE; if (wkb_.length() < po_num * WKB_POINT_DATA_SIZE + pos_) { @@ -116,8 +118,7 @@ template int ObGeoWkbCheckVisitor::check_point(T *geo) { int ret = OB_SUCCESS; - ObGeoWkbByteOrder bo; - if (OB_FAIL(check_common_header(geo, ObGeoType::POINT, bo))) { + if (OB_FAIL(check_common_header(geo, ObGeoType::POINT, bo_))) { LOG_WARN("invaid wkb point", K(ret), K(wkb_), K(pos_)); } else if (wkb_.length() < pos_ + WKB_POINT_DATA_SIZE) { ret = OB_INVALID_DATA; @@ -133,14 +134,17 @@ int ObGeoWkbCheckVisitor::check_multipoint(T *geo) { // [bo][type][num][point][...] int ret = OB_SUCCESS; - ObGeoWkbByteOrder bo; - if (OB_FAIL(check_common_header(geo, ObGeoType::MULTIPOINT, bo))) { + if (OB_FAIL(check_common_header(geo, ObGeoType::MULTIPOINT, bo_))) { LOG_WARN("invaid wkb linestring", K(ret), K(wkb_.length()), K(pos_), K(ObGeoType::MULTIPOINT)); } else { - uint32_t po_num = ObGeoWkbByteOrderUtil::read((wkb_.ptr() + pos_), bo); + uint32_t po_num = ObGeoWkbByteOrderUtil::read((wkb_.ptr() + pos_), bo_); + uint32_t len = wkb_.length() - pos_; if (po_num > MAX_MULIT_POINTS || po_num < 1) { ret = OB_INVALID_DATA; LOG_WARN("invalid point number of multi_point", K(ret), K(pos_), K(po_num), K(wkb_)); + } else if (len < po_num * (WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE + WKB_POINT_DATA_SIZE)) { + ret = OB_INVALID_DATA; + LOG_WARN("invalid wkb length", K(ret), K(pos_), K(po_num), K(wkb_.length()), K(ObGeoType::MULTIPOINT)); } else { pos_ += WKB_GEO_ELEMENT_NUM_SIZE; for (uint32_t i = 0; i < po_num && OB_SUCC(ret); i++) { @@ -158,8 +162,7 @@ int ObGeoWkbCheckVisitor::check_geometrycollection(T *geo) { // [bo][type][num][line][...] int ret = OB_SUCCESS; - ObGeoWkbByteOrder bo; - if (OB_FAIL(check_common_header(geo, ObGeoType::GEOMETRYCOLLECTION, bo))) { + if (OB_FAIL(check_common_header(geo, ObGeoType::GEOMETRYCOLLECTION, bo_))) { LOG_WARN("invaid wkb geo", K(ret), K(wkb_), K(pos_), K(ObGeoType::GEOMETRYCOLLECTION)); } else { pos_ += WKB_GEO_ELEMENT_NUM_SIZE; @@ -172,14 +175,17 @@ int ObGeoWkbCheckVisitor::check_multi_geo(T *geo, ObGeoType geo_type) { // [bo][type][num][line][...] int ret = OB_SUCCESS; - ObGeoWkbByteOrder bo; - if (OB_FAIL(check_common_header(geo, geo_type, bo))) { + if (OB_FAIL(check_common_header(geo, geo_type, bo_))) { LOG_WARN("invaid wkb geo", K(ret), K(wkb_), K(pos_), K(geo_type)); } else { - uint32_t geo_num = ObGeoWkbByteOrderUtil::read((wkb_.ptr() + pos_), bo); + uint32_t geo_num = ObGeoWkbByteOrderUtil::read((wkb_.ptr() + pos_), bo_); + uint32_t len = wkb_.length() - pos_; if (geo_num < 1) { ret = OB_INVALID_DATA; LOG_WARN("invaid geo number", K(ret), K(wkb_), K(pos_), K(geo_num), K(geo_type)); + } else if (len < geo_num * (WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE + WKB_POINT_DATA_SIZE)) { + ret = OB_INVALID_DATA; + LOG_WARN("invalid wkb length", K(ret), K(pos_), K(geo_num), K(wkb_.length()), K(geo_type)); } pos_ += WKB_GEO_ELEMENT_NUM_SIZE; } diff --git a/deps/oblib/src/lib/geo/ob_geo_wkb_check_visitor.h b/deps/oblib/src/lib/geo/ob_geo_wkb_check_visitor.h index b1e0b0865f..4a26243d47 100644 --- a/deps/oblib/src/lib/geo/ob_geo_wkb_check_visitor.h +++ b/deps/oblib/src/lib/geo/ob_geo_wkb_check_visitor.h @@ -72,7 +72,7 @@ private: bool is_ring_closed_; template - int check_common_header(T *geo, ObGeoType geo_type, ObGeoWkbByteOrder &bo); + int check_common_header(T *geo, ObGeoType geo_type, ObGeoWkbByteOrder bo); template int check_point(T *geo); template diff --git a/deps/oblib/src/lib/geo/ob_geometry_cast.cpp b/deps/oblib/src/lib/geo/ob_geometry_cast.cpp index fb04e1570e..3bfa7923ad 100644 --- a/deps/oblib/src/lib/geo/ob_geometry_cast.cpp +++ b/deps/oblib/src/lib/geo/ob_geometry_cast.cpp @@ -126,7 +126,7 @@ int ObGeometryTypeCastUtil::get_tree(ObIAllocator &allocator, int ret = OB_SUCCESS; ObGeometry *geo = NULL; - if (OB_FAIL(ObGeoTypeUtil::build_geometry(allocator, wkb, geo, srs, log_info, true, false))) { + if (OB_FAIL(ObGeoTypeUtil::build_geometry(allocator, wkb, geo, srs, log_info))) { LOG_WARN("fail to build geometry from wkb", K(ret)); } else if (geo->is_tree()) { geo_tree = geo; @@ -185,6 +185,26 @@ bool ObGeometryTypeCastUtil::is_line_can_ring(const L &line) return is_point_equal(*begin, *last); } +bool ObGeometryTypeCastUtil::is_sdo_geometry_varray_type(uint64_t udt_id) +{ + return udt_id == T_OBJ_SDO_ELEMINFO_ARRAY || udt_id == T_OBJ_SDO_ORDINATE_ARRAY; +} + +bool ObGeometryTypeCastUtil::is_sdo_geometry_udt(uint64_t udt_id) +{ + return udt_id >= T_OBJ_SDO_POINT && udt_id <= T_OBJ_SDO_ORDINATE_ARRAY; +} + +bool ObGeometryTypeCastUtil::is_sdo_geometry_type_compatible(uint64_t src_udt_id, uint64_t dst_udt_id) +{ + bool bret = true; + if (!is_sdo_geometry_varray_type(src_udt_id) || !is_sdo_geometry_varray_type(dst_udt_id)) { + // only allow varray (elem_info/ordiante_array) cast to each other + bret = false; + } + return bret; +} + int ObGeometryTypeCastFactory::alloc(ObIAllocator &alloc, ObGeoType geo_type, ObGeometryTypeCast *&geo_cast) diff --git a/deps/oblib/src/lib/geo/ob_geometry_cast.h b/deps/oblib/src/lib/geo/ob_geometry_cast.h index 14b1476e09..e01d90894b 100644 --- a/deps/oblib/src/lib/geo/ob_geometry_cast.h +++ b/deps/oblib/src/lib/geo/ob_geometry_cast.h @@ -49,7 +49,10 @@ public: const common::ObSrsItem *srs, double val); static const char *get_cast_name(common::ObGeoType type); + static bool is_sdo_geometry_type_compatible(uint64_t src_udt_id, uint64_t dst_udt_id); + static bool is_sdo_geometry_udt(uint64_t udt_id); private: + static bool is_sdo_geometry_varray_type(uint64_t udt_id); DISALLOW_COPY_AND_ASSIGN(ObGeometryTypeCastUtil); }; diff --git a/deps/oblib/src/lib/geo/ob_s2adapter.cpp b/deps/oblib/src/lib/geo/ob_s2adapter.cpp index 70ee31c7f4..555bdc4448 100644 --- a/deps/oblib/src/lib/geo/ob_s2adapter.cpp +++ b/deps/oblib/src/lib/geo/ob_s2adapter.cpp @@ -18,6 +18,7 @@ #include "lib/geo/ob_geo_utils.h" #include "lib/geo/ob_geo_bin.h" #include "lib/geo/ob_geo_ibin.h" +#include "lib/geo/ob_geo_3d.h" #include #include @@ -328,6 +329,15 @@ int64_t ObS2Adapter::init(const ObString &swkb, const ObSrsBoundsItem *bound) LOG_WARN("fail to get wkb from swkb", K(ret), K(swkb)); } else { geo->set_data(wkb); + if (ObGeoTypeUtil::is_3d_geo_type(type)) { + ObGeometry3D *geo_3d = static_cast(geo); + if (OB_FAIL(geo_3d->to_2d_geo(*allocator_, geo))) { + LOG_WARN("fail to convert 3d geo to 2d", K(ret)); + } + } + } + + if (OB_SUCC(ret)) { geo_ = geo; if (OB_FAIL(geo->do_visit(*visitor_))) { LOG_WARN("fail to do_visit by ObWkbToS2Visitor", K(ret)); diff --git a/deps/oblib/src/lib/geo/ob_sdo_geo_func_to_wkb.cpp b/deps/oblib/src/lib/geo/ob_sdo_geo_func_to_wkb.cpp new file mode 100644 index 0000000000..7aec4a943f --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_sdo_geo_func_to_wkb.cpp @@ -0,0 +1,811 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "lib/geo/ob_sdo_geo_func_to_wkb.h" + +namespace oceanbase +{ +namespace common +{ +int ObSdoGeoToWkb::normalize_point(double &lon, double &lat) +{ + // If the value entered is outside LONG/LAT range, + // the value is wrapped around to fit into the range + INIT_SUCC(ret); + double lat_right_margin = 90; + double lon_right_margin = 180; + + if (lat < -90.0 || lat > 90.0) { + // bool need_offset = (lat >= 270.0 || lat <= -270.0) ? true : false; + bool need_offset = false; + // wrapped around to [-90, 90] + int64_t quad = std::floor(std::abs(lat) / lat_right_margin); + quad %= 4; + double pole = (lat > 0) ? 90.0 : -90.0; + double offset = fmod(lat, lat_right_margin); + switch(quad) + { + case 0: { + lat = offset; + need_offset = true; + break; + } + case 1: { + lat = pole - offset; + if (offset == 0) { + need_offset = true; + } + break; + } + case 2: { + lat = -offset; + break; + } + case 3: { + lat = offset - pole; + need_offset = true; + break; + } + default: { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("fail to normalize latitude", K(ret), K(lat)); + } + } + // wrapped around to [-180, 180] + lon += need_offset ? 180.0 : 0.0; + if (fmod(lon, 360.0) == 0) { + lon = 180; + } else if (fmod(lon, 180.0) == 0) { + lon = 0; + } else { + double sign_lon = lon > 0.0 ? 1.0 : -1.0; + lon = (fmod(abs(lon), 360.0) - 180.0) * sign_lon; + } + } else if (lon > 180.0 || lon < -180.0) { + // wrapped around to [-180, 180] + lon += 180.0; + double sign = lon > 0.0 ? 1.0 : -1.0; + lon = (fmod(abs(lon), 360.0) - 180.0) * sign; + if (lon == -180) { + lon = -lon; + } + } + + return ret; +} + +template +int ObSdoGeoToWkb::append_num_with_endian(T data, uint64_t len) +{ + INIT_SUCC(ret); + char *p = reinterpret_cast(&data); + if (iorder_ == static_cast(ObGeoWkbByteOrder::BigEndian)) { + for(uint64_t i = 0; i < len / 2; i++) { + char tmp = p[i]; + p[i] = p[len - 1 - i]; + p[len - 1 - i] = tmp; + } + } + + if (OB_FAIL(buffer_.append(p, len))) { + ret = OB_BUF_NOT_ENOUGH; + LOG_WARN("failed to write buffer", K(ret), K(len)); + } + return ret; +} + +int ObSdoGeoToWkb::append_inner_point(double x, double y, double z, int swap_idx) +{ + INIT_SUCC(ret); + if (swap_idx == 0) { + double tmp = z; + z = x; + x = tmp; + } else if (swap_idx == 1) { + double tmp = z; + z = y; + y = tmp; + } + if (srs_type_ == ObSrsType::GEOGRAPHIC_SRS && need_normalize_ && OB_FAIL(normalize_point(x, y))) { + LOG_WARN("failed to normalize point in GEOGRAPHIC_SRS", K(ret), K(x), K(y), K(srs_type_)); + } else if (OB_FAIL(append_num_with_endian(x, WKB_GEO_DOUBLE_STORED_SIZE))) { + LOG_WARN("failed to write x value", K(ret), K(x)); + } else if (OB_FAIL(append_num_with_endian(y, WKB_GEO_DOUBLE_STORED_SIZE))) { + LOG_WARN("failed to write y value", K(ret), K(y)); + } else if (is_3d_geo_) { + if (isnan(z)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid z value", K(ret)); + } else if (OB_FAIL(append_num_with_endian(z, WKB_GEO_DOUBLE_STORED_SIZE))) { + LOG_WARN("failed to write y value", K(ret), K(z)); + } + } + + return ret; +} + +int ObSdoGeoToWkb::append_inner_point(const ObArray &ordinates, const uint64_t idx) +{ + INIT_SUCC(ret); + uint8_t len = is_3d_geo_ ? 3 : 2; + if (idx + len > ordinates.size()) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", + K(ret), + K(idx), + K(len), + K(ordinates.size())); + } else { + double x = ordinates[idx]; + double y = ordinates[idx + 1]; + double z = NAN; + if (is_3d_geo_) { + z = ordinates[idx + 2]; + } + if (OB_FAIL(append_inner_point(x, y, z))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret)); + } + } + return ret; +} + +int ObSdoGeoToWkb::append_point(ObSdoGeoObject *geo, int64_t idx) +{ + INIT_SUCC(ret); + uint32_t wkb_type = (is_3d_geo_ && !oracle_3d_format_) ? + static_cast(ObGeoType::POINTZ) : static_cast(ObGeoType::POINT); + uint64_t reserve_len = WKB_GEO_DOUBLE_STORED_SIZE * (is_3d_geo_ ? 3 : 2); // x y + reserve_len += is_multi_visit_ ? EWKB_COMMON_WKB_HEADER_LEN : WKB_COMMON_WKB_HEADER_LEN; + + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory to buffer_", K(ret), K(reserve_len)); + } else if (!is_multi_visit_ + && OB_FAIL(append_num_with_endian(geo->get_srid(), WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append srid to buffer_", K(ret), K(geo->get_srid())); + } else if (OB_FAIL(append_num_with_endian(iorder_, WKB_GEO_BO_SIZE))) { + LOG_WARN("fail to append order to buffer_", K(ret), K(iorder_)); + } else if (OB_FAIL(append_num_with_endian(wkb_type, WKB_GEO_TYPE_SIZE))) { + LOG_WARN("fail to append wkb_type to buffer_", K(ret), K(wkb_type)); + } else if (idx >= 0) { + size_t ori_size = geo->get_ordinates().size(); + if (idx >= ori_size) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", + K(ret), + K(idx), + K(ori_size)); + } else if (OB_FAIL(append_inner_point(geo->get_ordinates(), idx))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret)); + } + } else if (geo->has_point()) { + if (OB_FAIL(append_inner_point(geo->get_point().get_x(), geo->get_point().get_y(), + geo->get_point().has_z() ? geo->get_point().get_z() : NAN))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret)); + } + } else { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", K(ret), K(idx)); + } + + return ret; +} + +// ccw: Counter ClockWise +int ObSdoGeoToWkb::inner_append_rectangle(double lower_left_x, double lower_left_y, double upper_right_x, + double upper_right_y, uint64_t sdo_etype, bool is_ccw, double fix_z, int swap_idx) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(append_inner_point(lower_left_x, lower_left_y, fix_z, swap_idx))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret), K(lower_left_x), K(lower_left_y)); + } else if (is_ccw) { + // append lower left -> lower right -> upper right -> upper left -> lower left + if (OB_FAIL(append_inner_point(upper_right_x, lower_left_y, fix_z, swap_idx))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret), K(upper_right_x), K(lower_left_y)); + } else if (OB_FAIL(append_inner_point(upper_right_x, upper_right_y, fix_z, swap_idx))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret), K(upper_right_x), K(upper_right_y)); + } else if (OB_FAIL(append_inner_point(lower_left_x, upper_right_y, fix_z, swap_idx))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret), K(lower_left_x), K(upper_right_y)); + } + } else { + // append lower left -> upper left -> upper right -> lower right -> lower left + if (OB_FAIL(append_inner_point(lower_left_x, upper_right_y, fix_z, swap_idx))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret), K(upper_right_x), K(lower_left_y)); + } else if (OB_FAIL(append_inner_point(upper_right_x, upper_right_y, fix_z, swap_idx))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret), K(upper_right_x), K(upper_right_y)); + } else if (OB_FAIL(append_inner_point(upper_right_x, lower_left_y, fix_z, swap_idx))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret), K(lower_left_x), K(upper_right_y)); + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(append_inner_point(lower_left_x, lower_left_y, fix_z, swap_idx))) { + LOG_WARN("fail to append innerpoint to buffer_", K(ret), K(lower_left_x), K(lower_left_y)); + } + return ret; +} + +int ObSdoGeoToWkb::append_3D_rectangle(double x1, double y1, double x2, double y2, double fix_z, + uint64_t sdo_etype, int fix_idx) +{ + int ret = OB_SUCCESS; + bool is_ccw = true; + if (x2 > x1 && y2 > y1) { + is_ccw = true; + } else if (x2 < x1 && y2 < y1) { + is_ccw = false; + } else { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", K(ret)); + } + if (OB_SUCC(ret)) { + is_ccw = (fix_idx == 1) ? !is_ccw : is_ccw; + if (OB_FAIL(inner_append_rectangle(x1, y1, x2, y2, sdo_etype, is_ccw, fix_z, fix_idx))) { + LOG_WARN("fail to do inner append rectangle", K(ret), K(x1), K(y1), K(x2), K(y2)); + } + } + return ret; +} + +int ObSdoGeoToWkb::append_rectangle(ObSdoGeoObject *geo, size_t idx, uint64_t sdo_etype) +{ + INIT_SUCC(ret); + size_t step = is_3d_geo_ ? 3 : 2; + uint64_t reserve_len = + WKB_GEO_ELEMENT_NUM_SIZE + RECTANGLE_POINT_NUM * step * WKB_GEO_DOUBLE_STORED_SIZE; + const ObArray &ori = geo->get_ordinates(); + if ((idx + 2 * step - 1) >= ori.size()) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", + K(ret), + K(ori.size()), + K(idx)); + } else { + double x1 = ori[idx]; + double x2 = ori[idx + step]; + double y1 = ori[idx + 1]; + double y2 = ori[idx + step + 1]; + // bugfix: 52443172 + // rectangle should normalize first + if (srs_type_ == ObSrsType::GEOGRAPHIC_SRS && need_normalize_) { + if (OB_FAIL(normalize_point(x1, y1))) { + LOG_WARN("failed to normalize point in GEOGRAPHIC_SRS", K(ret), K(x1), K(y1), K(srs_type_)); + } else if (OB_FAIL(normalize_point(x2, y2))) { + LOG_WARN("failed to normalize point in GEOGRAPHIC_SRS", K(ret), K(x2), K(y2), K(srs_type_)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (OB_FAIL(append_num_with_endian(RECTANGLE_POINT_NUM, WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append point num buffer_", K(ret)); + } else if (is_3d_geo_) { + // a legal 3D rectangle should have only one same axis + double z1 = ori[idx + 2]; + double z2 = ori[idx + step + 2]; + int32_t same_axis_num = x1 == x2 ? 1 : 0; + same_axis_num = y1 == y2 ? same_axis_num + 1: same_axis_num; + same_axis_num = z1 == z2 ? same_axis_num + 1 : same_axis_num; + if (same_axis_num != 1) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", + K(ret), + K(same_axis_num)); + } else if (x1 == x2 && OB_FAIL(append_3D_rectangle(y1, z1, y2, z2, x1, sdo_etype, 0))) { + LOG_WARN("fail to append 3D rectangle", K(ret)); + } else if (y1 == y2 && OB_FAIL(append_3D_rectangle(x1, z1, x2, z2, y1, sdo_etype, 1))) { + LOG_WARN("fail to append 3D rectangle", K(ret)); + } else if (z1 == z2 && OB_FAIL(append_3D_rectangle(x1, y1, x2, y2, z1, sdo_etype, 2))) { + LOG_WARN("fail to append 3D rectangle", K(ret)); + } + } else { + if (OB_FAIL(inner_append_rectangle(x1, y1, x2, y2, sdo_etype, sdo_etype == EXTRING_ETYPE))) { + LOG_WARN("fail to do inner append rectangle", K(ret), K(x1), K(y1), K(x2), K(y2)); + } + } + } + return ret; +} + +int ObSdoGeoToWkb::append_inner_ring(ObSdoGeoObject *geo, size_t ori_begin, size_t ori_end) +{ + INIT_SUCC(ret); + uint64_t reserve_len = WKB_GEO_ELEMENT_NUM_SIZE; + reserve_len += (ori_end - ori_begin) * WKB_GEO_DOUBLE_STORED_SIZE; + size_t step = is_3d_geo_ ? 3 : 2; + uint32_t num_points = (ori_end - ori_begin + step - 1) / step; + + if (ori_begin >= geo->get_ordinates().size() || ((ori_end - ori_begin) % step)) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", + K(ret), + K(geo->get_ordinates().size()), + K(ori_begin), + K(ori_end)); + } else if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (OB_FAIL(append_num_with_endian(num_points, WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(num_points)); + } else { + // x y + const ObArray &ordinates = geo->get_ordinates(); + for (size_t i = 0; OB_SUCC(ret) && i < num_points; ++i) { + if (OB_FAIL(append_inner_point(ordinates, i * step + ori_begin))) { + LOG_WARN("fail to append_inner_point", K(ret)); + } + } + } + + return ret; +} + +int ObSdoGeoToWkb::append_linestring(ObSdoGeoObject *geo, size_t ori_begin, size_t ori_end) +{ + INIT_SUCC(ret); + uint32_t wkb_type = (is_3d_geo_ && !oracle_3d_format_) ? + static_cast(ObGeoType::LINESTRINGZ) : static_cast(ObGeoType::LINESTRING); + uint64_t reserve_len = is_multi_visit_ ? EWKB_COMMON_WKB_HEADER_LEN : WKB_COMMON_WKB_HEADER_LEN; + size_t step = is_3d_geo_ ? 3 : 2; + uint32_t num_points = (ori_end - ori_begin + step - 1) / step; + + if ((ori_begin >= geo->get_ordinates().size()) || (num_points < 1)) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", + K(ret), + K(geo->get_ordinates().size()), + K(ori_begin), + K(ori_end)); + } else if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (!is_multi_visit_ + && OB_FAIL(append_num_with_endian(geo->get_srid(), WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if (OB_FAIL(append_num_with_endian(iorder_, WKB_GEO_BO_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if (OB_FAIL(append_num_with_endian(wkb_type, WKB_GEO_TYPE_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(wkb_type)); + } else if (OB_FAIL(append_inner_ring(geo, ori_begin, ori_end))) { + LOG_WARN("fail to append inner ring", K(ret)); + } + + return ret; +} + +int ObSdoGeoToWkb::append_polygon(ObSdoGeoObject *geo, size_t elem_begin, size_t elem_end) +{ + INIT_SUCC(ret); + const ObArray &elem_info = geo->get_elem_info(); + if (elem_end > elem_info.size() || elem_begin >= elem_end) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", + K(ret), + K(elem_info.size()), + K(elem_begin), + K(elem_end)); + } else if (!is_multi_visit_) { + if (OB_FAIL(buffer_.reserve(WKB_GEO_SRID_SIZE))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret)); + } else if (OB_FAIL(append_num_with_endian(geo->get_srid(), WKB_GEO_SRID_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(geo->get_srid())); + } + } + + if (OB_FAIL(ret)) { + // do nothing + } else if (elem_info[elem_begin + 1] != EXTRING_ETYPE) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("the first ring in polygon should be exterior ring", K(ret), K(elem_info[elem_begin + 1])); + } else { + int32_t wkb_type = (is_3d_geo_ && !oracle_3d_format_) ? + static_cast(ObGeoType::POLYGONZ) : static_cast(ObGeoType::POLYGON); + uint64_t reserve_len = WKB_GEO_ELEMENT_NUM_SIZE + EWKB_COMMON_WKB_HEADER_LEN; + uint32_t num_rings = (elem_end - elem_begin) / 3; + + if (num_rings < 1) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("invalid input arguments", K(ret), K(num_rings), K(is_multi_visit_)); + } else if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (OB_FAIL(append_num_with_endian(iorder_, WKB_GEO_BO_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if (OB_FAIL(append_num_with_endian(wkb_type, WKB_GEO_TYPE_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(wkb_type)); + } else if (OB_FAIL(append_num_with_endian(num_rings, WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(num_rings)); + } + } + + size_t ori_end = 0; + for (size_t i = elem_begin; OB_SUCC(ret) && i < elem_end; i += 3) { + uint64_t sdo_etype = elem_info[i + 1]; + uint64_t expected_etype = (i == elem_begin) ? EXTRING_ETYPE : INNERRING_ETYPE; + if (sdo_etype != expected_etype) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("polygon ring with wrong sdo_etype", K(ret), K(sdo_etype), K(expected_etype)); + } else { + size_t ori_begin = elem_info[i] - 1; + if (elem_end >= elem_info.size()) { + ori_end = (i + 3) < elem_end ? (elem_info[i + 3] - 1) : geo->get_ordinates().size(); + } else { + ori_end = (i + 3) <= elem_end ? (elem_info[i + 3] - 1) : geo->get_ordinates().size(); + } + size_t step = is_3d_geo_ ? 3 : 2; + uint32_t num_points = (ori_end - ori_begin + step - 1) / step; + uint64_t sdo_interpre = elem_info[i + 2]; + if (sdo_interpre == 3) { + if (num_points != 2) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("invalid input arguments", K(ret), K(ori_begin), K(ori_end), K(is_3d_geo_)); + } else if (OB_FAIL(append_rectangle(geo, ori_begin, sdo_etype))) { + LOG_WARN("fail to append Rectangle", K(ret), K(ori_begin)); + } + } else if (num_points <= 0 || sdo_interpre != 1) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("invalid input arguments", K(ret), K(ori_begin), K(ori_end)); + } else if (OB_FAIL(append_inner_ring(geo, ori_begin, ori_end))) { + LOG_WARN("fail to append inner ring", K(ret), K(ori_begin), K(ori_end)); + } + } + } + + return ret; +} + +int ObSdoGeoToWkb::append_multi_point(ObSdoGeoObject *geo, size_t elem_begin, size_t elem_end) +{ + INIT_SUCC(ret); + uint32_t num_points = 0; + const ObArray &elem_info = geo->get_elem_info(); + for (size_t i = elem_begin; i < elem_end; i += 3) { + num_points += elem_info[i + 2]; + } + size_t step = is_3d_geo_ ? 3 : 2; + if ((elem_end - elem_begin) % 3 != 0) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", + K(ret), + K(geo->get_ordinates().size())); + } else if (num_points == 1 && is_deduce_dim_) { + // bugfix: + if (geo->get_ordinates().size() > step) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("Invalid data in the SDO_ELEM_INFO_ARRAY in SDO_GEOMETRY object", K(ret), K(step), K(geo->get_ordinates().size())); + } else if (OB_FAIL(append_point(geo, elem_info[elem_begin] - 1))) { + LOG_WARN("fail to append point"); + } + } else { + uint32_t wkb_type = (is_3d_geo_ && !oracle_3d_format_) ? + static_cast(ObGeoType::MULTIPOINTZ) : static_cast(ObGeoType::MULTIPOINT); + uint64_t reserve_len = WKB_GEO_ELEMENT_NUM_SIZE; + reserve_len += is_multi_visit_ ? EWKB_COMMON_WKB_HEADER_LEN : WKB_COMMON_WKB_HEADER_LEN; + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (!is_multi_visit_ + && OB_FAIL(append_num_with_endian(geo->get_srid(), WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append srid to buffer_", K(ret), K(geo->get_srid())); + } else if (OB_FAIL(append_num_with_endian(iorder_, WKB_GEO_BO_SIZE))) { + LOG_WARN("fail to append order to buffer_", K(ret), K(iorder_)); + } else if (OB_FAIL(append_num_with_endian(wkb_type, WKB_GEO_TYPE_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(wkb_type)); + } else if (OB_FAIL(append_num_with_endian(num_points, WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(wkb_type)); + } else { + // not sub geom in collection, but still a multi visit + if (!is_multi_visit_) { + is_multi_visit_ = true; + } + size_t idx = 0; + for (size_t i = elem_begin; OB_SUCC(ret) && i < elem_end; i += 3) { + uint32_t num_pt = elem_info[i + 2]; + size_t ori_begin = elem_info[i] - 1; + for (size_t j = 0; OB_SUCC(ret) && j < num_pt; ++j) { + idx = ori_begin + j * step; + if (OB_FAIL(append_point(geo, idx))) { + LOG_WARN("fail to append_point", K(ret), K(j)); + } + } + } + if (OB_FAIL(ret)) { + // do nothing + } else if (elem_end >= elem_info.size() && (idx + step) != geo->get_ordinates().size()) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("Invalid data in the SDO_ELEM_INFO_ARRAY in SDO_GEOMETRY object", K(ret), K(idx), K(step)); + } + } + } + + return ret; +} + +int ObSdoGeoToWkb::append_multi_linestring(ObSdoGeoObject *geo) +{ + INIT_SUCC(ret); + uint32_t wkb_type = (is_3d_geo_ && !oracle_3d_format_) ? + static_cast(ObGeoType::MULTILINESTRINGZ) : static_cast(ObGeoType::MULTILINESTRING); + uint64_t reserve_len = WKB_GEO_ELEMENT_NUM_SIZE + WKB_COMMON_WKB_HEADER_LEN; + uint32_t num_linestring = geo->get_elem_info().size() / 3; + + if (num_linestring < 1) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("invalid input arguments", K(ret), K(num_linestring)); + } else if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (OB_FAIL(append_num_with_endian(geo->get_srid(), WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append srid to buffer_", K(ret), K(geo->get_srid())); + } else if (OB_FAIL(append_num_with_endian(iorder_, WKB_GEO_BO_SIZE))) { + LOG_WARN("fail to append order to buffer_", K(ret), K(iorder_)); + } else if (OB_FAIL(append_num_with_endian(wkb_type, WKB_GEO_TYPE_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(wkb_type)); + } else if (OB_FAIL(append_num_with_endian(num_linestring, WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(num_linestring)); + } else { + // x y + is_multi_visit_ = true; + const ObArray &elem_info = geo->get_elem_info(); + for (size_t i = 0; OB_SUCC(ret) && i < elem_info.size(); i += 3) { + size_t ori_begin = elem_info[i] - 1; + size_t ori_end = + (i + 3) < elem_info.size() ? (elem_info[i + 3] - 1) : geo->get_ordinates().size(); + if (OB_FAIL(append_linestring(geo, ori_begin, ori_end))) { + LOG_WARN("fail to append linestring", K(ret), K(ori_begin), K(ori_end)); + } + } + } + + return ret; +} + +int ObSdoGeoToWkb::append_multi_polygon(ObSdoGeoObject *geo) +{ + INIT_SUCC(ret); + uint32_t wkb_type = (is_3d_geo_ && !oracle_3d_format_) ? + static_cast(ObGeoType::MULTIPOLYGONZ) : static_cast(ObGeoType::MULTIPOLYGON); + uint64_t reserve_len = WKB_GEO_ELEMENT_NUM_SIZE + WKB_COMMON_WKB_HEADER_LEN; + uint32_t num_polygon = 0; + const ObArray &elem_info = geo->get_elem_info(); + if (elem_info.size() % 3) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("invalid size of elem_info", K(ret), K(elem_info.size())); + } else { + for (size_t i = 1; i < elem_info.size(); i += 3) { + if (elem_info[i] == 1003) { + num_polygon++; // ext_ring + } + } + } + + if (OB_FAIL(ret)) { + // do nothing + } else if (num_polygon < 1) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ORDINATE_ARRAY; + LOG_WARN("invalid input arguments", K(ret), K(num_polygon)); + } else if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (OB_FAIL(append_num_with_endian(geo->get_srid(), WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append srid to buffer_", K(ret), K(geo->get_srid())); + } else if (OB_FAIL(append_num_with_endian(iorder_, WKB_GEO_BO_SIZE))) { + LOG_WARN("fail to append order to buffer_", K(ret), K(iorder_)); + } else if (OB_FAIL(append_num_with_endian(wkb_type, WKB_GEO_TYPE_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(wkb_type)); + } else if (OB_FAIL(append_num_with_endian(num_polygon, WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(num_polygon)); + } else { + // x y + is_multi_visit_ = true; + for (size_t i = 0; OB_SUCC(ret) && i < elem_info.size();) { + size_t elem_begin = i; + bool start_with_ext_ring = false; + if (elem_info[elem_begin + 1] == EXTRING_ETYPE) { + start_with_ext_ring = true; + } + for (i += 3; i < elem_info.size() && elem_info[i + 1] == INNERRING_ETYPE; i += 3) { + // to find next ext ring + } + if (start_with_ext_ring) { + if (OB_FAIL(append_polygon(geo, elem_begin, i))) { + LOG_WARN("fail to append linestring", K(ret), K(elem_begin), K(i)); + } + } else { + if (OB_FAIL(append_polygon(geo, elem_begin, i + 3))) { + LOG_WARN("fail to append linestring", K(ret), K(elem_begin), K(i)); + } + } + } + } + + return ret; +} + +int ObSdoGeoToWkb::append_collection(ObSdoGeoObject *geo) +{ + INIT_SUCC(ret); + uint32_t wkb_type = (is_3d_geo_ && !oracle_3d_format_) ? + static_cast(ObGeoType::GEOMETRYCOLLECTIONZ) : static_cast(ObGeoType::GEOMETRYCOLLECTION); + uint64_t reserve_len = WKB_GEO_ELEMENT_NUM_SIZE + WKB_COMMON_WKB_HEADER_LEN; + uint32_t num_wkb = 0; + + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to reserve memory for buffer_", K(ret), K(reserve_len)); + } else if (OB_FAIL(append_num_with_endian(geo->get_srid(), WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append srid to buffer_", K(ret), K(geo->get_srid())); + } else if (OB_FAIL(append_num_with_endian(iorder_, WKB_GEO_BO_SIZE))) { + LOG_WARN("fail to append order to buffer_", K(ret), K(iorder_)); + } else if (OB_FAIL(append_num_with_endian(wkb_type, WKB_GEO_TYPE_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(wkb_type)); + } else if (OB_FAIL(append_num_with_endian(num_wkb, WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to append buffer_", K(ret), K(num_wkb)); + } else { + is_multi_visit_ = true; + const ObArray &elem_info = geo->get_elem_info(); + for (size_t i = 0; OB_SUCC(ret) && i < elem_info.size(); i += 3) { + ++num_wkb; + size_t ori_begin = elem_info[i] - 1; + size_t ori_end = + (i + 3) < elem_info.size() ? (elem_info[i + 3] - 1) : geo->get_ordinates().size(); + ObGeoType type; + if (OB_FAIL( + ObGeoTypeUtil::geo_type_in_collection(elem_info[i + 1], elem_info[i + 2], type))) { + LOG_WARN("unsupported sdo type", K(ret), K(elem_info[i]), K(elem_info[i + 1]), K(type)); + } else if (type == ObGeoType::POINT && OB_FAIL(append_point(geo, ori_begin))) { + LOG_WARN("fail to append point", K(ret), K(ori_begin)); + } else if (type == ObGeoType::MULTIPOINT + && OB_FAIL(append_multi_point(geo, i, i + 3))) { + + LOG_WARN("fail to append multi point", K(ret), K(ori_end)); + } else if (type == ObGeoType::LINESTRING + && OB_FAIL(append_linestring(geo, ori_begin, ori_end))) { + LOG_WARN("fail to append linestring", K(ret), K(ori_end)); + } else if (type == ObGeoType::POLYGON) { + size_t elem_begin = i; + bool start_with_ext_ring = false; + if (elem_info[elem_begin + 1] == EXTRING_ETYPE) { + start_with_ext_ring = true; + } + for (i += 3; i < elem_info.size() && elem_info[i + 1] == INNERRING_ETYPE; i += 3) { + // to find next ext ring + } + if (start_with_ext_ring) { + if (OB_FAIL(append_polygon(geo, elem_begin, i))) { + LOG_WARN("fail to append linestring", K(ret), K(elem_begin), K(i)); + } else { + i -= 3; // next for i += 3 + } + } else { + if (OB_FAIL(append_polygon(geo, elem_begin, i + 3))) { + LOG_WARN("fail to append linestring", K(ret), K(elem_begin), K(i)); + } + } + } + } + } + + if (OB_SUCC(ret)) { + // change num_wkb + ObArenaAllocator tmp_allocator; + ObWkbBuffer tmp_buffer(tmp_allocator, static_cast(iorder_)); + if (OB_FAIL(tmp_buffer.reserve(WKB_GEO_ELEMENT_NUM_SIZE))) { + LOG_WARN("fail to reserve memory for tmp_buffer", K(ret)); + } else if (OB_FAIL(tmp_buffer.write(tmp_buffer.length(), num_wkb))) { + LOG_WARN("fail to write tmp_buffer", K(ret), K(num_wkb)); + } else { + MEMCPY(buffer_.ptr() + WKB_COMMON_WKB_HEADER_LEN, tmp_buffer.ptr(), WKB_GEO_ELEMENT_NUM_SIZE); + } + } + + return ret; +} + +void ObSdoGeoToWkb::reset() +{ + is_multi_visit_ = false; + buffer_.reset(); +} + +int ObSdoGeoToWkb::translate( + ObSdoGeoObject *geo, ObString &wkb, bool with_srid, ObGeoWkbByteOrder order) +{ + INIT_SUCC(ret); + iorder_ = static_cast(order); + uint64_t elem_sz = geo->get_elem_info().size(); + is_3d_geo_ = geo->is_3d_geo(); + + switch (geo->get_gtype()) { + case ObGeoType::POINT: + case ObGeoType::POINTZ: { + uint64_t ori_size = geo->get_ordinates().size(); + if (elem_sz >= 3 && ori_size > 0) { + // use elem_info and sdo_ordinate + if (geo->get_elem_info()[2] > 1 || + (geo->get_gtype() == ObGeoType::POINT && ori_size != 2) || + (geo->get_gtype() == ObGeoType::POINTZ && ori_size != 3)) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("Invalid data in the SDO_ORDINATE_ARRAY in SDO_GEOMETRY object", K(ret), K(elem_sz)); + } else { + ret = append_point(geo, geo->get_elem_info()[0] - 1); + } + } else if (geo->has_point()) { + // use sdo_point + ret = append_point(geo, -1); + } else { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("sdo_geometry has not point and elem_info", K(ret)); + } + break; + } + + case ObGeoType::LINESTRING: + case ObGeoType::LINESTRINGZ: { + if (elem_sz != 3) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("sdo_geometry has not point and elem_info", K(ret)); + } else { + ret = append_linestring(geo, geo->get_elem_info()[0] - 1, geo->get_ordinates().size()); + } + break; + } + + case ObGeoType::POLYGON: + case ObGeoType::POLYGONZ: { + ret = append_polygon(geo, 0, elem_sz); + break; + } + + case ObGeoType::GEOMETRYCOLLECTION: + case ObGeoType::GEOMETRYCOLLECTIONZ: { + ret = append_collection(geo); + break; + } + + case ObGeoType::MULTIPOINT: + case ObGeoType::MULTIPOINTZ: { + if (elem_sz < 3) { + ret = OB_ERR_INVALID_DATA_IN_SDO_ELEM_INFO_ARRAY; + LOG_WARN("sdo_geometry has not point and elem_info", K(ret)); + } else { + ret = append_multi_point(geo, 0, geo->get_elem_info().size()); + } + break; + } + + case ObGeoType::MULTILINESTRING: + case ObGeoType::MULTILINESTRINGZ: { + ret = append_multi_linestring(geo); + break; + } + + case ObGeoType::MULTIPOLYGON: + case ObGeoType::MULTIPOLYGONZ: { + ret = append_multi_polygon(geo); + break; + } + + default: { + ret = OB_ERR_INVALID_GTYPE_IN_SDO_GEROMETRY; + LOG_WARN("invalid geo type", K(ret), K(geo->get_gtype())); + break; + } + } + + if (OB_SUCC(ret)) { + if (with_srid) { + wkb.assign(buffer_.ptr(), static_cast(buffer_.length())); + } else { + wkb.assign(buffer_.ptr() + WKB_GEO_SRID_SIZE, + static_cast(buffer_.length() - WKB_GEO_SRID_SIZE)); + } + } + + return ret; +} + +} // namespace common +} // namespace oceanbase diff --git a/deps/oblib/src/lib/geo/ob_sdo_geo_func_to_wkb.h b/deps/oblib/src/lib/geo/ob_sdo_geo_func_to_wkb.h new file mode 100644 index 0000000000..9275decb8a --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_sdo_geo_func_to_wkb.h @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_SDO_GEO_FUNC_TO_WKB_ +#define OCEANBASE_LIB_GEO_OB_SDO_GEO_FUNC_TO_WKB_ + +#include + +#include "lib/allocator/ob_allocator.h" +#include "lib/geo/ob_geo_bin.h" +#include "lib/geo/ob_geo_common.h" +#include "lib/ob_define.h" +#include "lib/ob_errno.h" +#include "lib/oblog/ob_log_module.h" +#include "lib/utility/ob_print_utils.h" +#include "lib/geo/ob_sdo_geo_object.h" +#include "lib/geo/ob_geo_utils.h" + +namespace oceanbase +{ +namespace common +{ +class ObSdoGeoToWkb +{ +public: + static const uint32_t RECTANGLE_POINT_NUM = 5; + static const uint64_t INNERRING_ETYPE = 2003; + static const uint64_t EXTRING_ETYPE = 1003; + explicit ObSdoGeoToWkb(ObIAllocator *allocator, ObSrsType srs_type = ObSrsType::PROJECTED_SRS, + bool normalize = true, bool oracle_3d_format = false, bool is_deduce_dim = false) + : buffer_(allocator), is_multi_visit_(false), allocator_(allocator), + srs_type_(srs_type), need_normalize_(normalize), is_3d_geo_(false), + oracle_3d_format_(oracle_3d_format), is_deduce_dim_(is_deduce_dim) + {} + ~ObSdoGeoToWkb() + {} + int translate(ObSdoGeoObject *geo, ObString &wkb, bool with_srid = false, ObGeoWkbByteOrder order = ObGeoWkbByteOrder::BigEndian); + void reset(); + +private: + int append_point(ObSdoGeoObject *geo, int64_t idx); + int append_inner_point(double x, double y, double z = NAN, int swap_idx = 2); + int append_inner_point(const ObArray &ordinates, const uint64_t idx); + int append_inner_ring(ObSdoGeoObject *geo, size_t ori_begin, size_t ori_end); + int append_linestring(ObSdoGeoObject *geo, size_t ori_begin, size_t ori_end); + int append_polygon(ObSdoGeoObject *geo, size_t elem_begin, size_t elem_end); + int append_multi_point(ObSdoGeoObject *geo, size_t elem_begin, size_t elem_end); + int append_multi_linestring(ObSdoGeoObject *geo); + int append_multi_polygon(ObSdoGeoObject *geo); + int append_rectangle(ObSdoGeoObject *geo, size_t idx, uint64_t sdo_etype); + template + int append_num_with_endian(T data, uint64_t len); + int normalize_point(double &lon, double &lat); + int append_collection(ObSdoGeoObject *geo); + int inner_append_rectangle(double lower_left_x, double lower_left_y, double upper_right_x, + double upper_right_y, uint64_t sdo_etype, bool is_ccw, double fix_z = NAN, int swap_idx = 2); + int append_3D_rectangle(double x1, double y1, double x2, double y2, double fix_z, uint64_t sdo_etype, int fix_idx); + ObGeoStringBuffer buffer_; + uint8_t iorder_; + bool is_multi_visit_; + ObIAllocator *allocator_; + ObSrsType srs_type_; + bool need_normalize_; + bool is_3d_geo_; + bool oracle_3d_format_; + bool is_deduce_dim_; + DISALLOW_COPY_AND_ASSIGN(ObSdoGeoToWkb); +}; + +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_sdo_geo_object.cpp b/deps/oblib/src/lib/geo/ob_sdo_geo_object.cpp new file mode 100644 index 0000000000..3b65ce5c67 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_sdo_geo_object.cpp @@ -0,0 +1,193 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation support for the sdo geometry object abstraction. + */ +#define USING_LOG_PREFIX LIB +#include "ob_sdo_geo_object.h" +#include "ob_geo_utils.h" + +namespace oceanbase +{ +namespace common +{ + +bool ObSdoPoint::operator==(const ObSdoPoint &other) const +{ + bool bret = false; + if (is_null_ == other.is_null() && has_z_ == other.has_z()) { + if (fabs(x_ - other.get_x()) < OB_DOUBLE_EPSINON && + fabs(y_ - other.get_y()) < OB_DOUBLE_EPSINON && + (!has_z_ || fabs(z_ - other.get_z()) < OB_DOUBLE_EPSINON)) { + bret = true; + } + } + return bret; +} + +int ObSdoPoint::to_text(ObStringBuffer &buf) +{ + int ret = OB_SUCCESS; + int64_t len = 0; + char number_buf[128] = {0}; + ObString format_str_x = need_sci_format(x_) ? "%.4E" : "%.9g"; + ObString format_str_y = need_sci_format(y_) ? "%.4E" : "%.9g"; + ObString format_str_z = need_sci_format(z_) ? "%.4E" : "%.9g"; + if (is_null_) { + if (OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print null", K(ret)); + } + } else if (OB_FAIL(buf.append("SDO_POINT_TYPE"))) { + LOG_WARN("fail to print point type start", K(ret)); + } else if (OB_FAIL(buf.append("("))){ + LOG_WARN("fail to print (", K(ret)); + } else if ((len = snprintf(number_buf, 128, format_str_x.ptr(), x_)) < 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to val to string", K(ret), K(x_)); + } else if (OB_FAIL(buf.append(number_buf, len))) { + LOG_WARN("fail to print gtype", K(ret)); + } else if (OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } else if ((len = snprintf(number_buf, 128, format_str_y.ptr(), y_)) < 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to val to string", K(ret), K(y_)); + } else if (OB_FAIL(buf.append(number_buf, len))) { + LOG_WARN("fail to print gtype", K(ret)); + } else if (OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } else if (has_z_) { + if ((len = snprintf(number_buf, 128, format_str_z.ptr(), z_)) < 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to val to string", K(ret), K(x_)); + } else if (OB_FAIL(buf.append(number_buf, len))) { + LOG_WARN("fail to print gtype", K(ret)); + } else if (OB_FAIL(buf.append(")"))){ + LOG_WARN("fail to print (", K(ret)); + } + } else if (OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print null", K(ret)); + } else if (OB_FAIL(buf.append(")"))){ + LOG_WARN("fail to print (", K(ret)); + } + return ret; +} + +int ObSdoGeoObject::to_text(ObStringBuffer &buf) +{ + int ret = OB_SUCCESS; + uint64_t gtype_num; + int64_t len = 0; + char number_buf[128] = {0}; + if (OB_FAIL(buf.append("SDO_GEOMETRY"))) { + LOG_WARN("fail to print point type start", K(ret)); + } else if (OB_FAIL(buf.append("("))){ + LOG_WARN("fail to print (", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::get_num_by_gtype(gtype_, gtype_num))) { + LOG_WARN("fail to get_num_by_gtype", K(ret), K(gtype_), K(gtype_num)); + } else if ((len = snprintf(number_buf, 128, "%lu", gtype_num)) < 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to val to string", K(ret)); + } else if (OB_FAIL(buf.append(number_buf, len))) { + LOG_WARN("fail to print gtype", K(ret)); + } else if (OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } else if (srid_ == UINT32_MAX && OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print srid", K(ret)); + } else if (srid_ != UINT32_MAX && + ((len = snprintf(number_buf, 128, "%u", srid_)) < 0 || + OB_FAIL(buf.append(number_buf, len)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to val to string", K(ret), K(len)); + } else if (OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } else if (OB_FAIL(point_.to_text(buf))) { + LOG_WARN("fail to print point", K(ret)); + } else if (OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } else if (elem_info_.count() == 0) { + if (OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print null", K(ret)); + } + } else { + if (OB_FAIL(buf.append("SDO_ELEM_INFO_ARRAY"))) { + LOG_WARN("fail to print point type start", K(ret)); + } else if (OB_FAIL(buf.append("("))){ + LOG_WARN("fail to print (", K(ret)); + } + for (uint64_t i = 0; i < elem_info_.count() && OB_SUCC(ret); i++) { + if ((len = snprintf(number_buf, 128, "%lu", elem_info_.at(i))) < 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to val to string", K(ret)); + } else if (OB_FAIL(buf.append(number_buf, len))) { + LOG_WARN("fail to print gtype", K(ret)); + } else if (i + 1 != elem_info_.count() && OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } else if (i + 1 == elem_info_.count() && OB_FAIL(buf.append(")"))) { + LOG_WARN("fail to print )", K(ret)); + } + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } else if (ordinates_.count() == 0) { + if (OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print null", K(ret)); + } + } else { + if (OB_FAIL(buf.append("SDO_ORDINATE_ARRAY"))) { + LOG_WARN("fail to print point type start", K(ret)); + } else if (OB_FAIL(buf.append("("))){ + LOG_WARN("fail to print (", K(ret)); + } + for (uint64_t i = 0; i < ordinates_.count() && OB_SUCC(ret); i++) { + ObString format_str = need_sci_format(ordinates_.at(i)) ? "%.4E" : "%.9g"; + if ((len = snprintf(number_buf, 128, format_str.ptr(), ordinates_.at(i))) < 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to val to string", K(ret)); + } else if (OB_FAIL(buf.append(number_buf, len))) { + LOG_WARN("fail to print gtype", K(ret)); + } else if (i + 1 != ordinates_.count() && OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } else if (i + 1 == ordinates_.count() && OB_FAIL(buf.append(")"))) { + LOG_WARN("fail to print )", K(ret)); + } + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(buf.append(")"))) { + LOG_WARN("fail to print ,", K(ret)); + } + return ret; +} + +bool ObSdoGeoObject::operator==(const ObSdoGeoObject &other) const +{ + bool bret = false; + if (gtype_ == other.get_gtype() && srid_ == other.get_srid() && + point_ == other.get_point() && elem_info_.count() == other.get_elem_info().count() && + ordinates_.count() == other.get_ordinates().count()) { + bret = true; + for (int64_t i = 0; i < elem_info_.count() && bret; i++) { + if (elem_info_[i] != other.get_elem_info()[i]) { + bret = false; + } + } + for (int64_t i = 0; i < ordinates_.count() && bret; i++) { + if (fabs(ordinates_[i] - other.get_ordinates()[i]) > OB_DOUBLE_EPSINON) { + bret = false; + } + } + } + return bret; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_sdo_geo_object.h b/deps/oblib/src/lib/geo/ob_sdo_geo_object.h new file mode 100644 index 0000000000..a7e61ee011 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_sdo_geo_object.h @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_SDO_GEO_OBJECT_ +#define OCEANBASE_LIB_GEO_OB_SDO_GEO_OBJECT_ + +#include "lib/allocator/ob_allocator.h" +#include "lib/geo/ob_geo_bin.h" +#include "lib/utility/ob_print_utils.h" + + +namespace oceanbase +{ +namespace common +{ + +enum ObSdoGeoAttrIdx +{ + ObGtype = 1, + ObSrid = 2, + ObPointX = 3, + ObPointY = 4, + ObPointZ = 5, + ObElemArray = 6, + ObOrdArray = 7, +}; + +struct ObSdoPoint +{ +public: + ObSdoPoint(double x, double y) + : x_(x), y_(y), has_z_(false), is_null_(false) {} + ObSdoPoint(double x, double y, double z) + : x_(x), y_(y), has_z_(true), z_(z), is_null_(false) {} + ObSdoPoint() : has_z_(false), is_null_(true) {} + bool operator==(const ObSdoPoint &other) const; + void set_x(double x) { is_null_ = false; x_ = x; } + void set_y(double y) { is_null_ = false; y_ = y; } + void set_z(double z) { has_z_ = true; z_ = z; } + inline double get_x() const { return x_; } + inline double get_y() const { return y_; } + inline double get_z() const { return z_; } + inline bool has_z() const { return has_z_; } + inline bool is_null() const { return is_null_; } + int to_text(ObStringBuffer &buf); + TO_STRING_KV(K_(x), K_(y), K_(has_z), K_(z), K_(is_null)); + +private: + bool need_sci_format(double num) { return num <= -1e9 || num >= 1e10; } + + double x_; + double y_; + bool has_z_; + double z_; + bool is_null_; +}; + +class ObSdoGeoObject +{ +public: + ObSdoGeoObject(ObGeoType gtype, ObSdoPoint point, uint32_t srid = UINT32_MAX) + : gtype_(gtype), point_(point), srid_(srid) {} + + ObSdoGeoObject(ObGeoType gtype, ObArray elem_info, + ObArray ordinates, uint32_t srid = UINT32_MAX) + : gtype_(gtype), elem_info_(elem_info), ordinates_(ordinates), srid_(srid) + {} + ObSdoGeoObject() : gtype_(ObGeoType::GEOTYPEMAX), srid_(UINT32_MAX) {} + ~ObSdoGeoObject() + {} + bool operator==(const ObSdoGeoObject &other) const; + int to_text(ObStringBuffer &buf); + inline const ObArray &get_elem_info() const { return elem_info_; } + inline const ObArray &get_ordinates() const { return ordinates_; } + inline ObArray &get_elem_info() { return elem_info_; } + inline ObArray &get_ordinates() { return ordinates_; } + inline ObGeoType get_gtype() const { return gtype_; } + inline uint64_t get_srid() const { return srid_; } + inline const ObSdoPoint &get_point() const { return point_; } + inline ObSdoPoint &get_point() { return point_; } + inline void set_srid(uint32_t srid) { srid_ = srid; } + inline void set_gtype(ObGeoType gtype) { gtype_ = gtype; } + inline bool has_point() { return !point_.is_null(); } + inline bool is_3d_geo() { return gtype_ >= ObGeoType::POINTZ && gtype_ <= ObGeoType::GEOMETRYCOLLECTIONZ; } + int append_elem(uint64_t elem) { return elem_info_.push_back(elem); } + int append_ori(double ori) { return ordinates_.push_back(ori); } + TO_STRING_KV(K_(gtype), K_(srid), K_(point), K_(elem_info), K_(ordinates)); + +private: + bool need_sci_format(double num) { return num <= -1e9 || num >= 1e10; } + + ObGeoType gtype_; + ObSdoPoint point_; + ObArray elem_info_; + ObArray ordinates_; + uint32_t srid_; + DISALLOW_COPY_AND_ASSIGN(ObSdoGeoObject); +}; +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_vector_tile.pb-c.c b/deps/oblib/src/lib/geo/ob_vector_tile.pb-c.c new file mode 100644 index 0000000000..b65e58d8f4 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_vector_tile.pb-c.c @@ -0,0 +1,454 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: ob_vector_tile.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "ob_vector_tile.pb-c.h" +void vector_tile__tile__value__init + (VectorTile__Tile__Value *message) +{ + static const VectorTile__Tile__Value init_value = VECTOR_TILE__TILE__VALUE__INIT; + *message = init_value; +} +void vector_tile__tile__feature__init + (VectorTile__Tile__Feature *message) +{ + static const VectorTile__Tile__Feature init_value = VECTOR_TILE__TILE__FEATURE__INIT; + *message = init_value; +} +void vector_tile__tile__layer__init + (VectorTile__Tile__Layer *message) +{ + static const VectorTile__Tile__Layer init_value = VECTOR_TILE__TILE__LAYER__INIT; + *message = init_value; +} +void vector_tile__tile__init + (VectorTile__Tile *message) +{ + static const VectorTile__Tile init_value = VECTOR_TILE__TILE__INIT; + *message = init_value; +} +size_t vector_tile__tile__get_packed_size + (const VectorTile__Tile *message) +{ + assert(message->base.descriptor == &vector_tile__tile__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t vector_tile__tile__pack + (const VectorTile__Tile *message, + uint8_t *out) +{ + assert(message->base.descriptor == &vector_tile__tile__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t vector_tile__tile__pack_to_buffer + (const VectorTile__Tile *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &vector_tile__tile__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +VectorTile__Tile * + vector_tile__tile__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (VectorTile__Tile *) + protobuf_c_message_unpack (&vector_tile__tile__descriptor, + allocator, len, data); +} +void vector_tile__tile__free_unpacked + (VectorTile__Tile *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &vector_tile__tile__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +static const ProtobufCFieldDescriptor vector_tile__tile__value__field_descriptors[7] = +{ + { + "string_value", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_STRING, + offsetof(VectorTile__Tile__Value, test_oneof_case), + offsetof(VectorTile__Tile__Value, string_value), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "float_value", + 2, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_FLOAT, + offsetof(VectorTile__Tile__Value, test_oneof_case), + offsetof(VectorTile__Tile__Value, float_value), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "double_value", + 3, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_DOUBLE, + offsetof(VectorTile__Tile__Value, test_oneof_case), + offsetof(VectorTile__Tile__Value, double_value), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "int_value", + 4, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_INT64, + offsetof(VectorTile__Tile__Value, test_oneof_case), + offsetof(VectorTile__Tile__Value, int_value), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "uint_value", + 5, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(VectorTile__Tile__Value, test_oneof_case), + offsetof(VectorTile__Tile__Value, uint_value), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sint_value", + 6, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_SINT64, + offsetof(VectorTile__Tile__Value, test_oneof_case), + offsetof(VectorTile__Tile__Value, sint_value), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "bool_value", + 7, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_BOOL, + offsetof(VectorTile__Tile__Value, test_oneof_case), + offsetof(VectorTile__Tile__Value, bool_value), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned vector_tile__tile__value__field_indices_by_name[] = { + 6, /* field[6] = bool_value */ + 2, /* field[2] = double_value */ + 1, /* field[1] = float_value */ + 3, /* field[3] = int_value */ + 5, /* field[5] = sint_value */ + 0, /* field[0] = string_value */ + 4, /* field[4] = uint_value */ +}; +static const ProtobufCIntRange vector_tile__tile__value__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 7 } +}; +const ProtobufCMessageDescriptor vector_tile__tile__value__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "vector_tile.Tile.Value", + "Value", + "VectorTile__Tile__Value", + "vector_tile", + sizeof(VectorTile__Tile__Value), + 7, + vector_tile__tile__value__field_descriptors, + vector_tile__tile__value__field_indices_by_name, + 1, vector_tile__tile__value__number_ranges, + (ProtobufCMessageInit) vector_tile__tile__value__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const uint64_t vector_tile__tile__feature__id__default_value = 0ull; +static const VectorTile__Tile__GeomType vector_tile__tile__feature__type__default_value = VECTOR_TILE__TILE__GEOM_TYPE__UNKNOWN; +static const ProtobufCFieldDescriptor vector_tile__tile__feature__field_descriptors[4] = +{ + { + "id", + 1, + PROTOBUF_C_LABEL_OPTIONAL, + PROTOBUF_C_TYPE_UINT64, + offsetof(VectorTile__Tile__Feature, has_id), + offsetof(VectorTile__Tile__Feature, id), + NULL, + &vector_tile__tile__feature__id__default_value, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "tags", + 2, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_UINT32, + offsetof(VectorTile__Tile__Feature, n_tags), + offsetof(VectorTile__Tile__Feature, tags), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "type", + 3, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(VectorTile__Tile__Feature, type), + &vector_tile__tile__geom_type__descriptor, + &vector_tile__tile__feature__type__default_value, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "geometry", + 4, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_UINT32, + offsetof(VectorTile__Tile__Feature, n_geometry), + offsetof(VectorTile__Tile__Feature, geometry), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned vector_tile__tile__feature__field_indices_by_name[] = { + 3, /* field[3] = geometry */ + 0, /* field[0] = id */ + 1, /* field[1] = tags */ + 2, /* field[2] = type */ +}; +static const ProtobufCIntRange vector_tile__tile__feature__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 4 } +}; +const ProtobufCMessageDescriptor vector_tile__tile__feature__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "vector_tile.Tile.Feature", + "Feature", + "VectorTile__Tile__Feature", + "vector_tile", + sizeof(VectorTile__Tile__Feature), + 4, + vector_tile__tile__feature__field_descriptors, + vector_tile__tile__feature__field_indices_by_name, + 1, vector_tile__tile__feature__number_ranges, + (ProtobufCMessageInit) vector_tile__tile__feature__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const uint32_t vector_tile__tile__layer__version__default_value = 1u; +static const uint32_t vector_tile__tile__layer__extent__default_value = 4096u; +static const ProtobufCFieldDescriptor vector_tile__tile__layer__field_descriptors[6] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(VectorTile__Tile__Layer, name), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "features", + 2, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(VectorTile__Tile__Layer, n_features), + offsetof(VectorTile__Tile__Layer, features), + &vector_tile__tile__feature__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "keys", + 3, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_STRING, + offsetof(VectorTile__Tile__Layer, n_keys), + offsetof(VectorTile__Tile__Layer, keys), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "values", + 4, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(VectorTile__Tile__Layer, n_values), + offsetof(VectorTile__Tile__Layer, values), + &vector_tile__tile__value__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "extent", + 5, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(VectorTile__Tile__Layer, extent), + NULL, + &vector_tile__tile__layer__extent__default_value, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "version", + 15, + PROTOBUF_C_LABEL_REQUIRED, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(VectorTile__Tile__Layer, version), + NULL, + &vector_tile__tile__layer__version__default_value, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned vector_tile__tile__layer__field_indices_by_name[] = { + 4, /* field[4] = extent */ + 1, /* field[1] = features */ + 2, /* field[2] = keys */ + 0, /* field[0] = name */ + 3, /* field[3] = values */ + 5, /* field[5] = version */ +}; +static const ProtobufCIntRange vector_tile__tile__layer__number_ranges[2 + 1] = +{ + { 1, 0 }, + { 15, 5 }, + { 0, 6 } +}; +const ProtobufCMessageDescriptor vector_tile__tile__layer__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "vector_tile.Tile.Layer", + "Layer", + "VectorTile__Tile__Layer", + "vector_tile", + sizeof(VectorTile__Tile__Layer), + 6, + vector_tile__tile__layer__field_descriptors, + vector_tile__tile__layer__field_indices_by_name, + 2, vector_tile__tile__layer__number_ranges, + (ProtobufCMessageInit) vector_tile__tile__layer__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCEnumValue vector_tile__tile__geom_type__enum_values_by_number[4] = +{ + { "UNKNOWN", "VECTOR_TILE__TILE__GEOM_TYPE__UNKNOWN", 0 }, + { "POINT", "VECTOR_TILE__TILE__GEOM_TYPE__POINT", 1 }, + { "LINESTRING", "VECTOR_TILE__TILE__GEOM_TYPE__LINESTRING", 2 }, + { "POLYGON", "VECTOR_TILE__TILE__GEOM_TYPE__POLYGON", 3 }, +}; +static const ProtobufCIntRange vector_tile__tile__geom_type__value_ranges[] = { +{0, 0},{0, 4} +}; +static const ProtobufCEnumValueIndex vector_tile__tile__geom_type__enum_values_by_name[4] = +{ + { "LINESTRING", 2 }, + { "POINT", 1 }, + { "POLYGON", 3 }, + { "UNKNOWN", 0 }, +}; +const ProtobufCEnumDescriptor vector_tile__tile__geom_type__descriptor = +{ + PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, + "vector_tile.Tile.GeomType", + "GeomType", + "VectorTile__Tile__GeomType", + "vector_tile", + 4, + vector_tile__tile__geom_type__enum_values_by_number, + 4, + vector_tile__tile__geom_type__enum_values_by_name, + 1, + vector_tile__tile__geom_type__value_ranges, + NULL,NULL,NULL,NULL /* reserved[1234] */ +}; +static const ProtobufCFieldDescriptor vector_tile__tile__field_descriptors[1] = +{ + { + "layers", + 3, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(VectorTile__Tile, n_layers), + offsetof(VectorTile__Tile, layers), + &vector_tile__tile__layer__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned vector_tile__tile__field_indices_by_name[] = { + 0, /* field[0] = layers */ +}; +static const ProtobufCIntRange vector_tile__tile__number_ranges[1 + 1] = +{ + { 3, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor vector_tile__tile__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "vector_tile.Tile", + "Tile", + "VectorTile__Tile", + "vector_tile", + sizeof(VectorTile__Tile), + 1, + vector_tile__tile__field_descriptors, + vector_tile__tile__field_indices_by_name, + 1, vector_tile__tile__number_ranges, + (ProtobufCMessageInit) vector_tile__tile__init, + NULL,NULL,NULL /* reserved[123] */ +}; diff --git a/deps/oblib/src/lib/geo/ob_vector_tile.pb-c.h b/deps/oblib/src/lib/geo/ob_vector_tile.pb-c.h new file mode 100644 index 0000000000..e542a72997 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_vector_tile.pb-c.h @@ -0,0 +1,226 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ +/* Generated from: ob_vector_tile.proto */ + +#ifndef PROTOBUF_C_ob_5fvector_5ftile_2eproto__INCLUDED +#define PROTOBUF_C_ob_5fvector_5ftile_2eproto__INCLUDED + +#include + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1000000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1004001 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + + +typedef struct VectorTile__Tile VectorTile__Tile; +typedef struct VectorTile__Tile__Value VectorTile__Tile__Value; +typedef struct VectorTile__Tile__Feature VectorTile__Tile__Feature; +typedef struct VectorTile__Tile__Layer VectorTile__Tile__Layer; + + +/* --- enums --- */ + +/* + * GeomType is described in section 4.3.4 of the specification + */ +typedef enum _VectorTile__Tile__GeomType { + VECTOR_TILE__TILE__GEOM_TYPE__UNKNOWN = 0, + VECTOR_TILE__TILE__GEOM_TYPE__POINT = 1, + VECTOR_TILE__TILE__GEOM_TYPE__LINESTRING = 2, + VECTOR_TILE__TILE__GEOM_TYPE__POLYGON = 3 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(VECTOR_TILE__TILE__GEOM_TYPE) +} VectorTile__Tile__GeomType; + +/* --- messages --- */ + +typedef enum { + VECTOR_TILE__TILE__VALUE__TEST_ONEOF__NOT_SET = 0, + VECTOR_TILE__TILE__VALUE__TEST_ONEOF_STRING_VALUE = 1, + VECTOR_TILE__TILE__VALUE__TEST_ONEOF_FLOAT_VALUE = 2, + VECTOR_TILE__TILE__VALUE__TEST_ONEOF_DOUBLE_VALUE = 3, + VECTOR_TILE__TILE__VALUE__TEST_ONEOF_INT_VALUE = 4, + VECTOR_TILE__TILE__VALUE__TEST_ONEOF_UINT_VALUE = 5, + VECTOR_TILE__TILE__VALUE__TEST_ONEOF_SINT_VALUE = 6, + VECTOR_TILE__TILE__VALUE__TEST_ONEOF_BOOL_VALUE = 7 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(VECTOR_TILE__TILE__VALUE__TEST_ONEOF__CASE) +} VectorTile__Tile__Value__TestOneofCase; + +/* + * Variant type encoding + * The use of values is described in section 4.1 of the specification + * Made oneof (protobuf-c 1.1+ required) to reduce memory usage + */ +struct VectorTile__Tile__Value +{ + ProtobufCMessage base; + VectorTile__Tile__Value__TestOneofCase test_oneof_case; + union { + char *string_value; + float float_value; + double double_value; + int64_t int_value; + uint64_t uint_value; + int64_t sint_value; + protobuf_c_boolean bool_value; + }; +}; +#define VECTOR_TILE__TILE__VALUE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&vector_tile__tile__value__descriptor) \ + , VECTOR_TILE__TILE__VALUE__TEST_ONEOF__NOT_SET, {0} } + + +/* + * Features are described in section 4.2 of the specification + */ +struct VectorTile__Tile__Feature +{ + ProtobufCMessage base; + protobuf_c_boolean has_id; + uint64_t id; + /* + * Tags of this feature are encoded as repeated pairs of + * integers. + * A detailed description of tags is located in sections + * 4.2 and 4.4 of the specification + */ + size_t n_tags; + uint32_t *tags; + /* + * The type of geometry stored in this feature. + */ + VectorTile__Tile__GeomType type; + /* + * Contains a stream of commands and parameters (vertices). + * A detailed description on geometry encoding is located in + * section 4.3 of the specification. + */ + size_t n_geometry; + uint32_t *geometry; +}; +#define VECTOR_TILE__TILE__FEATURE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&vector_tile__tile__feature__descriptor) \ + , 0, 0ull, 0,NULL, VECTOR_TILE__TILE__GEOM_TYPE__UNKNOWN, 0,NULL } + + +/* + * Layers are described in section 4.1 of the specification + */ +struct VectorTile__Tile__Layer +{ + ProtobufCMessage base; + /* + * Any compliant implementation must first read the version + * number encoded in this message and choose the correct + * implementation for this version number before proceeding to + * decode other parts of this message. + */ + uint32_t version; + char *name; + /* + * The actual features in this tile. + */ + size_t n_features; + VectorTile__Tile__Feature **features; + /* + * Dictionary encoding for keys + */ + size_t n_keys; + char **keys; + /* + * Dictionary encoding for values + */ + size_t n_values; + VectorTile__Tile__Value **values; + /* + * it is required by the specification. + */ + uint32_t extent; +}; +#define VECTOR_TILE__TILE__LAYER__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&vector_tile__tile__layer__descriptor) \ + , 1u, NULL, 0,NULL, 0,NULL, 0,NULL, 4096u } + + +struct VectorTile__Tile +{ + ProtobufCMessage base; + size_t n_layers; + VectorTile__Tile__Layer **layers; +}; +#define VECTOR_TILE__TILE__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&vector_tile__tile__descriptor) \ + , 0,NULL } + + +/* VectorTile__Tile__Value methods */ +void vector_tile__tile__value__init + (VectorTile__Tile__Value *message); +/* VectorTile__Tile__Feature methods */ +void vector_tile__tile__feature__init + (VectorTile__Tile__Feature *message); +/* VectorTile__Tile__Layer methods */ +void vector_tile__tile__layer__init + (VectorTile__Tile__Layer *message); +/* VectorTile__Tile methods */ +void vector_tile__tile__init + (VectorTile__Tile *message); +size_t vector_tile__tile__get_packed_size + (const VectorTile__Tile *message); +size_t vector_tile__tile__pack + (const VectorTile__Tile *message, + uint8_t *out); +size_t vector_tile__tile__pack_to_buffer + (const VectorTile__Tile *message, + ProtobufCBuffer *buffer); +VectorTile__Tile * + vector_tile__tile__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void vector_tile__tile__free_unpacked + (VectorTile__Tile *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*VectorTile__Tile__Value_Closure) + (const VectorTile__Tile__Value *message, + void *closure_data); +typedef void (*VectorTile__Tile__Feature_Closure) + (const VectorTile__Tile__Feature *message, + void *closure_data); +typedef void (*VectorTile__Tile__Layer_Closure) + (const VectorTile__Tile__Layer *message, + void *closure_data); +typedef void (*VectorTile__Tile_Closure) + (const VectorTile__Tile *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCMessageDescriptor vector_tile__tile__descriptor; +extern const ProtobufCMessageDescriptor vector_tile__tile__value__descriptor; +extern const ProtobufCMessageDescriptor vector_tile__tile__feature__descriptor; +extern const ProtobufCMessageDescriptor vector_tile__tile__layer__descriptor; +extern const ProtobufCEnumDescriptor vector_tile__tile__geom_type__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_ob_5fvector_5ftile_2eproto__INCLUDED */ diff --git a/deps/oblib/src/lib/geo/ob_vector_tile.proto b/deps/oblib/src/lib/geo/ob_vector_tile.proto new file mode 100644 index 0000000000..a7121a9148 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_vector_tile.proto @@ -0,0 +1,79 @@ +syntax = "proto2"; + +package vector_tile; + +option optimize_for = LITE_RUNTIME; + +message Tile { + + // GeomType is described in section 4.3.4 of the specification + enum GeomType { + UNKNOWN = 0; + POINT = 1; + LINESTRING = 2; + POLYGON = 3; + } + + // Variant type encoding + // The use of values is described in section 4.1 of the specification + // Made oneof (protobuf-c 1.1+ required) to reduce memory usage + message Value { + oneof test_oneof { + string string_value = 1; + float float_value = 2; + double double_value = 3; + int64 int_value = 4; + uint64 uint_value = 5; + sint64 sint_value = 6; + bool bool_value = 7; + } + } + + // Features are described in section 4.2 of the specification + message Feature { + optional uint64 id = 1 [ default = 0 ]; + + // Tags of this feature are encoded as repeated pairs of + // integers. + // A detailed description of tags is located in sections + // 4.2 and 4.4 of the specification + repeated uint32 tags = 2 [ packed = true ]; + + // The type of geometry stored in this feature. + required GeomType type = 3 [ default = UNKNOWN ]; + + // Contains a stream of commands and parameters (vertices). + // A detailed description on geometry encoding is located in + // section 4.3 of the specification. + repeated uint32 geometry = 4 [ packed = true ]; + } + + // Layers are described in section 4.1 of the specification + message Layer { + // Any compliant implementation must first read the version + // number encoded in this message and choose the correct + // implementation for this version number before proceeding to + // decode other parts of this message. + required uint32 version = 15 [ default = 1 ]; + + required string name = 1; + + // The actual features in this tile. + repeated Feature features = 2; + + // Dictionary encoding for keys + repeated string keys = 3; + + // Dictionary encoding for values + repeated Value values = 4; + + // it is required by the specification. + required uint32 extent = 5 [ default = 4096 ]; + + extensions 16 to max; + } + + repeated Layer layers = 3; + + extensions 16 to 8191; +} diff --git a/deps/oblib/src/lib/geo/ob_wkb_byte_order_visitor.cpp b/deps/oblib/src/lib/geo/ob_wkb_byte_order_visitor.cpp new file mode 100644 index 0000000000..66c6190e6d --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_wkb_byte_order_visitor.cpp @@ -0,0 +1,326 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX LIB +#include "ob_wkb_byte_order_visitor.h" +#include "lib/ob_errno.h" + +namespace oceanbase +{ +namespace common +{ +int ObWkbByteOrderVisitor::init(ObGeometry *geo) +{ + int ret = OB_SUCCESS; + + if (OB_ISNULL(geo) || geo->length() < WKB_COMMON_WKB_HEADER_LEN) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("input geometry is invalid", K(ret), K(geo)); + } else { + from_bo_ = static_cast(*(geo->val())); + if (from_bo_ == ObGeoWkbByteOrder::INVALID) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("input geometry's byte order is invalid", K(ret), K(from_bo_), K(to_bo_)); + } + } + return ret; +} + +int ObWkbByteOrderVisitor::append_point(double x, double y) +{ + int ret = OB_SUCCESS; + + if (OB_FAIL(buffer_.append(x))) { + LOG_WARN("failed to append point value x", K(ret), K(x)); + } else if (OB_FAIL(buffer_.append(y))) { + LOG_WARN("failed to append point value y", K(ret), K(y)); + } + return ret; +} + +template +int ObWkbByteOrderVisitor::append_head_info(T *geo, int reserve_len) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(static_cast(to_bo_)))) { + LOG_WARN("failed to append little endian", K(ret)); + } else if (OB_FAIL(buffer_.append(static_cast(geo->type())))) { + LOG_WARN("failed to append type", K(ret), K(geo->type())); + } else if (OB_FAIL(buffer_.append(static_cast(geo->size())))) { + LOG_WARN("failed to append num value", K(ret), K(geo->size())); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbPoint *geo) +{ + int ret = OB_SUCCESS; + uint32_t reserve_len = EWKB_COMMON_WKB_HEADER_LEN + WKB_GEO_DOUBLE_STORED_SIZE * 2; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(static_cast(to_bo_)))) { + LOG_WARN("failed to append point little endian", K(ret)); + } else if (OB_FAIL(buffer_.append(static_cast(geo->type())))) { + LOG_WARN("failed to append point type", K(ret)); + } else if (OB_FAIL(append_point(geo->x(), geo->y()))) { + LOG_WARN("failed to point value", K(ret), K(geo->x()), K(geo->y())); + } + return ret; +} + +template +int ObWkbByteOrderVisitor::append_line(T_IBIN *geo) +{ + int ret = OB_SUCCESS; + uint32_t reserve_len = WKB_COMMON_WKB_HEADER_LEN + geo->size() * 2 * WKB_GEO_DOUBLE_STORED_SIZE; + if (OB_FAIL(append_head_info(geo, reserve_len))) { + LOG_WARN("failed to append line string head info", K(ret)); + } else { + const T_BIN *line = reinterpret_cast(geo->val()); + typename T_BIN::iterator iter = line->begin(); + for (; OB_SUCC(ret) && iter != line->end(); iter++) { + if (OB_FAIL(append_point(iter->template get<0>(from_bo_), + iter->template get<1>(from_bo_)))) { + LOG_WARN("failed to point value", K(ret)); + } + } + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeomLineString *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL((append_line(geo)))) { + LOG_WARN("fail to append line", K(ret)); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeogLineString *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL((append_line(geo)))) { + LOG_WARN("fail to append line", K(ret)); + } + return ret; +} + +template +int ObWkbByteOrderVisitor::append_polygon(T_IBIN *geo) +{ + int ret = OB_SUCCESS; + uint32_t reserve_len = 0; + if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } else { + T_BIN &poly = *(T_BIN *)(geo->val()); + T_BIN_RING &exterior = poly.exterior_ring(); + if (poly.size() != 0) { + uint32_t ext_num = exterior.size(from_bo_); + reserve_len = WKB_GEO_ELEMENT_NUM_SIZE + ext_num * 2 * WKB_GEO_DOUBLE_STORED_SIZE; + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(ext_num))) { + LOG_WARN("fail to append ring size", K(ret)); + } + typename T_BIN_RING::iterator iter = exterior.begin(); + for (; OB_SUCC(ret) && iter != exterior.end(from_bo_); ++iter) { + if (OB_FAIL(append_point(iter->template get<0>(from_bo_), + iter->template get<1>(from_bo_)))) { + LOG_WARN("fail to appendInnerPoint", K(ret)); + } + } + } + + T_BIN_INNER_RING &inner_rings = poly.inner_rings(); + typename T_BIN_INNER_RING::iterator iterInnerRing = inner_rings.begin(); + for (; OB_SUCC(ret) && iterInnerRing != inner_rings.end(); ++iterInnerRing) { + uint32_t inner_num = iterInnerRing->size(from_bo_); + reserve_len = WKB_GEO_ELEMENT_NUM_SIZE + inner_num * 2 * WKB_GEO_DOUBLE_STORED_SIZE; + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else if (OB_FAIL(buffer_.append(inner_num))) { + LOG_WARN("fail to append ring size", K(ret)); + } + typename T_BIN_RING::iterator iter = (*iterInnerRing).begin(); + for (; OB_SUCC(ret) && iter != (*iterInnerRing).end(from_bo_); ++iter) { + if (OB_FAIL(append_point(iter->template get<0>(from_bo_), + iter->template get<1>(from_bo_)))) { + LOG_WARN("fail to appendInnerPoint", K(ret)); + } + } + } + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeogPolygon *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL( + (append_polygon( + geo)))) { + LOG_WARN("fail to append polygon", K(ret)); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeomPolygon *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL( + (append_polygon( + geo)))) { + LOG_WARN("fail to append polygon", K(ret)); + } + return ret; +} + +template +int ObWkbByteOrderVisitor::append_multipoint(T_IBIN *geo) +{ + int ret = OB_SUCCESS; + uint32_t size = geo->size(); + uint32_t reserve_len = size * (EWKB_COMMON_WKB_HEADER_LEN + WKB_GEO_DOUBLE_STORED_SIZE * 2); + if (OB_FAIL(buffer_.reserve(reserve_len))) { + LOG_WARN("fail to alloc memory", K(ret), K(reserve_len)); + } else { + char *ptr = reinterpret_cast(geo->val()); + uint32_t sz = geo->size(); + for (uint32_t i = 0; i < sz; ++i) { + uint64_t offset = WKB_COMMON_WKB_HEADER_LEN; + T_POINT p; + offset += i * p.length(); + ObString data(sizeof(T_POINT), (ptr + offset)); + T_IPOINT point; + point.set_data(data); + if (OB_FAIL(visit(&point))) { + LOG_WARN("fail to do point visit", K(ret)); + } + } + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeogMultiPoint *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } else if (OB_FAIL((append_multipoint(geo)))) { + LOG_WARN("fail to append multipoint", K(ret)); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeomMultiPoint *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } else if (OB_FAIL((append_multipoint(geo)))) { + LOG_WARN("fail to append multipoint", K(ret)); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeogMultiLineString *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeomMultiLineString *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeogMultiPolygon *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeomMultiPolygon *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeogCollection *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +int ObWkbByteOrderVisitor::visit(ObIWkbGeomCollection *geo) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(init(geo))) { + LOG_WARN("fail to init geometry", K(ret)); + } else if (OB_FAIL(append_head_info(geo, WKB_COMMON_WKB_HEADER_LEN))) { + LOG_WARN("failed to append head info", K(ret)); + } + return ret; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_wkb_byte_order_visitor.h b/deps/oblib/src/lib/geo/ob_wkb_byte_order_visitor.h new file mode 100644 index 0000000000..29a8d68781 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_wkb_byte_order_visitor.h @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_WKB_BYTE_ORDER_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_WKB_BYTE_ORDER_VISITOR_ +#include "lib/geo/ob_geo_visitor.h" +#include "lib/geo/ob_geo_common.h" + +namespace oceanbase +{ +namespace common +{ +// All BIG ENDIAN wkb needs to go through this visitor transformation before being used +class ObWkbByteOrderVisitor : public ObEmptyGeoVisitor +{ +public: + ObWkbByteOrderVisitor(ObIAllocator *allocator, ObGeoWkbByteOrder to_bo) + : buffer_(*allocator, to_bo), to_bo_(to_bo), from_bo_(ObGeoWkbByteOrder::INVALID) + {} + + virtual ~ObWkbByteOrderVisitor() + {} + + bool prepare(ObGeometry *geo) + { + UNUSED(geo); + return true; + } + + // wkb + int visit(ObIWkbPoint *geo); + + int visit(ObIWkbGeogLineString *geo); + int visit(ObIWkbGeomLineString *geo); + + int visit(ObIWkbGeogMultiPoint *geo); + int visit(ObIWkbGeomMultiPoint *geo); + + int visit(ObIWkbGeogPolygon *geo); + int visit(ObIWkbGeomPolygon *geo); + + int visit(ObIWkbGeogMultiLineString *geo); + int visit(ObIWkbGeomMultiLineString *geo); + + int visit(ObIWkbGeogMultiPolygon *geo); + int visit(ObIWkbGeomMultiPolygon *geo); + + int visit(ObIWkbGeogCollection *geo); + int visit(ObIWkbGeomCollection *geo); + + // is_end default false + bool is_end(ObIWkbGeogLineString *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeomLineString *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeogPolygon *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeomPolygon *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeogMultiPoint *geo) + { + UNUSED(geo); + return true; + } + + bool is_end(ObIWkbGeomMultiPoint *geo) + { + UNUSED(geo); + return true; + } + + const ObString get_wkb() + { + return buffer_.string(); + } + +private: + int init(ObGeometry *geo); + int append_point(double x, double y); + template + int append_head_info(T *geo, int reserve_len); + template + int append_line(T_IBIN *geo); + template + int append_polygon(T_IBIN *geo); + template + int append_multipoint(T_IBIN *geo); + + ObWkbBuffer buffer_; + ObGeoWkbByteOrder to_bo_; + ObGeoWkbByteOrder from_bo_; + DISALLOW_COPY_AND_ASSIGN(ObWkbByteOrderVisitor); +}; +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_wkb_to_json_visitor.cpp b/deps/oblib/src/lib/geo/ob_wkb_to_json_visitor.cpp new file mode 100644 index 0000000000..559bb4a36d --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_wkb_to_json_visitor.cpp @@ -0,0 +1,716 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#include "lib/ob_errno.h" +#include +#define USING_LOG_PREFIX LIB +#include "ob_wkb_to_json_visitor.h" +#include "ob_srs_info.h" +#include "lib/number/ob_number_v2.h" +#include "lib/charset/ob_dtoa.h" +#include "lib/utility/ob_fast_convert.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_to_wkt_visitor.h" +#include "lib/geo/ob_geo_func_register.h" +#include "lib/utility/ob_fast_convert.h" +#include "rpc/obmysql/ob_mysql_global.h" + +namespace oceanbase { +namespace common { + +ObWkbToJsonVisitor::ObWkbToJsonVisitor(ObIAllocator *allocator, uint32_t max_dec_digits/* = UINT_MAX32*/, uint8_t flag/* = 0*/, const ObGeoSrid srid/* = 0*/) + : buffer_(allocator), + in_multi_visit_(false), + colloction_level_(0), + is_mysql_mode_(lib::is_mysql_mode()), + flag_(flag), + max_dec_digits_(max_dec_digits), + srid_(srid), + allocator_(allocator), + append_crs_(false) +{ + left_curly_bracket_ = lib::is_mysql_mode() ? "{" : "{ "; + right_curly_bracket_ = lib::is_mysql_mode() ? "}" : " }"; + left_sq_bracket_ = lib::is_mysql_mode() ? "[" : "[ "; + right_sq_bracket_ = lib::is_mysql_mode() ? "]" : " ]"; +} + +bool ObWkbToJsonVisitor::prepare(ObIWkbGeogMultiPoint *geo) +{ + UNUSED(geo); + in_multi_visit_ = true; + return true; +} + +bool ObWkbToJsonVisitor::prepare(ObIWkbGeomMultiPoint *geo) +{ + UNUSED(geo); + in_multi_visit_ = true; + return true; +} + +bool ObWkbToJsonVisitor::prepare(ObIWkbGeogMultiLineString *geo) +{ + UNUSED(geo); + in_multi_visit_ = true; + return true; +} + +bool ObWkbToJsonVisitor::prepare(ObIWkbGeomMultiLineString *geo) +{ + UNUSED(geo); + in_multi_visit_ = true; + return true; +} + +bool ObWkbToJsonVisitor::prepare(ObIWkbGeogMultiPolygon *geo) +{ + UNUSED(geo); + in_multi_visit_ = true; + return true; +} + +bool ObWkbToJsonVisitor::prepare(ObIWkbGeomMultiPolygon *geo) +{ + UNUSED(geo); + in_multi_visit_ = true; + return true; +} + +bool ObWkbToJsonVisitor::prepare(ObIWkbGeogCollection *geo) +{ + UNUSED(geo); + colloction_level_++; + return true; +} + +bool ObWkbToJsonVisitor::prepare(ObIWkbGeomCollection *geo) +{ + UNUSED(geo); + colloction_level_++; + return true; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeogPoint *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL(appendPoint(geo))) { + LOG_WARN("fail to append point", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeomPoint *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL(appendPoint(geo))) { + LOG_WARN("fail to append point", K(ret)); + } + return ret; +} + +template +int ObWkbToJsonVisitor::appendPoint(T_IBIN *geo) +{ + INIT_SUCC(ret); + const char *type_name = "Point"; + // { "type": "Point", "coordinates": [x, y] } + if (!in_multi_visit_ && OB_FAIL(appendJsonFields(geo->type(), type_name, geo))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(appendInnerPoint(geo->x(), geo->y()))) { + LOG_WARN("fail to appendInnerPoint", K(ret), K(geo->x()), K(geo->y())); + } else if (!in_multi_visit_ && OB_FAIL(buffer_.append(right_curly_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_)); + } else if ((in_multi_visit_ || in_colloction_visit()) && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::appendInnerPoint(double x, double y) +{ + // [x, y] + INIT_SUCC(ret); + if (OB_FAIL(buffer_.append("["))) { + LOG_WARN("fail to append to buffer_", K(ret)); + } else if (OB_FAIL(appendDouble(x))) { + LOG_WARN("fail to append x", K(ret), K(x)); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append to buffer_", K(ret)); + } else if (OB_FAIL(appendDouble(y))) { + LOG_WARN("fail to append y", K(ret), K(y)); + } else if (OB_FAIL(buffer_.append("]"))) { + LOG_WARN("fail to append to buffer_", K(ret)); + } + + return ret; +} + +int ObWkbToJsonVisitor::appendDouble(double x) +{ + INIT_SUCC(ret); + uint64_t double_buff_size = is_mysql_mode_ ? DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE : MAX_DIGITS_IN_DOUBLE; + uint64_t len_x = 0; + char *buff_ptr = NULL; + if (OB_FAIL(buffer_.reserve(double_buff_size))) { + LOG_WARN("fail to reserve buffer", K(ret)); + } else if (FALSE_IT(buff_ptr = buffer_.ptr() + buffer_.length())) { + } else if (is_mysql_mode_) { + x = ObGeoTypeUtil::round_double(x, max_dec_digits_, false); + len_x = ob_gcvt(x, ob_gcvt_arg_type::OB_GCVT_ARG_DOUBLE, + DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE, buff_ptr, NULL); + } else if (OB_FAIL(ObGeoToWktVisitor::convert_double_to_str(buff_ptr, double_buff_size, x, true, + MAX_DIGITS_IN_DOUBLE, !is_mysql_mode_, len_x))) { + LOG_WARN("fail to append x val to buffer", K(ret)); + } + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(buffer_.set_length(buffer_.length() + len_x))) { + LOG_WARN("fail to set buffer x len", K(ret), K(len_x)); + } else if (is_mysql_mode_) { + // add '.0' to interger + bool has_sci_or_dot = false; + for (int i = 0; i < len_x && !has_sci_or_dot; ++i) { + if (buff_ptr[i] == 'e' || buff_ptr[i] == '.') { + has_sci_or_dot = true; + } + } + if (!has_sci_or_dot) { + if (OB_FAIL(buffer_.append("."))) { + LOG_WARN("fail to append '.' to buffer", K(ret), K(len_x)); + } else if (OB_FAIL(buffer_.append("0"))) { + LOG_WARN("fail to append '0' to buffer", K(ret), K(len_x)); + } + } + } + return ret; +} + +int ObWkbToJsonVisitor::appendJsonFields(ObGeoType type, const char *type_name, ObGeometry *geo) { + int ret = OB_SUCCESS; + if (type <= ObGeoType::GEOMETRY || type >= ObGeoType::GEOTYPEMAX) { + LOG_WARN("invalid geo type", K(ret), K(type)); + } else if (OB_FAIL(buffer_.append(left_curly_bracket_))) { + LOG_WARN("fail to append left curly bracket", K(ret)); + } else if (is_mysql_mode_ && OB_FAIL(appendMySQLFlagInfo(geo))) { + LOG_WARN("fail to append mysql geojson flag info", K(ret)); + } else if (OB_FAIL(buffer_.append("\"type\": \""))) { + LOG_WARN("fail to append type field", K(ret)); + } else if (OB_FAIL(buffer_.append(type_name))) { + LOG_WARN("fail to append type value", K(ret), K(type_name)); + } else if (type != ObGeoType::GEOMETRYCOLLECTION && + OB_FAIL(buffer_.append("\", \"coordinates\": "))) { + LOG_WARN("fail to append coordinates field", K(ret)); + } else if (type == ObGeoType::GEOMETRYCOLLECTION && + OB_FAIL(buffer_.append("\", \"geometries\": "))) { + LOG_WARN("fail to append geometries field", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeogLineString *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((appendLine(geo)))) { + LOG_WARN("fail to append line", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeomLineString *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((appendLine(geo)))) { + LOG_WARN("fail to append line", K(ret)); + } + return ret; +} + +template +int ObWkbToJsonVisitor::appendLine(T_IBIN *geo) +{ + INIT_SUCC(ret); + const char *type_name = "LineString"; + if ((!in_multi_visit_ || in_oracle_colloction_visit()) && OB_FAIL(appendJsonFields(geo->type(), type_name, geo))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append(left_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else { + const T_BIN *line = reinterpret_cast(geo->val()); + typename T_BIN::iterator iter = line->begin(); + for ( ; OB_SUCC(ret) && iter != line->end(); iter++) { + if (OB_FAIL(appendInnerPoint(iter->template get<0>(), iter->template get<1>()))) { + LOG_WARN("fail to appendInnerPoint", K(ret), K(iter->template get<0>()), K(iter->template get<1>())); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if (OB_FAIL(buffer_.append(right_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if ((!in_multi_visit_ || in_oracle_colloction_visit()) && OB_FAIL(buffer_.append(right_curly_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if ((in_multi_visit_ || in_colloction_visit()) && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeogMultiPoint *geo) +{ + INIT_SUCC(ret); + const char *type_name = "MultiPoint"; + if (OB_FAIL(appendJsonFields(geo->type(), type_name, geo))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append(left_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeomMultiPoint *geo) +{ + INIT_SUCC(ret); + const char *type_name = "MultiPoint"; + if (OB_FAIL(appendJsonFields(geo->type(), type_name, geo))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append(left_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeogMultiLineString *geo) +{ + INIT_SUCC(ret); + if (!in_oracle_colloction_visit()) { + const char *type_name = "MultiLineString"; + if (OB_FAIL(appendJsonFields(geo->type(), type_name, geo))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append(left_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeomMultiLineString *geo) +{ + INIT_SUCC(ret); + if (!in_oracle_colloction_visit()) { + const char *type_name = "MultiLineString"; + if (OB_FAIL(appendJsonFields(geo->type(), type_name, geo))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append(left_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeogPolygon *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((appendPolygon(geo)))) { + LOG_WARN("fail to append polygon", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeomPolygon *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((appendPolygon(geo)))) { + LOG_WARN("fail to append polygon", K(ret)); + } + return ret; +} + +template +int ObWkbToJsonVisitor::appendPolygon(T_IBIN *geo) +{ + INIT_SUCC(ret); + const char *type_name = "Polygon"; + if (geo->length() < WKB_COMMON_WKB_HEADER_LEN) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid wkb length", K(ret), K(geo->length())); + } else if ((!in_multi_visit_ || in_oracle_colloction_visit()) && OB_FAIL(appendJsonFields(geo->type(), type_name, geo))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append(left_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else { + T_BIN& poly = *(T_BIN *)(geo->val()); + T_BIN_RING& exterior = poly.exterior_ring(); + T_BIN_INNER_RING& inner_rings = poly.inner_rings(); + if (poly.size() != 0) { + typename T_BIN_RING::iterator iter = exterior.begin(); + if (OB_FAIL(buffer_.append(left_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + for (; OB_SUCC(ret) && iter != exterior.end(); ++iter) { + if (OB_FAIL(appendInnerPoint(iter->template get<0>(), iter->template get<1>()))) { + LOG_WARN("fail to appendInnerPoint", K(ret), K(iter->template get<0>()), K(iter->template get<1>())); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if (OB_FAIL(buffer_.append(right_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + } + + typename T_BIN_INNER_RING::iterator iterInnerRing = inner_rings.begin(); + for (; OB_SUCC(ret) && iterInnerRing != inner_rings.end(); ++iterInnerRing) { + typename T_BIN_RING::iterator iter = (*iterInnerRing).begin(); + if (OB_FAIL(buffer_.append(left_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + for (; OB_SUCC(ret) && iter != (*iterInnerRing).end(); ++iter) { + if (OB_FAIL(appendInnerPoint(iter->template get<0>(), iter->template get<1>()))) { + LOG_WARN("fail to appendInnerPoint", K(ret), K(iter->template get<0>()), K(iter->template get<1>())); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if (OB_FAIL(buffer_.append(right_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if (OB_FAIL(buffer_.append(right_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if ((!in_multi_visit_ || in_oracle_colloction_visit()) && OB_FAIL(buffer_.append(right_curly_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if ((in_multi_visit_ || in_colloction_visit()) && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeogMultiPolygon *geo) +{ + INIT_SUCC(ret); + if (!in_oracle_colloction_visit()) { + const char *type_name = "MultiPolygon"; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiPrefix(geo->type(), type_name, geo))){ + LOG_WARN("fail to append multi prefix", K(ret)); + } + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeomMultiPolygon *geo) +{ + INIT_SUCC(ret); + if (!in_oracle_colloction_visit()) { + const char *type_name = "MultiPolygon"; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiPrefix(geo->type(), type_name, geo))){ + LOG_WARN("fail to append multi prefix", K(ret)); + } + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeogCollection *geo) +{ + INIT_SUCC(ret); + const char *type_name = "GeometryCollection"; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiPrefix(geo->type(), type_name, geo))){ + LOG_WARN("fail to append multi prefix", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::visit(ObIWkbGeomCollection *geo) +{ + INIT_SUCC(ret); + const char *type_name = "GeometryCollection"; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiPrefix(geo->type(), type_name, geo))){ + LOG_WARN("fail to append multi prefix", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::appendMultiPrefix(ObGeoType geo_type, const char *type_name, ObGeometry *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL(appendJsonFields(geo_type, type_name, geo))) { + LOG_WARN("fail to append buffer_", K(ret), K(in_multi_visit_), K(type_name)); + } else if (OB_FAIL(buffer_.append(left_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::appendMultiSuffix(ObGeoType geo_type) +{ + INIT_SUCC(ret); + if (OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if ((geo_type == ObGeoType::MULTIPOINT || !in_oracle_colloction_visit()) && OB_FAIL(buffer_.append(right_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if (OB_FAIL(buffer_.append(right_curly_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret), K(right_curly_bracket_)); + } else if ((in_colloction_visit()) && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::finish(ObIWkbGeogMultiPoint *geo) +{ + INIT_SUCC(ret); + in_multi_visit_ = false; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiSuffix(geo->type()))) { + LOG_WARN("fail to append multi suffix", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::finish(ObIWkbGeomMultiPoint *geo) +{ + INIT_SUCC(ret); + in_multi_visit_ = false; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiSuffix(geo->type()))) { + LOG_WARN("fail to append multi suffix", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::finish(ObIWkbGeogMultiLineString *geo) +{ + INIT_SUCC(ret); + in_multi_visit_ = false; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiSuffix(geo->type()))) { + LOG_WARN("fail to append multi suffix", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::finish(ObIWkbGeomMultiLineString *geo) +{ + INIT_SUCC(ret); + in_multi_visit_ = false; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiSuffix(geo->type()))) { + LOG_WARN("fail to append multi suffix", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::finish(ObIWkbGeogMultiPolygon *geo) +{ + INIT_SUCC(ret); + in_multi_visit_ = false; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiSuffix(geo->type()))) { + LOG_WARN("fail to append multi suffix", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::finish(ObIWkbGeomMultiPolygon *geo) +{ + INIT_SUCC(ret); + in_multi_visit_ = false; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geo is NULL", K(ret)); + } else if (OB_FAIL(appendMultiSuffix(geo->type()))) { + LOG_WARN("fail to append multi suffix", K(ret)); + } + return ret; +} + +template +int ObWkbToJsonVisitor::appendCollectionSuffix(T_IBIN *geo) +{ + INIT_SUCC(ret); + ObString comma(2, buffer_.ptr() + buffer_.length() - 2); + if ((comma.compare(", ") == 0) && OB_FAIL(buffer_.set_length(buffer_.length() - 2))) { + LOG_WARN("fail to set buffer_ len", K(ret), K(buffer_.length())); + } else if (OB_FAIL(buffer_.append(right_sq_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret)); + } else if (OB_FAIL(buffer_.append(right_curly_bracket_))) { + LOG_WARN("fail to append buffer_", K(ret), K(right_curly_bracket_)); + } + + colloction_level_--; + if (OB_FAIL(ret)) { + } else if (in_colloction_visit() && OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append buffer_", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::finish(ObIWkbGeomCollection *geo) +{ + return appendCollectionSuffix(geo); +} + +int ObWkbToJsonVisitor::finish(ObIWkbGeogCollection *geo) +{ + return appendCollectionSuffix(geo); +} + +void ObWkbToJsonVisitor::get_geojson(ObString &geojson) +{ + geojson.assign(buffer_.ptr(), static_cast(buffer_.length())); +} + +void ObWkbToJsonVisitor::reset() +{ + buffer_.reset(); + in_multi_visit_ = false; + colloction_level_ = 0; + max_dec_digits_ = UINT_MAX32; + flag_ = 0; + srid_ = 0; +} + +int ObWkbToJsonVisitor::appendBox(ObGeogBox &box) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(buffer_.append("\"bbox\": ["))) { + LOG_WARN("fail to append bbox field", K(ret)); + } else if (OB_FAIL(appendDouble(box.xmin))) { + LOG_WARN("fail to append x", K(ret), K(box.xmin)); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append comma", K(ret)); + } else if (OB_FAIL(appendDouble(box.ymin))) { + LOG_WARN("fail to append x", K(ret), K(box.ymin)); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append comma", K(ret)); + } else if (OB_FAIL(appendDouble(box.xmax))) { + LOG_WARN("fail to append x", K(ret), K(box.xmax)); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append comma", K(ret)); + } else if (OB_FAIL(appendDouble(box.ymax))) { + LOG_WARN("fail to append x", K(ret), K(box.ymax)); + } else if (OB_FAIL(buffer_.append("]"))) { + LOG_WARN("fail to append comma", K(ret)); + } + return ret; +} + +int ObWkbToJsonVisitor::appendMySQLFlagInfo(ObGeometry *geo) +{ + int ret = OB_SUCCESS; + if (!append_crs_ && srid_ != 0 + && ((flag_ & ObGeoJsonFormat::SHORT_SRID) || (flag_ & ObGeoJsonFormat::LONG_SRID))) { + // "crs": {"type": "name", "properties": {"name": "[EPSG srid]"}}, + if (OB_FAIL(buffer_.append("\"crs\": {\"type\": \"name\", \"properties\": {\"name\": \""))) { + LOG_WARN("fail to append crs field", K(ret)); + } else if (flag_ & ObGeoJsonFormat::LONG_SRID) { + // urn:ogc:def:crs:EPSG::[srid] + // long srid flag will overwrite short srid + if (OB_FAIL(buffer_.append("urn:ogc:def:crs:EPSG::"))) { + LOG_WARN("fail to append crs value", K(ret)); + } + } else { + // EPSG:[srid] + if (OB_FAIL(buffer_.append("EPSG:"))) { + LOG_WARN("fail to append crs value", K(ret)); + } + } + if (OB_FAIL(ret)) { + // do nothing + } else { + char flag_buf[ObFastFormatInt::MAX_DIGITS10_STR_SIZE] = {0}; + uint64_t len = ObFastFormatInt::format_signed(srid_, flag_buf); + if (OB_FAIL(buffer_.append(flag_buf, len))) { + LOG_WARN("fail to append srid value", K(ret), K(srid_)); + } else if (OB_FAIL(buffer_.append("\"}}, "))) { + LOG_WARN("fail to append crs ending str", K(ret)); + } else { + append_crs_ = true; + } + } + } + + if (OB_SUCC(ret) && (flag_ & ObGeoJsonFormat::BBOX) && !geo->is_empty()) { + // "bbox": [ymin, xmin, ymax, xmax], + ObGeogBox *box = nullptr; + // geographic geometry also represent it's cartesian box in mysql + ObArenaAllocator tmp_allocator; + ObGeometry *box_geo = nullptr; + if (geo->crs() == ObGeoCRS::Geographic) { + if (OB_FAIL(ObGeoTypeUtil::create_geo_by_type(tmp_allocator, geo->type(), false, true, box_geo, geo->get_srid()))) { + LOG_WARN("fail to create geo by type", K(ret), K(geo->type())); + } else { + box_geo->set_data(geo->val()); + } + } else { + box_geo = geo; + } + ObGeoEvalCtx geo_ctx(allocator_); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(geo_ctx.append_geo_arg(box_geo))) { + LOG_WARN("build gis context failed", K(ret)); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(geo_ctx, box))) { + LOG_WARN("failed to do box functor failed", K(ret)); + } else if (OB_FAIL(appendBox(*box))) { + LOG_WARN("fail to append bbox field", K(ret)); + } else if (OB_FAIL(buffer_.append(", "))) { + LOG_WARN("fail to append comma", K(ret)); + } + } + return ret; +} + +} // namespace common +} // namespace oceanbase diff --git a/deps/oblib/src/lib/geo/ob_wkb_to_json_visitor.h b/deps/oblib/src/lib/geo/ob_wkb_to_json_visitor.h new file mode 100644 index 0000000000..109d17dfd2 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_wkb_to_json_visitor.h @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_GEO_TO_JSON_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_GEO_TO_JSON_VISITOR_ +#include "lib/geo/ob_geo_visitor.h" +#include "lib/geo/ob_geo_utils.h" + + +namespace oceanbase +{ +namespace common +{ +enum ObGeoJsonFormat { + DEFAULT = 0, + BBOX = 1, + SHORT_SRID = 2, + LONG_SRID = 4 +}; + +class ObWkbToJsonVisitor : public ObEmptyGeoVisitor +{ +public: + static const int MAX_DIGITS_IN_DOUBLE = 25; + explicit ObWkbToJsonVisitor(ObIAllocator *allocator, uint32_t max_dec_digits = UINT_MAX32, uint8_t flag = 0, const ObGeoSrid srid = 0); + + ~ObWkbToJsonVisitor() {} + bool prepare(ObGeometry *geo) { UNUSED(geo); return true; } + bool prepare(ObIWkbGeogMultiPoint *geo); + bool prepare(ObIWkbGeomMultiPoint *geo); + bool prepare(ObIWkbGeogMultiLineString *geo); + bool prepare(ObIWkbGeomMultiLineString *geo); + bool prepare(ObIWkbGeogMultiPolygon *geo); + bool prepare(ObIWkbGeomMultiPolygon *geo); + bool prepare(ObIWkbGeogCollection *geo); + bool prepare(ObIWkbGeomCollection *geo); + // wkb + int visit(ObIWkbGeogPoint *geo); + int visit(ObIWkbGeomPoint *geo); + int visit(ObIWkbGeogLineString *geo); + int visit(ObIWkbGeomLineString *geo); + int visit(ObIWkbGeogMultiPoint *geo); + int visit(ObIWkbGeomMultiPoint *geo); + int visit(ObIWkbGeogMultiLineString *geo); + int visit(ObIWkbGeomMultiLineString *geo); + int visit(ObIWkbGeogPolygon *geo); + int visit(ObIWkbGeomPolygon *geo); + int visit(ObIWkbGeogMultiPolygon *geo); + int visit(ObIWkbGeomMultiPolygon *geo); + int visit(ObIWkbGeogCollection *geo); + int visit(ObIWkbGeomCollection *geo); + + bool is_end(ObIWkbGeogLineString *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeomLineString *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeogLinearRing *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeomLinearRing *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeogPolygon *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeomPolygon *geo) { UNUSED(geo); return true; } + + virtual int finish(ObIWkbGeogMultiPoint *geo) override; + virtual int finish(ObIWkbGeomMultiPoint *geo) override; + virtual int finish(ObIWkbGeogMultiLineString *geo) override; + virtual int finish(ObIWkbGeomMultiLineString *geo) override; + virtual int finish(ObIWkbGeogMultiPolygon *geo) override; + virtual int finish(ObIWkbGeomMultiPolygon *geo) override; + virtual int finish(ObIWkbGeogCollection *geo) override; + virtual int finish(ObIWkbGeomCollection *geo) override; + + void get_geojson(ObString &geojson); + void reset(); +private: + // for Point + template + int appendPoint(T_IBIN *geo); + int appendInnerPoint(double x, double y); + int appendDouble(double x); + // for LineString + template + int appendLine(T_IBIN *geo); + // for Polygon + template + int appendPolygon(T_IBIN *geo); + // for multi + int appendMultiPrefix(ObGeoType geo_type, const char *type_name, ObGeometry *geo); + int appendMultiSuffix(ObGeoType type); + template + int appendCollectionSuffix(T_IBIN *geo); + // common + int appendJsonFields(ObGeoType type, const char *type_name, ObGeometry *geo); + bool in_colloction_visit() { return colloction_level_ > 0; } + bool in_oracle_colloction_visit() { return (colloction_level_ > 0) && !is_mysql_mode_; } + int appendMySQLFlagInfo(ObGeometry *geo); + int appendBox(ObGeogBox &box); + + ObGeoStringBuffer buffer_; + bool in_multi_visit_; + int colloction_level_; + bool is_mysql_mode_; + uint8_t flag_; + uint32_t max_dec_digits_; + ObGeoSrid srid_; + ObIAllocator *allocator_; + bool append_crs_; + + ObString right_curly_bracket_; + ObString left_curly_bracket_; + ObString left_sq_bracket_; + ObString right_sq_bracket_; + DISALLOW_COPY_AND_ASSIGN(ObWkbToJsonVisitor); +}; + +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_wkb_to_sdo_geo_visitor.cpp b/deps/oblib/src/lib/geo/ob_wkb_to_sdo_geo_visitor.cpp new file mode 100644 index 0000000000..7c1454fafe --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_wkb_to_sdo_geo_visitor.cpp @@ -0,0 +1,452 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ +#define USING_LOG_PREFIX LIB +#include "ob_wkb_to_sdo_geo_visitor.h" + +namespace oceanbase +{ +namespace common +{ + +template +int ObWkbToSdoGeoVisitor::append_point(T_IBIN *geo) +{ + INIT_SUCC(ret); + // collection_visit may include both POINT(multi_visit = false) and MULTIPOINT(multi_visit = true) + if (is_multi_visit_ || is_collection_visit_) { + // elem_info = (start_idx, 1, 1) + if (!is_multi_visit_ && OB_FAIL(append_elem_info(sdo_geo_->get_ordinates().size() + 1, 1, 1))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(sdo_geo_->get_ordinates().size())); + } else if (OB_FAIL(append_inner_point(geo->x(), geo->y()))) { + LOG_WARN("fail to append inner point", K(ret), K(geo->x()), K(geo->y())); + } + } else { + // point = (x, y, null) + double x = geo->x(); + double y = geo->y(); + sdo_geo_->set_gtype(geo->type()); + if (std::isnan(x) || std::isnan(y) || std::isinf(x) || std::isinf(y)) { + ret = OB_ERR_INVALID_NULL_SDO_GEOMETRY; + LOG_WARN("x coordinate or y coordinate is NAN or INF", K(ret), K(x), K(y)); + } else if (!is_valid_to_represent(x) || !is_valid_to_represent(y)) { + ret = OB_NUMERIC_OVERFLOW; + LOG_WARN("number is out of range", K(ret), K(x), K(y)); + } else { + sdo_geo_->get_point().set_x(x); + sdo_geo_->get_point().set_y(y); + } + } + return ret; +} + +bool ObWkbToSdoGeoVisitor::is_valid_to_represent(double num) +{ + bool is_valid = false; + if (num == 0) { + is_valid = true; + } else if (num >= MIN_NUMBER_ORACLE && num < MAX_NUMBER_ORACLE) { + is_valid = true; + } else if (num <= (-MIN_NUMBER_ORACLE) && num > (-MAX_NUMBER_ORACLE)) { + is_valid = true; + } + return is_valid; +} + +int ObWkbToSdoGeoVisitor::append_inner_point(double x, double y) +{ + INIT_SUCC(ret); + if (!is_valid_to_represent(x)) { + ret = OB_NUMERIC_OVERFLOW; + LOG_WARN("number is out of range", K(ret), K(x)); + } else if (OB_FAIL(sdo_geo_->append_ori(x))) { + LOG_WARN("fail to append sdo_elem_info", K(ret)); + } else if (!is_valid_to_represent(y)) { + ret = OB_NUMERIC_OVERFLOW; + LOG_WARN("number is out of range", K(ret), K(y)); + } else if (OB_FAIL(sdo_geo_->append_ori(y))) { + LOG_WARN("fail to append sdo_elem_info", K(ret)); + } + + return ret; +} + +int ObWkbToSdoGeoVisitor::append_elem_info(uint64_t offset, uint64_t etype, uint64_t interpretation) +{ + INIT_SUCC(ret); + if (OB_FAIL(sdo_geo_->append_elem(offset))) { + LOG_WARN("fail to append offset to sdo_elem_info", K(ret), K(offset)); + } else if (OB_FAIL(sdo_geo_->append_elem(etype))) { + LOG_WARN("fail to append etype to sdo_elem_info", K(ret), K(etype)); + } else if (OB_FAIL(sdo_geo_->append_elem(interpretation))) { + LOG_WARN("fail to append interpretation to sdo_elem_info", K(ret), K(interpretation)); + } + return ret; +} + +template +int ObWkbToSdoGeoVisitor::append_linestring(T_IBIN *geo) +{ + INIT_SUCC(ret); + if (!is_multi_visit_ && !is_collection_visit_) { + sdo_geo_->set_gtype(geo->type()); + } + + // elem_info = (start_idx, 2, 1) + if (geo->length() < WKB_COMMON_WKB_HEADER_LEN) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid wkb length", K(ret), K(geo->length())); + } else if (OB_FAIL(append_elem_info(sdo_geo_->get_ordinates().size() + 1, 2, 1))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(sdo_geo_->get_ordinates().size())); + } else { + const T_BIN *line = reinterpret_cast(geo->val()); + typename T_BIN::iterator iter = line->begin(); + for (; OB_SUCC(ret) && iter != line->end(); iter++) { + // (x, y) + if (OB_FAIL(append_inner_point(iter->template get<0>(), iter->template get<1>()))) { + LOG_WARN("fail to append_inner_point", + K(ret), + K(iter->template get<0>()), + K(iter->template get<1>())); + } + } + } + + return ret; +} + +template +int ObWkbToSdoGeoVisitor::append_polygon(T_IBIN *geo) +{ + INIT_SUCC(ret); + + if (!is_multi_visit_ && !is_collection_visit_) { + sdo_geo_->set_gtype(geo->type()); + } + + if (geo->length() < WKB_COMMON_WKB_HEADER_LEN) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid wkb length", K(ret), K(geo->length())); + } else { + T_BIN &poly = *(T_BIN *)(geo->val()); + T_BIN_RING &exterior = poly.exterior_ring(); + T_BIN_INNER_RING &inner_rings = poly.inner_rings(); + if (poly.size() == 0) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid poly size", K(ret), K(poly.size())); + } else if (OB_FAIL(append_elem_info(sdo_geo_->get_ordinates().size() + 1, 1003, 1))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(sdo_geo_->get_ordinates().size())); + } else { + typename T_BIN_RING::iterator ext_iter = exterior.begin(); + for (; OB_SUCC(ret) && ext_iter != exterior.end(); ++ext_iter) { + if (OB_FAIL(append_inner_point(ext_iter->template get<0>(), ext_iter->template get<1>()))) { + LOG_WARN("fail to append_inner_point", + K(ret), + K(ext_iter->template get<0>()), + K(ext_iter->template get<1>())); + } + } + + typename T_BIN_INNER_RING::iterator inner_iter = inner_rings.begin(); + for (; OB_SUCC(ret) && inner_iter != inner_rings.end(); ++inner_iter) { + // uint32_t size = inner_iter->size(); + if (OB_FAIL(append_elem_info(sdo_geo_->get_ordinates().size() + 1, 2003, 1))) { + LOG_WARN("fail to append sdo_elem_info", K(ret), K(sdo_geo_->get_ordinates().size())); + } + typename T_BIN_RING::iterator iter = (*inner_iter).begin(); + for (; OB_SUCC(ret) && iter != (*inner_iter).end(); ++iter) { + if (OB_FAIL(append_inner_point(iter->template get<0>(), iter->template get<1>()))) { + LOG_WARN("fail to append_inner_point", + K(ret), + K(iter->template get<0>()), + K(iter->template get<1>())); + } + } + } + } + } + + return ret; +} + +template +void ObWkbToSdoGeoVisitor::append_gtype(T_IBIN *geo) +{ + if (!is_collection_visit_ || geo->type() == ObGeoType::GEOMETRYCOLLECTION) { + sdo_geo_->set_gtype(geo->type()); + } +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeomLineString *geo) +{ + UNUSED(geo); + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeomPolygon *geo) +{ + UNUSED(geo); + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeomMultiPoint *geo) +{ + UNUSED(geo); + is_multi_visit_ = true; + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeomMultiLineString *geo) +{ + UNUSED(geo); + is_multi_visit_ = true; + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeomMultiPolygon *geo) +{ + UNUSED(geo); + is_multi_visit_ = true; + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeomCollection *geo) +{ + UNUSED(geo); + is_collection_visit_ = true; + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeogLineString *geo) +{ + UNUSED(geo); + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeogPolygon *geo) +{ + UNUSED(geo); + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeogMultiPoint *geo) +{ + UNUSED(geo); + is_multi_visit_ = true; + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeogMultiLineString *geo) +{ + UNUSED(geo); + is_multi_visit_ = true; + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeogMultiPolygon *geo) +{ + UNUSED(geo); + is_multi_visit_ = true; + return true; +} + +bool ObWkbToSdoGeoVisitor::prepare(ObIWkbGeogCollection *geo) +{ + UNUSED(geo); + is_collection_visit_ = true; + return true; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeomPoint *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((append_point(geo)))) { + LOG_WARN("fail to append point", K(ret)); + } + return ret; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeomLineString *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((append_linestring(geo)))) { + LOG_WARN("fail to append line", K(ret)); + } + return ret; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeomPolygon *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((append_polygon(geo)))) { + LOG_WARN("fail to append polygon", K(ret)); + } + return ret; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeomMultiPoint *geo) +{ + INIT_SUCC(ret); + append_gtype(geo); + if (OB_FAIL(append_elem_info(sdo_geo_->get_ordinates().size() + 1, 1, geo->size()))) { + LOG_WARN( + "fail to append_elem_info", K(ret), K(sdo_geo_->get_ordinates().size()), K(geo->size())); + } + return ret; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeomMultiLineString *geo) +{ + append_gtype(geo); + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeomMultiPolygon *geo) +{ + append_gtype(geo); + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeomCollection *geo) +{ + append_gtype(geo); + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeogPoint *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((append_point(geo)))) { + LOG_WARN("fail to append point", K(ret)); + } + return ret; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeogLineString *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((append_linestring(geo)))) { + LOG_WARN("fail to append line", K(ret)); + } + return ret; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeogPolygon *geo) +{ + INIT_SUCC(ret); + if (OB_FAIL((append_polygon(geo)))) { + LOG_WARN("fail to append polygon", K(ret)); + } + return ret; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeogMultiPoint *geo) +{ + INIT_SUCC(ret); + append_gtype(geo); + if (OB_FAIL(append_elem_info(sdo_geo_->get_ordinates().size() + 1, 1, geo->size()))) { + LOG_WARN( + "fail to append_elem_info", K(ret), K(sdo_geo_->get_ordinates().size()), K(geo->size())); + } + return ret; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeogMultiLineString *geo) +{ + append_gtype(geo); + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeogMultiPolygon *geo) +{ + append_gtype(geo); + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::visit(ObIWkbGeogCollection *geo) +{ + append_gtype(geo); + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::finish(ObIWkbGeomMultiPoint *geo) +{ + is_multi_visit_ = false; + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::finish(ObIWkbGeomMultiLineString *geo) +{ + UNUSED(geo); + is_multi_visit_ = false; + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::finish(ObIWkbGeomMultiPolygon *geo) +{ + UNUSED(geo); + is_multi_visit_ = false; + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::finish(ObIWkbGeomCollection *geo) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::finish(ObIWkbGeogMultiPoint *geo) +{ + is_multi_visit_ = false; + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::finish(ObIWkbGeogMultiLineString *geo) +{ + UNUSED(geo); + is_multi_visit_ = false; + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::finish(ObIWkbGeogMultiPolygon *geo) +{ + UNUSED(geo); + is_multi_visit_ = false; + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::finish(ObIWkbGeogCollection *geo) +{ + UNUSED(geo); + return OB_SUCCESS; +} + +int ObWkbToSdoGeoVisitor::init(ObSdoGeoObject *geo, uint32_t srid) +{ + INIT_SUCC(ret); + sdo_geo_ = geo; + if (OB_ISNULL(sdo_geo_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("ObSdoGeoObject ptr is null", K(ret)); + } else { + sdo_geo_->set_srid(srid); + } + + return ret; +} +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_wkb_to_sdo_geo_visitor.h b/deps/oblib/src/lib/geo/ob_wkb_to_sdo_geo_visitor.h new file mode 100644 index 0000000000..e13ebedac4 --- /dev/null +++ b/deps/oblib/src/lib/geo/ob_wkb_to_sdo_geo_visitor.h @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_LIB_GEO_OB_WKB_TO_SDO_GEO_VISITOR_ +#define OCEANBASE_LIB_GEO_OB_WKB_TO_SDO_GEO_VISITOR_ + +#include "lib/geo/ob_geo_visitor.h" +#include "lib/geo/ob_sdo_geo_object.h" + +namespace oceanbase +{ +namespace common +{ +class ObWkbToSdoGeoVisitor : public ObEmptyGeoVisitor +{ +public: + explicit ObWkbToSdoGeoVisitor() + : is_multi_visit_(false), is_collection_visit_(false) + {} + ~ObWkbToSdoGeoVisitor() + {} + int init(ObSdoGeoObject *geo, uint32_t srid = UINT32_MAX); + + bool prepare(ObIWkbGeomLineString *geo); + bool prepare(ObIWkbGeomPolygon *geo); + bool prepare(ObIWkbGeomMultiPoint *geo); + bool prepare(ObIWkbGeomMultiLineString *geo); + bool prepare(ObIWkbGeomMultiPolygon *geo); + bool prepare(ObIWkbGeomCollection *geo); + bool prepare(ObIWkbGeogLineString *geo); + bool prepare(ObIWkbGeogPolygon *geo); + bool prepare(ObIWkbGeogMultiPoint *geo); + bool prepare(ObIWkbGeogMultiLineString *geo); + bool prepare(ObIWkbGeogMultiPolygon *geo); + bool prepare(ObIWkbGeogCollection *geo); + + int visit(ObIWkbGeomPoint *geo); + int visit(ObIWkbGeomLineString *geo); + int visit(ObIWkbGeomPolygon *geo); + int visit(ObIWkbGeomMultiPoint *geo); + int visit(ObIWkbGeomMultiLineString *geo); + int visit(ObIWkbGeomMultiPolygon *geo); + int visit(ObIWkbGeomCollection *geo); + int visit(ObIWkbGeogPoint *geo); + int visit(ObIWkbGeogLineString *geo); + int visit(ObIWkbGeogPolygon *geo); + int visit(ObIWkbGeogMultiPoint *geo); + int visit(ObIWkbGeogMultiLineString *geo); + int visit(ObIWkbGeogMultiPolygon *geo); + int visit(ObIWkbGeogCollection *geo); + + virtual int finish(ObIWkbGeomMultiPoint *geo) override; + virtual int finish(ObIWkbGeomMultiLineString *geo) override; + virtual int finish(ObIWkbGeomMultiPolygon *geo) override; + virtual int finish(ObIWkbGeomCollection *geo) override; + virtual int finish(ObIWkbGeogMultiPoint *geo) override; + virtual int finish(ObIWkbGeogMultiLineString *geo) override; + virtual int finish(ObIWkbGeogMultiPolygon *geo) override; + virtual int finish(ObIWkbGeogCollection *geo) override; + + bool is_end(ObIWkbGeomLineString *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeomLinearRing *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeomPolygon *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeogLineString *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeogLinearRing *geo) { UNUSED(geo); return true; } + bool is_end(ObIWkbGeogPolygon *geo) { UNUSED(geo); return true; } + + // void get_sdo_geo(ObSdoGeoObject *geo); + +private: + static constexpr double MAX_NUMBER_ORACLE = 1e+126; + static constexpr double MIN_NUMBER_ORACLE = 1e-130; + + template + int append_point(T_IBIN *geo); + template + int append_linestring(T_IBIN *geo); + template + int append_polygon(T_IBIN *geo); + template + void append_gtype(T_IBIN *geo); + int append_inner_point(double x, double y); + int append_elem_info(uint64_t offset, uint64_t etype, uint64_t interpretation); + bool is_valid_to_represent(double num); + + bool is_multi_visit_; + bool is_collection_visit_; + ObSdoGeoObject *sdo_geo_; +}; +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_wkt_parser.cpp b/deps/oblib/src/lib/geo/ob_wkt_parser.cpp index 8cab49e6b0..4553226b93 100644 --- a/deps/oblib/src/lib/geo/ob_wkt_parser.cpp +++ b/deps/oblib/src/lib/geo/ob_wkt_parser.cpp @@ -189,7 +189,9 @@ bool ObWktParser::is_wkt_end() bool ObWktParser::is_number_beginning(char ch) { int bret = false; - if ('+' == ch || '-' == ch || '.' == ch || isdigit(ch)) { + if ('-' == ch || '.' == ch || isdigit(ch)) { + bret = true; + } else if (!is_oracle_mode_ && '+' == ch ) { bret = true; } return bret; @@ -258,31 +260,20 @@ int ObWktParser::process_word(ObWktTokenVal &tkn_val) int ObWktParser::parse(ObGeometry *&geo, bool is_geographical) { int ret = OB_SUCCESS; - skip_left_space(); - ObWktTokenVal tkn_val; - ObGeoType geo_type = ObGeoType::GEOTYPEMAX; - - if (OB_FAIL(check_next_token_with_val_keep_pos(ObWktTokenType::W_WORD, tkn_val))) { - LOG_WARN("fail to parse geometry type from wkt", K(ret)); - } else { - geo_type = ObGeoTypeUtil::get_geo_type_by_name(tkn_val.string_val_); - if (ObGeoType::GEOTYPEMAX == geo_type) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid geo type", K(ret), K(tkn_val.string_val_)); - } else if (OB_FAIL(inner_parse())){ + if (OB_FAIL(inner_parse())){ LOG_WARN("fail to do inner parse for wkt", K(ret)); - } - } - - if (OB_SUCC(ret) && !is_wkt_end()) { + } else if (!is_wkt_end()) { ret = OB_ERR_PARSER_SYNTAX; LOG_WARN("wkt has extra character after parse", K(ret), K(cur_pos_)); } if (OB_SUCC(ret)) { // new geo and attach wkb buffer - if (OB_FAIL(ObGeoTypeUtil::create_geo_by_type(allocator_, geo_type, is_geographical, true, geo))) { - LOG_WARN("fail to create geometry given type", K(ret), K(tkn_val.string_val_)); + uint32_t geo_type = 0; + if (OB_FAIL(wkb_buf_.read(sizeof(uint8_t), geo_type))) { + LOG_WARN("fail to get geo type from wkb buff", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_type(allocator_, static_cast(geo_type), is_geographical, true, geo))) { + LOG_WARN("fail to create geometry given type", K(ret), K(geo_type)); } else { geo->set_data(wkb_buf_.string()); } @@ -291,6 +282,55 @@ int ObWktParser::parse(ObGeometry *&geo, bool is_geographical) return ret; } +int ObWktParser::parse_geo_type(ObGeoType &geo_type) +{ + int ret = OB_SUCCESS; + skip_left_space(); + ObWktTokenVal tkn_val_1; + + if (OB_FAIL(check_next_token_with_val(ObWktTokenType::W_WORD, tkn_val_1))) { + LOG_WARN("fail to parse geometry type from wkt", K(ret)); + } else if (0 == tkn_val_1.string_val_.case_compare("geomcollection")) { + ret = OB_ERR_PARSER_SYNTAX; + LOG_WARN("wkt has extra character after parse", K(ret), K(cur_pos_)); + } else { + geo_type = ObGeoTypeUtil::get_geo_type_by_name(tkn_val_1.string_val_); + } + + if (OB_FAIL(ret)) { + } else if (ObGeoTypeUtil::is_3d_geo_type(geo_type)) { + // 3d type + if (OB_FAIL(set_dimension(ObGeoDimType::IS_3D))) { + LOG_WARN("fail to set dimension type", K(ret)); + } + } else { + ObWktTokenType tkn_type_2; + ObWktTokenVal tkn_val_2; + if (OB_FAIL(get_next_token_keep_pos(tkn_type_2, tkn_val_2))) { + LOG_WARN("fail to parse next token", K(ret)); + } else if (tkn_type_2 == ObWktTokenType::W_WORD && 0 == tkn_val_2.string_val_.case_compare("z")) { + // case like 'point z(1 1 1)' + if (OB_FAIL(set_dimension(ObGeoDimType::IS_3D))) { + LOG_WARN("fail to set dimension type", K(ret)); + } else { + geo_type = static_cast(static_cast(geo_type) + 1000); + if (OB_FAIL(check_next_token(ObWktTokenType::W_WORD))) { // move the cur_pos_ to next token + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected token type", K(ret)); + } + } + } + } + + if (is_oracle_mode_ && ObGeoTypeUtil::is_3d_geo_type(geo_type) && OB_SUCC(ret)) { + // wkt + z is not supported in oracle mode + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected token type", K(ret)); + } + + return ret; +} + // [bo][geo_type][binary] int ObWktParser::inner_parse() { @@ -298,95 +338,149 @@ int ObWktParser::inner_parse() skip_left_space(); ObWktTokenVal tkn_val; ObGeoType geo_type = ObGeoType::GEOTYPEMAX; - - if (OB_FAIL(check_next_token_with_val(ObWktTokenType::W_WORD, tkn_val))) { - LOG_WARN("fail to parse geometry type from wkt", K(ret)); + if (OB_FAIL(parse_geo_type(geo_type))) { + LOG_WARN("fail to parse geo type", K(ret)); + } else if (OB_FAIL(wkb_buf_.append(static_cast(ObGeoWkbByteOrder::LittleEndian)))) { + LOG_WARN("fail to append byteorder to wkb buffer", K(ret)); + } else if (OB_FAIL(wkb_buf_.append(static_cast(geo_type)))) { + LOG_WARN("fail to append geo_type to wkb buffer", K(ret)); } else { - geo_type = ObGeoTypeUtil::get_geo_type_by_name(tkn_val.string_val_); - if (ObGeoType::GEOTYPEMAX == geo_type) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid geo type", K(ret), K(tkn_val.string_val_)); - } else { - if (OB_FAIL(wkb_buf_.append(static_cast(ObGeoWkbByteOrder::LittleEndian)))) { - LOG_WARN("fail to append byteorder to wkb buffer", K(ret)); - } else if (OB_FAIL(wkb_buf_.append(static_cast(geo_type)))) { - LOG_WARN("fail to append geo_type to wkb buffer", K(ret)); - } else { - switch(geo_type) { - case ObGeoType::POINT: { - if (OB_FAIL(parse_point())) { - LOG_WARN("fail to parse point wkt", K(ret)); - } - break; - } - case ObGeoType::LINESTRING: { - if (OB_FAIL(parse_linestring())) { - LOG_WARN("fail to parse linestring wkt", K(ret)); - } - break; - } - case ObGeoType::POLYGON: { - if (OB_FAIL(parse_polygon())) { - LOG_WARN("fail to parse polygon wkt", K(ret)); - } - break; - } - case ObGeoType::MULTIPOINT: { - if (OB_FAIL(parse_multipoint())) { - LOG_WARN("fail to parse multipoint wkt", K(ret)); - } - break; - } - case ObGeoType::MULTILINESTRING: { - if (OB_FAIL(parse_mutilinestring())) { - LOG_WARN("fail to parse multilinestring wkt", K(ret)); - } - break; - } - case ObGeoType::MULTIPOLYGON: { - if (OB_FAIL(parse_multipolygen())) { - LOG_WARN("fail to parse multipolygen wkt", K(ret)); - } - break; - } - case ObGeoType::GEOMETRYCOLLECTION: { - if (OB_FAIL(parse_geometrycollectioin())) { - LOG_WARN("fail to parse geometrycollection wkt", K(ret)); - } - break; - } - default: { - // not reach here - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid wkt geo type", K(ret), K(geo_type), K(tkn_val.string_val_)); - break; - } + uint64_t pos = wkb_buf_.length() - sizeof(uint32_t); + switch(geo_type) { + case ObGeoType::POINT: + case ObGeoType::POINTZ: { + if (OB_FAIL(parse_point())) { + LOG_WARN("fail to parse point wkt", K(ret)); } + break; } + case ObGeoType::LINESTRING: + case ObGeoType::LINESTRINGZ: { + if (OB_FAIL(parse_linestring())) { + LOG_WARN("fail to parse linestring wkt", K(ret)); + } + break; + } + case ObGeoType::POLYGON: + case ObGeoType::POLYGONZ: { + if (OB_FAIL(parse_polygon())) { + LOG_WARN("fail to parse polygon wkt", K(ret)); + } + break; + } + case ObGeoType::MULTIPOINT: + case ObGeoType::MULTIPOINTZ: { + if (OB_FAIL(parse_multipoint())) { + LOG_WARN("fail to parse multipoint wkt", K(ret)); + } + break; + } + case ObGeoType::MULTILINESTRING: + case ObGeoType::MULTILINESTRINGZ: { + if (OB_FAIL(parse_mutilinestring())) { + LOG_WARN("fail to parse multilinestring wkt", K(ret)); + } + break; + } + case ObGeoType::MULTIPOLYGON: + case ObGeoType::MULTIPOLYGONZ: { + if (OB_FAIL(parse_multipolygen())) { + LOG_WARN("fail to parse multipolygen wkt", K(ret)); + } + break; + } + case ObGeoType::GEOMETRYCOLLECTION: + case ObGeoType::GEOMETRYCOLLECTIONZ: { + if (OB_FAIL(parse_geometrycollectioin())) { + LOG_WARN("fail to parse geometrycollection wkt", K(ret)); + } + break; + } + default: { + // not reach here + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid wkt geo type", K(ret), K(geo_type), K(tkn_val.string_val_)); + break; + } + } // end switch + if (OB_SUCC(ret) && OB_FAIL(refresh_type(pos))) { + LOG_WARN("fail to refresh type", K(ret)); } } return ret; } +int ObWktParser::refresh_type(uint64_t pos) +{ + int ret = OB_SUCCESS; + const char *ptr = wkb_buf_.ptr(); + uint32_t type = static_cast(ObGeoType::GEO3DTYPEMAX); + if (OB_ISNULL(ptr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to refresh type",K(ret)); + } else if (OB_FAIL(wkb_buf_.read(pos, type))) { + LOG_WARN("fail to read type", K(ret)); + } else if (dim_type_ == ObGeoDimType::IS_3D && + type <= 7 && + OB_FAIL(wkb_buf_.write(pos, type + 1000))) { + LOG_WARN("fail to refresh type", K(ret), K(type)); + } + return ret; +} + // encode wkt without bo and geo_type int ObWktParser::parse_point(bool with_brackets) { int ret = OB_SUCCESS; ObWktTokenVal x_val; ObWktTokenVal y_val; + ObWktTokenVal z_val; if (with_brackets && OB_FAIL(check_next_token(ObWktTokenType::W_LEFT_B))) { LOG_WARN("fail to parse point, check next LEFT_B", K(ret)); } else if (OB_FAIL(check_next_token_with_val(ObWktTokenType::W_NUMBER, x_val))) { LOG_WARN("fail to parse point, check next NUMBER", K(ret)); } else if (OB_FAIL(check_next_token_with_val(ObWktTokenType::W_NUMBER, y_val))) { LOG_WARN("fail to parse point, check next NUMBER", K(ret)); + } else if (OB_FAIL(try_parse_zdim_token(z_val))) { + LOG_WARN("fail to try parse z dim value", K(ret)); } else if (with_brackets && OB_FAIL(check_next_token(ObWktTokenType::W_RIGHT_B))) { LOG_WARN("fail to parse point, check next RIGHT_B", K(ret)); } else if (OB_FAIL(wkb_buf_.append(x_val.number_val_))) { LOG_WARN("fail to append x_val to point", K(ret)); } else if (OB_FAIL(wkb_buf_.append(y_val.number_val_))) { LOG_WARN("fail to append y_val to point", K(ret)); + } else if (dim_type_ == ObGeoDimType::IS_3D && OB_FAIL(wkb_buf_.append(z_val.number_val_))) { + LOG_WARN("fail to append z_val to point", K(dim_type_), K(ret)); + } + return ret; +} + +int ObWktParser::try_parse_zdim_token(ObWktTokenVal &z_val) +{ + int ret = OB_SUCCESS; + ObGeoDimType tmp_dim_type = ObGeoDimType::NOT_INIT; + ObWktTokenType tk_type; + if (OB_FAIL(get_next_token_keep_pos(tk_type, z_val))) { + LOG_WARN("fail to get next token", K(ret)); + } else if (tk_type == ObWktTokenType::W_NUMBER) { + tmp_dim_type = ObGeoDimType::IS_3D; + } else if (tk_type == ObWktTokenType::W_RIGHT_B || tk_type == ObWktTokenType::W_COMMA) { + tmp_dim_type = ObGeoDimType::IS_2D; + } else { + ret = OB_ERR_PARSER_SYNTAX; + LOG_WARN("fail to parse point type", K(ret)); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(set_dimension(tmp_dim_type))) { + LOG_WARN("fail to set dimension type", K(ret)); + } + + if (OB_SUCC(ret)) { // if dim is 3,move the ptr to next token + if (dim_type_ == ObGeoDimType::IS_3D && OB_FAIL(check_next_token(ObWktTokenType::W_NUMBER))) { + LOG_WARN("fail to move to the next token", K(ret)); + } + } } return ret; } @@ -428,15 +522,17 @@ int ObWktParser::parse_linestring(bool is_ring) if (num_points < 4) { ret = OB_ERR_PARSER_SYNTAX; } else { + uint8_t dim = dim_type_ == ObGeoDimType::IS_3D ? 3 : 2; + // 3D ring is legal as long as the X/Y axes are equal bool not_same_point = MEMCMP(wkb_buf_.ptr() + pos + sizeof(uint32_t), - wkb_buf_.ptr() + wkb_buf_.length() - 2 * sizeof(double), 2 * sizeof(double)); + wkb_buf_.ptr() + wkb_buf_.length() - dim * sizeof(double), 2 * sizeof(double)); - if (not_same_point) { + if (not_same_point && !lib::is_oracle_mode()) { ret = OB_ERR_PARSER_SYNTAX; LOG_WARN("first point and last point have to be the same in a ring", K(ret)); } } - } else if (num_points < 2){ + } else if (num_points < 2) { ret = OB_ERR_PARSER_SYNTAX; } } @@ -446,7 +542,6 @@ int ObWktParser::parse_linestring(bool is_ring) } } - return ret; } @@ -519,6 +614,7 @@ int ObWktParser::parse_multi_geom(ObGeoType geo_type, bool brackets) LOG_WARN("fail to move back wkb buffer", K(ret)); } else { do { + uint64_t type_pos = wkb_buf_.length() + sizeof(char); // TODO: point without brackets if (OB_FAIL(wkb_buf_.append(static_cast(ObGeoWkbByteOrder::LittleEndian)))) { LOG_WARN("fail to add bo to xxx inside multixxx", K(ret), K(geo_type)); @@ -537,6 +633,9 @@ int ObWktParser::parse_multi_geom(ObGeoType geo_type, bool brackets) } else { ret = OB_ERR_PARSER_SYNTAX; } + if (OB_SUCC(ret) && OB_FAIL(refresh_type(type_pos))) { // refresh type + LOG_WARN("fail to refresh geo type", K(ret)); + } } } while(has_more_geo && OB_SUCC(ret)); @@ -552,7 +651,18 @@ int ObWktParser::parse_multi_geom(ObGeoType geo_type, bool brackets) } int ObWktParser::parse_multipoint() { - return parse_multi_geom(ObGeoType::POINT, is_two_brac_beginning()); + int ret = OB_SUCCESS; + bool two_brac_beg = is_two_brac_beginning(); + if (is_oracle_mode_) { + if (!two_brac_beg) { + ret = OB_ERR_PARSER_SYNTAX; + LOG_WARN("Oracle's Multipoint objects require brac around each point", K(ret)); + } + } + if (OB_SUCC(ret)) { + ret = parse_multi_geom(ObGeoType::POINT, two_brac_beg); + } + return ret; } int ObWktParser::parse_mutilinestring() @@ -633,5 +743,17 @@ int ObWktParser::parse_wkt(ObIAllocator &allocator, const ObString &wkt, ObGeome return ret; } +int ObWktParser::set_dimension(ObGeoDimType dim) +{ + int ret = OB_SUCCESS; + if (dim_type_ == ObGeoDimType::NOT_INIT) { + dim_type_ = dim; + } else if (dim_type_ != dim) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("dimensions mismatch in geometry", K(ret), K(dim_type_), K(dim)); + } + return ret; +} + } // end namespace common } // end namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/lib/geo/ob_wkt_parser.h b/deps/oblib/src/lib/geo/ob_wkt_parser.h index c38de0a06e..312f2b71eb 100644 --- a/deps/oblib/src/lib/geo/ob_wkt_parser.h +++ b/deps/oblib/src/lib/geo/ob_wkt_parser.h @@ -40,6 +40,13 @@ private: W_EMPTY }; + enum ObGeoDimType: uint8_t + { + NOT_INIT, + IS_2D, + IS_3D + }; + typedef union ObWktTokenVal { ObString string_val_; double number_val_; @@ -47,7 +54,8 @@ private: } ObWktTokenVal; explicit ObWktParser (ObIAllocator &allocator, const ObString &wkt) : - allocator_(allocator), wkt_(wkt.ptr()), wkb_buf_(allocator), cur_pos_(0), wkt_len_(wkt.length()) {} + allocator_(allocator), wkt_(wkt.ptr()), wkb_buf_(allocator), cur_pos_(0), wkt_len_(wkt.length()), + dim_type_(ObGeoDimType::NOT_INIT), is_oracle_mode_(lib::is_oracle_mode()) {} ~ObWktParser(){}; int parse(ObGeometry *&geo, bool is_geographical); @@ -77,13 +85,19 @@ private: int process_word(ObWktTokenVal &tkn_val); int get_next_token(ObWktTokenType &tkn_type, ObString &tkn_string); + // for 3D object + int try_parse_zdim_token(ObWktTokenVal &z_val); + int parse_geo_type(ObGeoType &geo_type); + int refresh_type(uint64_t pos); + int set_dimension(ObGeoDimType dim); common::ObIAllocator &allocator_; const char *wkt_; ObWkbBuffer wkb_buf_; int64_t cur_pos_; int64_t wkt_len_; - + ObGeoDimType dim_type_; + bool is_oracle_mode_; DISALLOW_COPY_AND_ASSIGN(ObWktParser); }; diff --git a/deps/oblib/src/lib/json_type/ob_json_base.cpp b/deps/oblib/src/lib/json_type/ob_json_base.cpp index 4e2deff7d7..c2b254004b 100644 --- a/deps/oblib/src/lib/json_type/ob_json_base.cpp +++ b/deps/oblib/src/lib/json_type/ob_json_base.cpp @@ -3692,8 +3692,10 @@ static const obmysql::EMySQLFieldType opaque_ob_type_to_mysql_type[ObMaxType] = obmysql::EMySQLFieldType::MYSQL_TYPE_OB_UROWID, obmysql::EMySQLFieldType::MYSQL_TYPE_ORA_BLOB, /* ObLobType */ obmysql::EMySQLFieldType::MYSQL_TYPE_JSON, /* ObJsonType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_GEOMETRY, /* ObGeometryType */ obmysql::EMySQLFieldType::MYSQL_TYPE_COMPLEX, /* ObUserDefinedSQLType, buf for xml we use long_blob type currently? */ obmysql::EMySQLFieldType::MYSQL_TYPE_NEWDECIMAL, /* ObDecimalIntType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_COMPLEX, /* ObCollectionSQLType */ /* ObMaxType */ }; diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_result.h b/deps/oblib/src/lib/mysqlclient/ob_mysql_result.h index 32b38e2031..fd133e2858 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_result.h +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_result.h @@ -1063,7 +1063,7 @@ res_obj.meta_.set_collation_level(CS_LEVEL_IMPLICIT); \ ret = (class_obj).set_##column_name(res_obj); \ } \ - else if (column.is_identity_column() || ob_is_string_type(data_type) || ob_is_geometry(data_type)) \ + else if (column.is_identity_column() || ob_is_string_type(data_type) || ob_is_geometry(data_type) || ob_is_collection_sql_type(data_type)) \ { \ res_obj.set_string(data_type, str_value); \ res_obj.meta_.set_collation_type(column.get_collation_type()); \ @@ -1075,7 +1075,7 @@ SQL_LOG(WARN, "outrow lob unsupported", "column_name", #column_name); \ } \ else { \ - if (ob_is_text_tc(data_type) || ob_is_geometry(data_type)) { res_obj.set_inrow(); } \ + if (ob_is_text_tc(data_type) || ob_is_geometry(data_type) || ob_is_collection_sql_type(data_type)) { res_obj.set_inrow(); } \ ret = (class_obj).set_##column_name(res_obj); \ } \ } \ diff --git a/deps/oblib/src/lib/ob_define.h b/deps/oblib/src/lib/ob_define.h index 1954ec494d..f7b89454a2 100644 --- a/deps/oblib/src/lib/ob_define.h +++ b/deps/oblib/src/lib/ob_define.h @@ -1719,7 +1719,7 @@ const int64_t OB_MAX_BIT_LENGTH = 64; // Compatible with mysql, 64 bit const int64_t OB_MAX_SET_ELEMENT_NUM = 64; // Compatible with mysql8.0, the number of values const int64_t OB_MAX_INTERVAL_VALUE_LENGTH = 255; // Compatible with mysql, unit character const int64_t OB_MAX_ENUM_ELEMENT_NUM = 65535; // Compatible with mysql8.0, the number of enum values - +const int64_t OB_MAX_QUALIFIED_COLUMN_NAME_LENGTH = 4096; // Compatible with oracle const int64_t OB_MAX_VARCHAR_LENGTH_KEY = 16 * 1024L; //KEY key varchar maximum length limit const int64_t OB_OLD_MAX_VARCHAR_LENGTH = 64 * 1024; // for compatible purpose // For compatibility we set max default value as 256K bytes/64K chars. diff --git a/deps/oblib/src/lib/ob_name_def.h b/deps/oblib/src/lib/ob_name_def.h index a837cbe97e..b1cd8344a0 100644 --- a/deps/oblib/src/lib/ob_name_def.h +++ b/deps/oblib/src/lib/ob_name_def.h @@ -1070,11 +1070,31 @@ #define N_XMLCAST "xmlcast" #define N_UPDATEXML "updatexml" #define N_NLS_INITCAP "nls_initcap" +#define N_PRIV_SQL_UDT_CONSTRUCT "_udt_construct" +#define N_PRIV_UDT_ATTR_ACCESS "_udt_attr_access" #define N_TEMP_TABLE_SSID "temp_table_ssid" +#define N_PRIV_ST_NUMINTERIORRINGS "_st_numinteriorrings" +#define N_PRIV_ST_ISCOLLECTION "_st_iscollection" +#define N_PRIV_ST_EQUALS "st_equals" +#define N_PRIV_ST_TOUCHES "_st_touches" #define N_ALIGN_DATE4CMP "align_date4cmp" #define N_INEER_IS_TRUE "inner_is_true" #define N_INNER_DECODE_LIKE "inner_decode_like" #define N_EXTRACT_CERT_EXPIRED_TIME "extract_cert_expired_time" #define N_INNER_ROW_CMP_VALUE "inner_row_cmp_value" #define N_SYS_LAST_REFRESH_SCN "last_refresh_scn" +#define N_PRIV_ST_MAKEENVELOPE "_st_makeenvelope" +#define N_PRIV_ST_CLIPBYBOX2D "_st_clipbybox2d" +#define N_PRIV_ST_POINTONSURFACE "_st_pointonsurface" +#define N_PRIV_ST_GEOMETRYTYPE "_st_geometrytype" +#define N_ST_CROSSES "st_crosses" +#define N_ST_OVERLAPS "st_overlaps" +#define N_ST_UNION "st_union" +#define N_ST_LENGTH "st_length" +#define N_ST_DIFFERENCE "st_difference" +#define N_ST_ASGEOJSON "st_asgeojson" +#define N_ST_CENTROID "st_centroid" +#define N_ST_SYMDIFFERENCE "st_symdifference" +#define N_PRIV_ST_ASMVTGEOM "_st_asmvtgeom" +#define N_PRIV_ST_MAKEVALID "_st_makevalid" #endif //OCEANBASE_LIB_OB_NAME_DEF_H_ diff --git a/deps/oblib/src/lib/rowid/ob_urowid.cpp b/deps/oblib/src/lib/rowid/ob_urowid.cpp index 7f208f8cd3..b4e5f0e372 100644 --- a/deps/oblib/src/lib/rowid/ob_urowid.cpp +++ b/deps/oblib/src/lib/rowid/ob_urowid.cpp @@ -357,7 +357,8 @@ DEF_GET_OTIME_PK_VALUE(ObTimestampNanoType, timestamp_nano, uint16_t); ObJsonType, \ ObGeometryType, \ ObUserDefinedSQLType, \ - ObDecimalIntType + ObDecimalIntType, \ + ObCollectionSQLType #define DEF_GET_PK_FUNC(obj_type) ObURowIDData::inner_get_pk_value diff --git a/deps/oblib/src/lib/udt/ob_udt_type.h b/deps/oblib/src/lib/udt/ob_udt_type.h index fb696aca50..c69f456711 100644 --- a/deps/oblib/src/lib/udt/ob_udt_type.h +++ b/deps/oblib/src/lib/udt/ob_udt_type.h @@ -48,9 +48,7 @@ public: bool is_same(ObSqlUDTAttrMeta &other) { bool is_same = (order_ == other.order_); if (is_same) { - if ((type_info_.is_user_defined_sql_type() - // || type_info_.is_collection_sql_type() - )) { + if ((type_info_.is_user_defined_sql_type() || type_info_.is_collection_sql_type())) { is_same = (type_info_.get_type() == other.type_info_.get_type() && type_info_.get_scale() == other.type_info_.get_scale()); } else { @@ -191,6 +189,7 @@ public: static uint32_t get_offset_array_len(uint32_t count); static int set_null_bitmap_pos(char *bitmap_start, uint32_t bitmap_len, uint32_t pos); static int get_null_bitmap_pos(const char *bitmap_start, uint32_t bitmap_len, uint32_t pos, bool &is_set); + static inline void increase_varray_null_count(char *null_count) { (*reinterpret_cast(null_count))++; } TO_STRING_KV(KP_(allocator), K_(udt_meta), K_(udt_data)); @@ -199,7 +198,7 @@ private: inline int32_t get_attr_offset(uint32_t index, uint32_t null_bitmap_offset, bool is_varray_element = false) { - int32_t count_offset = is_varray_element ? sizeof(uint32) : 0; + int32_t count_offset = is_varray_element ? sizeof(uint32) + sizeof(uint32) : 0; return reinterpret_cast(udt_data_.ptr() + null_bitmap_offset + count_offset)[index]; } diff --git a/src/logservice/libobcdc/src/ob_cdc_udt.cpp b/src/logservice/libobcdc/src/ob_cdc_udt.cpp index 60f4cb0924..dd6669b21d 100644 --- a/src/logservice/libobcdc/src/ob_cdc_udt.cpp +++ b/src/logservice/libobcdc/src/ob_cdc_udt.cpp @@ -277,7 +277,9 @@ int ObCDCUdtValueBuilder::build_xmltype( if (OB_FAIL(ret)) { } else if (OB_ISNULL(col_str)) { LOG_INFO("col_str is null", K(is_new_value), K(value->is_out_row_), K(value->column_id_)); - } else if (OB_FALSE_IT(cv.value_.set_string(ObUserDefinedSQLType, *col_str))) { + } else if (OB_FALSE_IT(cv.value_.set_sql_udt(col_str->ptr(), + static_cast(col_str->length()), + ObXMLSqlType))) { } else if (OB_FAIL(dml_stmt_task.parse_col( dml_stmt_task.get_tenant_id(), cv.column_id_, diff --git a/src/objit/src/ob_llvm_helper.cpp b/src/objit/src/ob_llvm_helper.cpp index 82df1b8277..025b3e39dc 100644 --- a/src/objit/src/ob_llvm_helper.cpp +++ b/src/objit/src/ob_llvm_helper.cpp @@ -124,7 +124,8 @@ static ObGetIRType OB_IR_TYPE[common::ObMaxType + 1] = NULL, //48.ObGeometryType NULL, //49.ObUserDefinedSQLType NULL, //50. ObDecimalIntType - NULL, //51.ObMaxType + NULL, //51.ObCollectionSQLType + NULL, //52.ObMaxType }; template diff --git a/src/observer/mysql/ob_query_driver.cpp b/src/observer/mysql/ob_query_driver.cpp index b0f642b082..05ca5c8586 100644 --- a/src/observer/mysql/ob_query_driver.cpp +++ b/src/observer/mysql/ob_query_driver.cpp @@ -23,11 +23,12 @@ #include #include "share/ob_lob_access_utils.h" #include "lib/charset/ob_charset.h" +#include "sql/engine/expr/ob_expr_sql_udt_utils.h" #include "observer/mysql/obmp_stmt_prexecute.h" +#include "sql/engine/expr/ob_expr_xml_func_helper.h" #ifdef OB_BUILD_ORACLE_XML #include "lib/xml/ob_multi_mode_interface.h" #include "lib/xml/ob_xml_util.h" -#include "sql/engine/expr/ob_expr_xml_func_helper.h" #endif namespace oceanbase @@ -224,7 +225,8 @@ int ObQueryDriver::response_query_result(ObResultSet &result, } for (int64_t i = 0; OB_SUCC(ret) && i < row->get_count(); i++) { ObObj& value = row->get_cell(i); - if (result.is_ps_protocol() && !is_packed) { + if (result.is_ps_protocol() && !is_packed + && !(value.is_geometry() && lib::is_oracle_mode())) { // oracle gis will do cast in process_sql_udt_results if (value.get_type() != fields->at(i).type_.get_type()) { ObCastCtx cast_ctx(&result.get_mem_pool(), NULL, CM_WARN_ON_FAIL, fields->at(i).type_.get_collation_type()); @@ -259,10 +261,9 @@ int ObQueryDriver::response_query_result(ObResultSet &result, } else if ((value.is_lob() || value.is_lob_locator() || value.is_json() || value.is_geometry()) && OB_FAIL(process_lob_locator_results(value, result))) { LOG_WARN("convert lob locator to longtext failed", K(ret)); -#ifdef OB_BUILD_ORACLE_XML - } else if (value.is_user_defined_sql_type() && OB_FAIL(ObXMLExprHelper::process_sql_udt_results(value, result))) { + } else if ((value.is_user_defined_sql_type() || value.is_collection_sql_type() || value.is_geometry()) && + OB_FAIL(ObXMLExprHelper::process_sql_udt_results(value, result))) { LOG_WARN("convert udt to client format failed", K(ret), K(value.get_udt_subschema_id())); -#endif } } } @@ -634,7 +635,7 @@ int ObQueryDriver::process_lob_locator_results(ObObj& value, // refer to sz/aibo1m // 3. if client does not support use_lob_locator ,,return full lob data without locator header bool is_lob_type = value.is_lob() || value.is_json() || value.is_geometry() || value.is_lob_locator(); - bool is_actual_return_lob_locator = is_use_lob_locator && !value.is_json(); + bool is_actual_return_lob_locator = is_use_lob_locator && !value.is_json() && !value.is_geometry(); if (!is_lob_type) { // not lob types, do nothing } else if (value.is_null() || value.is_nop_value()) { diff --git a/src/observer/mysql/ob_query_driver.h b/src/observer/mysql/ob_query_driver.h index d7e631cad5..9ab5f2a0fb 100644 --- a/src/observer/mysql/ob_query_driver.h +++ b/src/observer/mysql/ob_query_driver.h @@ -25,6 +25,7 @@ namespace sql { struct ObSqlCtx; class ObSQLSessionInfo; +class ObExecContext; class ObResultSet; } @@ -81,7 +82,6 @@ public: common::ObIAllocator &allocator); int convert_lob_locator_to_longtext(common::ObObj& value, sql::ObResultSet &result); int process_lob_locator_results(common::ObObj& value, sql::ObResultSet &result); - int process_sql_udt_results(common::ObObj& value, sql::ObResultSet &result); int convert_lob_value_charset(common::ObObj& value, sql::ObResultSet &result); int convert_text_value_charset(common::ObObj& value, sql::ObResultSet &result); static int convert_lob_locator_to_longtext(common::ObObj& value, @@ -92,11 +92,6 @@ public: bool is_support_outrow_locator_v2, common::ObIAllocator *allocator, const sql::ObSQLSessionInfo *session_info); - - static int process_sql_udt_results(common::ObObj& value, - common::ObIAllocator *allocator, - sql::ObSQLSessionInfo *session_info); - static int convert_string_charset(const common::ObString &in_str, const common::ObCollationType in_cs_type, const common::ObCollationType out_cs_type, diff --git a/src/observer/mysql/ob_sync_cmd_driver.cpp b/src/observer/mysql/ob_sync_cmd_driver.cpp index e0aca50f63..39c9ebef2d 100644 --- a/src/observer/mysql/ob_sync_cmd_driver.cpp +++ b/src/observer/mysql/ob_sync_cmd_driver.cpp @@ -23,9 +23,7 @@ #include "share/ob_lob_access_utils.h" #include "observer/mysql/obmp_stmt_prexecute.h" #include "src/pl/ob_pl_user_type.h" -#ifdef OB_BUILD_ORACLE_XML #include "sql/engine/expr/ob_expr_xml_func_helper.h" -#endif namespace oceanbase { @@ -340,10 +338,9 @@ int ObSyncCmdDriver::response_query_result(ObMySQLResultSet &result) } else if ((value.is_lob() || value.is_lob_locator() || value.is_json() || value.is_geometry()) && OB_FAIL(process_lob_locator_results(value, result))) { LOG_WARN("convert lob locator to longtext failed", K(ret)); -#ifdef OB_BUILD_ORACLE_XML - } else if (value.is_user_defined_sql_type() && OB_FAIL(ObXMLExprHelper::process_sql_udt_results(value, result))) { + } else if ((value.is_user_defined_sql_type() || value.is_collection_sql_type() || value.is_geometry()) && + OB_FAIL(ObXMLExprHelper::process_sql_udt_results(value, result))) { LOG_WARN("convert udt to client format failed", K(ret), K(value.get_udt_subschema_id())); -#endif } } diff --git a/src/observer/mysql/obmp_base.cpp b/src/observer/mysql/obmp_base.cpp index 46a3cc4968..27c19f7b00 100644 --- a/src/observer/mysql/obmp_base.cpp +++ b/src/observer/mysql/obmp_base.cpp @@ -47,9 +47,7 @@ #include "share/ob_lob_access_utils.h" #include "sql/monitor/flt/ob_flt_utils.h" #include "sql/session/ob_sess_info_verify.h" -#ifdef OB_BUILD_ORACLE_XML #include "sql/engine/expr/ob_expr_xml_func_helper.h" -#endif namespace oceanbase { using namespace share; @@ -519,7 +517,10 @@ int ObMPBase::check_and_refresh_schema(uint64_t login_tenant_id, int ObMPBase::response_row(ObSQLSessionInfo &session, common::ObNewRow &row, const ColumnsFieldIArray *fields, - bool is_packed) + bool is_packed, + ObExecContext *exec_ctx, + bool is_ps_protocol, + ObSchemaGetterGuard *schema_guard) { int ret = OB_SUCCESS; ObArenaAllocator allocator; @@ -536,7 +537,8 @@ int ObMPBase::response_row(ObSQLSessionInfo &session, ObCharsetType charset_type = CHARSET_INVALID; ObCharsetType ncharset_type = CHARSET_INVALID; // need at ps mode - if (!is_packed && value.get_type() != fields->at(i).type_.get_type()) { + if (!is_packed && value.get_type() != fields->at(i).type_.get_type() + && !(value.is_geometry() && lib::is_oracle_mode())) {// oracle gis will do cast in process_sql_udt_results ObCastCtx cast_ctx(&allocator, NULL, CM_WARN_ON_FAIL, fields->at(i).type_.get_collation_type()); if (ObDecimalIntType == fields->at(i).type_.get_type()) { cast_ctx.res_accuracy_ = const_cast(&fields->at(i).accuracy_); @@ -581,20 +583,22 @@ int ObMPBase::response_row(ObSQLSessionInfo &session, &allocator, &session))) { LOG_WARN("convert lob locator to longtext failed", K(ret)); -#ifdef OB_BUILD_ORACLE_XML - } else if (value.is_user_defined_sql_type() + } else if ((value.is_user_defined_sql_type() || value.is_collection_sql_type() || value.is_geometry()) && OB_FAIL(ObXMLExprHelper::process_sql_udt_results(value, &allocator, - &session))) { + &session, + exec_ctx, + is_ps_protocol, + fields, + schema_guard))) { LOG_WARN("convert udt to client format failed", K(ret), K(value.get_udt_subschema_id())); -#endif } } } if (OB_SUCC(ret)) { const ObDataTypeCastParams dtc_params = ObBasicSessionInfo::create_dtc_params(&session); - ObSMRow sm_row(obmysql::BINARY, tmp_row, dtc_params, fields); + ObSMRow sm_row(obmysql::BINARY, tmp_row, dtc_params, fields, schema_guard); sm_row.set_packed(is_packed); obmysql::OMPKRow rp(sm_row); rp.set_is_packed(is_packed); diff --git a/src/observer/mysql/obmp_base.h b/src/observer/mysql/obmp_base.h index c4330a91fb..4780b1ea8a 100644 --- a/src/observer/mysql/obmp_base.h +++ b/src/observer/mysql/obmp_base.h @@ -126,7 +126,10 @@ protected: int response_row(sql::ObSQLSessionInfo &session, common::ObNewRow &row, const ColumnsFieldIArray *fields, - bool is_packed); + bool is_packed, + sql::ObExecContext *exec_ctx = NULL, + bool is_ps_protocol = false, + ObSchemaGetterGuard *schema_guard = NULL); int process_extra_info(sql::ObSQLSessionInfo &session, const obmysql::ObMySQLRawPacket &pkt, bool &need_response_error); int process_kill_client_session(sql::ObSQLSessionInfo &session, bool is_connect = false); diff --git a/src/observer/mysql/obmp_stmt_fetch.cpp b/src/observer/mysql/obmp_stmt_fetch.cpp index 95bfe35ba0..f5849a7b51 100644 --- a/src/observer/mysql/obmp_stmt_fetch.cpp +++ b/src/observer/mysql/obmp_stmt_fetch.cpp @@ -472,6 +472,12 @@ int ObMPStmtFetch::response_result(pl::ObPLCursorInfo &cursor, } ObPLExecCtx pl_ctx(cursor.get_allocator(), exec_ctx, ¶ms, NULL/*result*/, &ret, NULL/*func*/, true); + ObSchemaGetterGuard schema_guard; + if (OB_SUCC(ret) && need_fetch) { + if (OB_FAIL(gctx_.schema_service_->get_tenant_schema_guard(session.get_effective_tenant_id(), schema_guard))) { + LOG_WARN("get tenant schema guard failed ", K(ret), K(session.get_effective_tenant_id())); + } + } while (OB_SUCC(ret) && need_fetch && row_num < fetch_limit && OB_SUCC(sql::ObSPIService::dbms_cursor_fetch(&pl_ctx, static_cast(cursor)))) { @@ -491,7 +497,7 @@ int ObMPStmtFetch::response_result(pl::ObPLCursorInfo &cursor, OZ (response_row(session, row, fields, column_flag_, cursor_id_, 0 == row_num ? true : false, cursor.is_packed())); } else { - OZ (response_row(session, row, fields, cursor.is_packed())); + OZ (response_row(session, row, fields, cursor.is_packed(), exec_ctx, cursor.is_ps_cursor(), &schema_guard)); } if (OB_SUCC(ret)) { ++row_num; diff --git a/src/observer/mysql/obmp_stmt_fetch.h b/src/observer/mysql/obmp_stmt_fetch.h index 6d131b2489..f7d3283a4e 100644 --- a/src/observer/mysql/obmp_stmt_fetch.h +++ b/src/observer/mysql/obmp_stmt_fetch.h @@ -65,8 +65,11 @@ public: int response_row(sql::ObSQLSessionInfo &session, common::ObNewRow &row, const ColumnsFieldArray *fields, - bool is_packed) { - return ObMPBase::response_row(session, row, fields, is_packed); + bool is_packed, + sql::ObExecContext *exec_ctx = NULL, + bool is_ps_protocol = false, + ObSchemaGetterGuard *schema_guard = NULL) { + return ObMPBase::response_row(session, row, fields, is_packed, exec_ctx, is_ps_protocol, schema_guard); } bool need_close_cursor() { return need_close_cursor_; } void set_close_cursor() { need_close_cursor_ = true; } diff --git a/src/observer/mysql/obsm_utils.cpp b/src/observer/mysql/obsm_utils.cpp index 756d5a5037..5bc7069e28 100644 --- a/src/observer/mysql/obsm_utils.cpp +++ b/src/observer/mysql/obsm_utils.cpp @@ -18,6 +18,10 @@ #include "share/schema/ob_schema_getter_guard.h" #include "share/schema/ob_udt_info.h" #include "pl/ob_pl_user_type.h" +#include "pl/ob_pl_stmt.h" +#ifdef OB_BUILD_ORACLE_PL +#include "pl/sys_package/ob_sdo_geometry.h" +#endif using namespace oceanbase::common; using namespace oceanbase::obmysql; @@ -196,7 +200,21 @@ int ObSMUtils::cell_str( break; } case ObGeometryTC: { - ret = ObMySQLUtil::geometry_cell_str(buf, len, obj.get_string(), pos); + if (lib::is_oracle_mode() && type == MYSQL_PROTOCOL_TYPE::TEXT) { +#ifdef OB_BUILD_ORACLE_PL + common::ObArenaAllocator allocator; + ObStringBuffer geo_str(&allocator); + if (OB_FAIL(pl::ObSdoGeometry::wkb_to_sdo_geometry_text(obj.get_string(), geo_str))) { + OB_LOG(WARN, "wkb to sdo geometry text failed", K(ret)); + } else { + ret = ObMySQLUtil::varchar_cell_str(buf, len, geo_str.string(), is_oracle_raw, pos); + } +#else + ret = OB_NOT_SUPPORTED; +#endif + } else { + ret = ObMySQLUtil::geometry_cell_str(buf, len, obj.get_string(), pos); + } break; } case ObBitTC: { @@ -220,9 +238,29 @@ int ObSMUtils::cell_str( if (OB_ISNULL(field) || OB_ISNULL(schema_guard)) { ret = OB_ERR_UNEXPECTED; OB_LOG(WARN, "complex type need field and schema guard not null", K(ret)); - } else if (BINARY == type && field->type_.get_type() != ObExtendType) { + } else if (BINARY == type && field->type_.get_type() != ObExtendType && + !(field->type_.is_geometry() && lib::is_oracle_mode()) && // oracle gis will cast to extend in ps mode + !field->type_.is_user_defined_sql_type() && + !field->type_.is_collection_sql_type()) { // sql udt will cast to extend in ps mode ret = OB_ERR_UNEXPECTED; OB_LOG(WARN, "field type is not ObExtended", K(ret)); + } else if (field->type_.is_user_defined_sql_type() || field->type_.is_collection_sql_type() + || (field->type_.get_type() == ObExtendType && field->accuracy_.get_accuracy() == T_OBJ_SDO_GEOMETRY)) { + const uint64_t udt_id = field->accuracy_.get_accuracy(); + const uint64_t tenant_id = pl::get_tenant_id_by_object_id(udt_id); + if (OB_FAIL(schema_guard->get_udt_info(tenant_id, udt_id, udt_info))) { + OB_LOG(WARN, "failed to get sys udt info", K(ret), K(field)); + } else if (OB_ISNULL(udt_info)) { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "udt info is null", K(ret)); + } else if (OB_FAIL(udt_info->transform_to_pl_type(allocator, user_type))) { + OB_LOG(WARN, "faild to transform to pl type", K(ret)); + } else if (OB_ISNULL(user_type)) { + ret = OB_ERR_UNEXPECTED; + OB_LOG(WARN, "user type is null", K(ret)); + } else if (OB_FAIL(user_type->serialize(*schema_guard, dtc_params.tz_info_, type, src, buf, len, pos))) { + OB_LOG(WARN, "failed to serialize", K(ret)); + } } else if (field->type_owner_.empty() || field->type_name_.empty()) { if (0 == field->type_name_.case_compare("SYS_REFCURSOR")) { ObPLCursorInfo *cursor = reinterpret_cast(obj.get_int()); @@ -334,8 +372,17 @@ int ObSMUtils::cell_str( } break; } - case ObUserDefinedSQLTC: { - ret = ObMySQLUtil::sql_utd_cell_str(MTL_ID(), buf, len, obj.get_string(), pos); + case ObUserDefinedSQLTC: + case ObCollectionSQLTC: { + if (obj.get_udt_subschema_id() == 0) { // xml + ret = ObMySQLUtil::sql_utd_cell_str(MTL_ID(), buf, len, obj.get_string(), pos); + } else if (type == MYSQL_PROTOCOL_TYPE::TEXT) { // common sql udt text protocal + ret = ObMySQLUtil::varchar_cell_str(buf, len, obj.get_string(), is_oracle_raw, pos); + } else { + // ToDo: sql udt binary protocal (result should be the same as extend type) + ret = OB_NOT_IMPLEMENT; + OB_LOG(WARN, "UDTSQLType binary protocal not implemented", K(ret)); + } break; } case ObDecimalIntTC: { diff --git a/src/observer/virtual_table/ob_information_columns_table.cpp b/src/observer/virtual_table/ob_information_columns_table.cpp index f3712f26c4..34822606cd 100644 --- a/src/observer/virtual_table/ob_information_columns_table.cpp +++ b/src/observer/virtual_table/ob_information_columns_table.cpp @@ -733,7 +733,7 @@ int ObInfoSchemaColumnsTable::fill_row_cells(const ObString &database_name, case COLUMN_TYPE: { int64_t pos = 0; const ObLengthSemantics default_length_semantics = session_->get_local_nls_length_semantics(); - const uint64_t sub_type = column_schema->is_xmltype() ? + const uint64_t sub_type = column_schema->is_extend() ? column_schema->get_sub_data_type() : static_cast(column_schema->get_geo_type()); ObObjType column_type = ObMaxType; const ObColumnSchemaV2 *tmp_column_schema = NULL; diff --git a/src/observer/virtual_table/ob_table_columns.cpp b/src/observer/virtual_table/ob_table_columns.cpp index 464377d76c..09de4dfaf7 100644 --- a/src/observer/virtual_table/ob_table_columns.cpp +++ b/src/observer/virtual_table/ob_table_columns.cpp @@ -826,8 +826,8 @@ int ObTableColumns::deduce_column_attributes( } } else if (result_type.is_user_defined_sql_type()) { sub_type = result_type.get_subschema_id(); - } else if (result_type.get_udt_id() == T_OBJ_XML) { - sub_type = T_OBJ_XML; + } else if ((result_type.get_udt_id() == T_OBJ_XML) || (result_type.get_udt_id() == T_OBJ_SDO_GEOMETRY)) { + sub_type = result_type.get_udt_id(); } if (OB_SUCC(ret) && !skip_type_str) { int64_t pos = 0; diff --git a/src/pl/ob_pl_interface_pragma.h b/src/pl/ob_pl_interface_pragma.h index 31c3bcf4ea..9d0a4d4955 100644 --- a/src/pl/ob_pl_interface_pragma.h +++ b/src/pl/ob_pl_interface_pragma.h @@ -58,6 +58,7 @@ #include "pl/sys_package/ob_dbms_rls.h" #include "pl/sys_package/ob_json_object_type.h" #include "pl/sys_package/ob_json_element_type.h" +#include "pl/sys_package/ob_sdo_geometry.h" #include "pl/sys_package/ob_dbms_mview.h" #include "pl/sys_package/ob_dbms_mview_stats.h" #endif @@ -454,6 +455,17 @@ #undef PREFIX //end of anydata + //start of sdo_geometry + INTERFACE_DEF(INTERFACE_SDO_GEOMETRY_GET_WKB, "SDO_GEOMETRY_GET_WKB", (ObSdoGeometry::get_wkb)) + INTERFACE_DEF(INTERFACE_SDO_GEOMETRY_GET_WKT, "SDO_GEOMETRY_GET_WKT", (ObSdoGeometry::get_wkt)) + INTERFACE_DEF(INTERFACE_SDO_GEOMETRY_GET_GTYPE, "SDO_GEOMETRY_GET_GTYPE", (ObSdoGeometry::get_gtype)) + INTERFACE_DEF(INTERFACE_SDO_GEOMETRY_GET_DIMS, "SDO_GEOMETRY_GET_DIMS", (ObSdoGeometry::get_dims)) + INTERFACE_DEF(INTERFACE_SDO_GEOMETRY_ST_COORDDIM, "SDO_GEOMETRY_ST_COORDDIM", (ObSdoGeometry::st_coorddim)) + INTERFACE_DEF(INTERFACE_SDO_GEOMETRY_ST_ISVALID, "SDO_GEOMETRY_ST_ISVALID", (ObSdoGeometry::st_isvalid)) + INTERFACE_DEF(INTERFACE_SDO_GEOMETRY_CONSTRUCTOR, "SDO_GEOMETRY_CONSTRUCTOR", (ObSdoGeometry::constructor)) + INTERFACE_DEF(INTERFACE_SDO_GEOMETRY_GET_GEOJSON, "SDO_GEOMETRY_GET_GEOJSON", (ObSdoGeometry::get_geojson)) + //end of sdo_geometry + #ifdef OB_BUILD_ORACLE_XML //start of xmltype INTERFACE_DEF(INTERFACE_XML_TYPE_TRANSFORM, "XML_TYPE_TRANSFORM", (ObXmlType::transform)) diff --git a/src/pl/ob_pl_package_manager.cpp b/src/pl/ob_pl_package_manager.cpp index e3174230a4..98858d3251 100644 --- a/src/pl/ob_pl_package_manager.cpp +++ b/src/pl/ob_pl_package_manager.cpp @@ -260,6 +260,7 @@ static ObSysPackageFile oracle_sys_package_file_table[] = { {"json_object_t", "json_object_type.sql", "json_object_type_body.sql"}, {"dbms_mview", "dbms_mview.sql", "dbms_mview_body.sql"}, {"dbms_mview_stats", "dbms_mview_stats.sql", "dbms_mview_stats_body.sql"}, + {"sdo_geometry", "sdo_geometry.sql", "sdo_geometry_body.sql"}, #endif }; diff --git a/src/pl/ob_pl_resolver.cpp b/src/pl/ob_pl_resolver.cpp index 423c424cfa..dab66b8d20 100644 --- a/src/pl/ob_pl_resolver.cpp +++ b/src/pl/ob_pl_resolver.cpp @@ -2534,12 +2534,14 @@ int ObPLResolver::build_record_type_by_table_schema(ObSchemaGetterGuard &schema_ const ObColumnSchemaV2 &column_schema = **cs_iter; if (!column_schema.is_hidden() && !(column_schema.is_invisible_column() && !with_rowid)) { ObPLDataType pl_type; - if (column_schema.get_meta_type().is_user_defined_sql_type()) { + if (column_schema.get_meta_type().is_user_defined_sql_type() + || (lib::is_oracle_mode() && column_schema.get_meta_type().is_geometry())) { // oracle sdo_geometry + uint64_t udt_id = column_schema.get_meta_type().is_geometry() ? ObUDTType::T_OBJ_SDO_GEOMETRY : column_schema.get_sub_data_type(); const ObUDTTypeInfo *udt_info = NULL; const ObUserDefinedType *user_type = NULL; ObArenaAllocator allocator; - uint64_t tenant_id = get_tenant_id_by_object_id(column_schema.get_sub_data_type()); - OZ (schema_guard.get_udt_info(tenant_id, column_schema.get_sub_data_type(), udt_info)); + uint64_t tenant_id = get_tenant_id_by_object_id(udt_id); + OZ (schema_guard.get_udt_info(tenant_id, udt_id, udt_info)); CK (OB_NOT_NULL(udt_info)); OZ (udt_info->transform_to_pl_type(allocator, user_type)); CK (OB_NOT_NULL(user_type)); @@ -11817,7 +11819,9 @@ int ObPLResolver::resolve_qualified_name(ObQualifiedName &q_name, //"case a when b xx when c xx" to "case when a == b then xx case when a == c then xx" if (OB_SUCC(ret)) { bool transformed = false; - OZ (formalize_expr(*expr)); + if (!ObObjUDTUtil::ob_is_supported_sql_udt(expr->get_result_type().get_udt_id())) { + OZ (formalize_expr(*expr)); // bugfix: 53193337, need get real type in that case + } OZ(ObTransformPreProcess::transform_expr(unit_ast.get_expr_factory(), resolve_ctx_.session_info_, expr, transformed)); @@ -13890,9 +13894,11 @@ int ObPLResolver::check_routine_callable(const ObPLBlockNS &ns, if (OB_FAIL(expr_params.at(0)->clear_flag(IS_UDT_UDF_SELF_PARAM))) { LOG_WARN("failed to clear flag", K(ret)); } - } else if (expr_params.count() > 0 - && expr_params.at(0)->get_result_type().is_xml_sql_type() - && (T_OBJ_XML == access_idxs.at(access_idxs.count() - 1).var_index_)) { + } else if (expr_params.count() > 0 && + ((expr_params.at(0)->get_result_type().is_xml_sql_type() && + T_OBJ_XML == access_idxs.at(access_idxs.count() - 1).var_index_) || + (expr_params.at(0)->get_result_type().is_geometry() && + T_OBJ_SDO_GEOMETRY == access_idxs.at(access_idxs.count() - 1).var_index_))) { // select 'head' || xmlparse(document '123').getclobval() into a from dual; if (OB_FAIL(expr_params.at(0)->clear_flag(IS_UDT_UDF_SELF_PARAM))) { LOG_WARN("failed to clear flag", K(ret)); @@ -14337,15 +14343,30 @@ int ObPLResolver::resolve_sys_func_access(ObObjAccessIdent &access_ident, LOG_WARN("deduce type failed for sys func ident", K(ret)); } } + uint64_t udt_id = 0; if (OB_FAIL(ret)) { - } else if (!access_ident.sys_func_expr_->get_result_type().is_xml_sql_type() - && !(access_ident.sys_func_expr_->get_result_type().is_ext())) { + } else if (access_ident.sys_func_expr_->get_result_type().is_user_defined_sql_type()) { + uint16_t subschema_id = access_ident.sys_func_expr_->get_result_type().get_subschema_id(); + if (subschema_id == ObXMLSqlType) { + udt_id = T_OBJ_XML; + } else { + udt_id = access_ident.sys_func_expr_->get_result_type().get_udt_id(); + } + } else if (access_ident.sys_func_expr_->get_result_type().is_ext()) { + udt_id = access_ident.sys_func_expr_->get_result_type().get_udt_id(); + } else if (access_ident.sys_func_expr_->get_result_type().is_geometry() && lib::is_oracle_mode()) { + // oracle gis + udt_id = T_OBJ_SDO_GEOMETRY; + } + + if (OB_FAIL(ret)) { + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_id) + && !(access_ident.sys_func_expr_->get_result_type().is_ext())) { ret = OB_ERR_NOT_OBJ_REF; LOG_WARN("unsupported sys func ident", - K(ret), K(access_ident), K(access_ident.sys_func_expr_->get_result_type()), - K(access_ident.sys_func_expr_->get_result_type().get_udt_id())); - } else { // only xmltype is supported - OZ (ns.get_pl_data_type_by_id(T_OBJ_XML, user_type)); + K(ret), K(access_ident), K(access_ident.sys_func_expr_->get_result_type()), K(udt_id)); + } else { + OZ (ns.get_pl_data_type_by_id(udt_id, user_type)); } } CK (OB_NOT_NULL(user_type)); diff --git a/src/pl/ob_pl_resolver.h b/src/pl/ob_pl_resolver.h index ce8a322a05..1fcee1b048 100644 --- a/src/pl/ob_pl_resolver.h +++ b/src/pl/ob_pl_resolver.h @@ -610,6 +610,9 @@ public: ObRawExprFactory &expr_factory, ObRawExpr *&expr, ObPLCompileUnitAST &unit_ast); + static int replace_udf_param_expr(ObObjAccessIdent &access_ident, + ObIArray &columns, + ObIArray &real_exprs); private: int resolve_declare_var(const ObStmtNodeTree *parse_tree, ObPLDeclareVarStmt *stmt, ObPLFunctionAST &func_ast); int resolve_declare_var(const ObStmtNodeTree *parse_tree, ObPLPackageAST &package_ast); @@ -921,7 +924,6 @@ private: ObPLForAllStmt *stmt, ObPLFunctionAST &func, ObIArray &access_idxs); - private: int check_duplicate_condition(const ObPLDeclareHandlerStmt &stmt, const ObPLConditionValue &value, bool &dup, ObPLDeclareHandlerStmt::DeclareHandler::HandlerDesc* cur_desc); @@ -1113,9 +1115,6 @@ private: int replace_udf_param_expr(ObQualifiedName &q_name, ObIArray &columns, ObIArray &real_exprs); - int replace_udf_param_expr(ObObjAccessIdent &access_ident, - ObIArray &columns, - ObIArray &real_exprs); int get_names_by_access_ident(ObObjAccessIdent &access_ident, ObIArray &access_idxs, ObString &database_name, diff --git a/src/pl/ob_pl_user_type.cpp b/src/pl/ob_pl_user_type.cpp index 94d2f8e0a5..3660126362 100644 --- a/src/pl/ob_pl_user_type.cpp +++ b/src/pl/ob_pl_user_type.cpp @@ -700,12 +700,14 @@ int ObUserDefinedType::text_protocol_suffix_info_for_each_item(const ObPLDataTyp if (len - pos < 3) { ret = OB_SIZE_OVERFLOW; LOG_WARN("buffer length is not enough. ", K(type_name_), K(type_name_.length()), K(len)); - } else if (is_last_item) { + } else if (!is_null) { MEMCPY(buf + pos, ")", 1); pos += 1; - } else { - MEMCPY(buf + pos, "), ", 3); - pos += 3; + } + + if (OB_SUCC(ret) && !is_last_item) { + MEMCPY(buf + pos, ", ", 2); + pos += 2; } } else if (!is_null && NULL != type.get_meta_type() && (type.get_meta_type()->is_string_or_lob_locator_type() || type.get_meta_type()->is_oracle_temporal_type() diff --git a/src/pl/sys_package/ob_json_pl_utils.h b/src/pl/sys_package/ob_json_pl_utils.h index deb8f8fedd..454ea59e7b 100644 --- a/src/pl/sys_package/ob_json_pl_utils.h +++ b/src/pl/sys_package/ob_json_pl_utils.h @@ -71,6 +71,8 @@ public: static bool is_pl_json_object_type(int64_t id) { return (id == JSN_PL_OBJECT_TYPE_ID); } static bool is_pl_json_array_type(int64_t id) { return (id == JSN_PL_ARRAY_TYPE_ID); } + static int str_to_lob_storage_obj(ObIAllocator &allocator, const ObString& input, common::ObObj& output); + static int get_lob_inner(ObIAllocator& allocator, const ObString& val_str, ObPlJsonUtil::PL_JSN_STRING_TYPE type, ObIJsonBase*& j_base); }; diff --git a/src/rootserver/ob_ddl_service.cpp b/src/rootserver/ob_ddl_service.cpp index 65d1b6acc4..53c8811d1d 100755 --- a/src/rootserver/ob_ddl_service.cpp +++ b/src/rootserver/ob_ddl_service.cpp @@ -7528,12 +7528,16 @@ int ObDDLService::resolve_timestamp_column(AlterColumnSchema *alter_column_schem ObIAllocator &allocator) { int ret = OB_SUCCESS; + bool is_oracle_mode = false; if (OB_ISNULL(alter_column_schema)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("alter_column_schema is NULL", K(ret)); + } else if (OB_FAIL(new_table_schema.check_if_oracle_compat_mode(is_oracle_mode))) { + LOG_WARN("fail to check if tenant mode is oracle mode", K(ret)); } else if (ObTimestampType != new_column_schema.get_data_type() || new_column_schema.is_generated_column() - || false == alter_column_schema->check_timestamp_column_order_) { + || false == alter_column_schema->check_timestamp_column_order_ + || new_column_schema.is_udt_related_column(is_oracle_mode)) { //nothing to do } else { bool is_first_timestamp = false; @@ -9182,6 +9186,7 @@ int ObDDLService::add_new_column_to_table_schema( AlterColumnSchema &alter_column_schema, ObIArray &gen_col_expr_arr, ObSchemaGetterGuard &schema_guard, + uint64_t &curr_udt_set_id, ObDDLOperator *ddl_operator, common::ObMySQLTransaction *trans) { @@ -9220,9 +9225,9 @@ int ObDDLService::add_new_column_to_table_schema( } else { if (alter_column_schema.is_udt_hidden_column()) { // udt hidden column - char col_name[128] = {0}; - alter_column_schema.set_udt_set_id(max_used_column_id); - databuff_printf(col_name, 128, "SYS_NC%05lu$",max_used_column_id + 1); + char col_name[OB_MAX_COLUMN_NAME_LENGTH] = {0}; + alter_column_schema.set_udt_set_id(curr_udt_set_id); + databuff_printf(col_name, OB_MAX_COLUMN_NAME_LENGTH, "SYS_NC%05lu$",max_used_column_id + 1); if (OB_FAIL(alter_column_schema.set_column_name(col_name))) { SQL_RESV_LOG(WARN, "failed to set column name", K(ret)); } @@ -9240,6 +9245,7 @@ int ObDDLService::add_new_column_to_table_schema( } if (alter_column_schema.is_xmltype()) { alter_column_schema.set_udt_set_id(alter_column_schema.get_column_id()); + curr_udt_set_id = alter_column_schema.get_udt_set_id(); } new_table_schema.set_max_used_column_id(max_used_column_id); } @@ -9269,10 +9275,10 @@ int ObDDLService::add_new_column_to_table_schema( ObSchemaChecker schema_checker; if (OB_FAIL(schema_checker.init(schema_guard))) { LOG_WARN("failed to init schema guard", K(ret)); - } else if (alter_column_schema.is_udt_related_column()) { - // 1. xmltype cannot be primary key - // 2. xmltype column and its hidden blob column default value is calc/set in resolver - // only check xmltype schema version on rs in check_parallel_ddl_conflict + } else if (alter_column_schema.is_udt_related_column(is_oracle_mode)) { + // udt column/oracle gis not need to do the flowing else ifs: + // 1. default values is check and calculated in resolver, only check dependency version on RS + // 2. udt column and it's hidden columns cannot be primary key LOG_INFO("alter table add udt related column", K(alter_column_schema)); } else if (OB_FAIL(ObDDLResolver::check_default_value( alter_column_schema.get_cur_default_value(), @@ -9489,6 +9495,7 @@ int ObDDLService::gen_alter_column_new_table_schema_offline( // drop column related. int64_t new_table_cols_cnt = 0; ObArray drop_cols_id_arr; + uint64_t curr_udt_set_id = 0; bool is_oracle_mode = false; LOG_DEBUG("check before alter table column", K(origin_table_schema), K(alter_table_schema), K(new_table_schema)); ObSchemaChecker schema_checker; @@ -9598,6 +9605,7 @@ int ObDDLService::gen_alter_column_new_table_schema_offline( *alter_column_schema, gen_col_expr_arr, schema_guard, + curr_udt_set_id, nullptr, nullptr))) { LOG_WARN("failed to add new column to table schema", K(ret)); @@ -9959,6 +9967,7 @@ int ObDDLService::alter_table_column(const ObTableSchema &origin_table_schema, ObArray idx_schema_array; common::hash::ObHashSet update_column_name_set; ObSEArray gen_col_expr_arr; + uint64_t curr_udt_set_id = 0; bool is_origin_table_has_lob_column = false; if (OB_FAIL(update_column_name_set.create(32))) { LOG_WARN("failed to create update column name set", K(ret)); @@ -10023,6 +10032,7 @@ int ObDDLService::alter_table_column(const ObTableSchema &origin_table_schema, *alter_column_schema, gen_col_expr_arr, schema_guard, + curr_udt_set_id, &ddl_operator, &trans))) { LOG_WARN("failed to add new column to table schema", K(ret)); @@ -10099,6 +10109,7 @@ int ObDDLService::alter_table_column(const ObTableSchema &origin_table_schema, update_column_name_set))) { RS_LOG(WARN, "failed to pre check orig column schema", K(ret)); } else if (!alter_column_schema->is_generated_column() /* Not support modify to generate columns, so there is no need to check again here */ + && !alter_column_schema->is_udt_related_column(is_oracle_mode) /* udt default values are checked in resolver */ && OB_FAIL(ObDDLResolver::check_default_value(alter_column_schema->get_cur_default_value(), tz_info_wrap, nls_formats, diff --git a/src/rootserver/ob_ddl_service.h b/src/rootserver/ob_ddl_service.h index a5ec4594ce..00c4e12481 100644 --- a/src/rootserver/ob_ddl_service.h +++ b/src/rootserver/ob_ddl_service.h @@ -353,6 +353,7 @@ public: share::schema::AlterColumnSchema &alter_column_schema, ObIArray &gen_col_expr_arr, share::schema::ObSchemaGetterGuard &schema_guard, + uint64_t &curr_udt_set_id, ObDDLOperator *ddl_operator, common::ObMySQLTransaction *trans); int add_column_to_column_group( diff --git a/src/rootserver/ob_mlog_builder.cpp b/src/rootserver/ob_mlog_builder.cpp index 50765af0ec..a2ac06f018 100644 --- a/src/rootserver/ob_mlog_builder.cpp +++ b/src/rootserver/ob_mlog_builder.cpp @@ -76,7 +76,7 @@ int ObMLogBuilder::MLogColumnUtils::check_column_type( LOG_USER_ERROR(OB_NOT_SUPPORTED, "create materialized view log on geometry columns is"); LOG_WARN("create materialized view log on geometry columns is not supported", KR(ret), K(column_schema.get_column_name_str())); - } else if (column_schema.is_udt_related_column()) { + } else if (column_schema.is_udt_related_column(lib::is_oracle_mode())) { ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "create materialized view log on udt columns is"); LOG_WARN("create materialized view log on udt columns is not supported", diff --git a/src/share/datum/ob_datum.cpp b/src/share/datum/ob_datum.cpp index 16c0916675..199c4b511d 100644 --- a/src/share/datum/ob_datum.cpp +++ b/src/share/datum/ob_datum.cpp @@ -75,6 +75,7 @@ ObObjDatumMapType ObDatum::get_obj_datum_map_type(const ObObjType type) OBJ_DATUM_STRING, // ObGeometryType OBJ_DATUM_STRING, // ObUserDefinedSQLType OBJ_DATUM_DECIMALINT, // ObDecimalIntType + OBJ_DATUM_STRING, // ObCollectionSQLType }; static_assert(sizeof(maps) / sizeof(maps[0]) == ObMaxType, "new added type should extend this map"); diff --git a/src/share/datum/ob_datum.h b/src/share/datum/ob_datum.h index 2e7ab90189..e86ff95d59 100644 --- a/src/share/datum/ob_datum.h +++ b/src/share/datum/ob_datum.h @@ -863,7 +863,8 @@ inline int ObDatum::from_obj(const ObObj &obj) case ObLobType: case ObJsonType: case ObGeometryType: - case ObUserDefinedSQLType: { + case ObUserDefinedSQLType: + case ObCollectionSQLType: { obj2datum(obj); break; } @@ -1008,7 +1009,8 @@ inline int ObDatum::to_obj(ObObj &obj, const ObObjMeta &meta) const case ObLobType: case ObJsonType: case ObGeometryType: - case ObUserDefinedSQLType: { + case ObUserDefinedSQLType: + case ObCollectionSQLType: { datum2obj(obj); break; } diff --git a/src/share/datum/ob_datum_funcs.cpp b/src/share/datum/ob_datum_funcs.cpp index 9e4b65d494..7c1aeb9df3 100644 --- a/src/share/datum/ob_datum_funcs.cpp +++ b/src/share/datum/ob_datum_funcs.cpp @@ -552,32 +552,12 @@ struct DatumGeoHashCalculator : public DefHashMethod { static int calc_datum_hash(const ObDatum &datum, const uint64_t seed, uint64_t &res) { - int ret = OB_SUCCESS; - common::ObString wkb; - res = 0; - common::ObArenaAllocator allocator(ObModIds::OB_LOB_READER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); - ObTextStringIter str_iter(ObJsonType, CS_TYPE_BINARY, datum.get_string(), HAS_LOB_HEADER); - if (datum.is_null()) { - res = seed; - } else if (OB_FAIL(str_iter.init(0, NULL, &allocator))) { - LOG_WARN("Lob: str iter init failed ", K(ret), K(str_iter)); - } else if (OB_FAIL(str_iter.get_full_data(wkb))) { - LOG_WARN("Lob: str iter get full data failed ", K(ret), K(str_iter)); - } else { - ret = ObjHashCalculator::calc_hash_value(datum, seed, res); - } - return ret; + return datum_lob_locator_hash(datum, CS_TYPE_UTF8MB4_BIN, seed, T::is_varchar_hash ? T::hash : NULL, res); } static int calc_datum_hash_v2(const ObDatum &datum, const uint64_t seed, uint64_t &res) { - int ret = OB_SUCCESS; - if (datum.is_null()) { - res = seed; - } else { - ret = calc_datum_hash(datum, seed, res); - } - return ret; + return datum_lob_locator_hash(datum, CS_TYPE_UTF8MB4_BIN, seed, T::is_varchar_hash ? T::hash : NULL, res); } }; @@ -1266,6 +1246,8 @@ ObExprBasicFuncs* ObDatumFuncs::get_basic_func(const ObObjType type, res = &EXPR_BASIC_GEO_FUNCS[has_lob_locator]; } else if (ob_is_user_defined_sql_type(type)) { res = &EXPR_BASIC_UDT_FUNCS[0]; + } else if (ob_is_collection_sql_type(type)) { + res = &EXPR_BASIC_STR_FUNCS[cs_type][false][has_lob_locator]; } else if (!is_oracle_mode && ob_is_double_type(type) && scale > SCALE_UNKNOWN_YET && scale < OB_NOT_FIXED_SCALE) { res = &FIXED_DOUBLE_BASIC_FUNCS[scale]; diff --git a/src/share/inner_table/ob_inner_table_schema.25001_25050.cpp b/src/share/inner_table/ob_inner_table_schema.25001_25050.cpp index d2f778b94f..09b048e20c 100644 --- a/src/share/inner_table/ob_inner_table_schema.25001_25050.cpp +++ b/src/share/inner_table/ob_inner_table_schema.25001_25050.cpp @@ -910,7 +910,7 @@ int ObInnerTableSchema::all_tab_cols_v_schema(ObTableSchema &table_schema) table_schema.set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); if (OB_SUCC(ret)) { - if (OB_FAIL(table_schema.set_view_definition(R"__( SELECT CAST(DB.DATABASE_NAME AS VARCHAR2(128)) AS OWNER, CAST(TC.TABLE_NAME AS VARCHAR2(128)) AS TABLE_NAME, CAST(TC.COLUMN_NAME AS VARCHAR2(128)) AS COLUMN_NAME, CAST(DECODE(TC.DATA_TYPE, 0, 'VARCHAR2', 1, 'NUMBER', 2, 'NUMBER', 3, 'NUMBER', 4, 'NUMBER', 5, 'NUMBER', 6, 'NUMBER', 7, 'NUMBER', 8, 'NUMBER', 9, 'NUMBER', 10, 'NUMBER', 11, 'BINARY_FLOAT', 12, 'BINARY_DOUBLE', 13, 'NUMBER', 14, 'NUMBER', 15, 'NUMBER', 16, 'NUMBER', 17, 'DATE', 18, 'TIMESTAMP', 19, 'DATE', 20, 'TIME', 21, 'YEAR', 22, 'VARCHAR2', 23, 'CHAR', 24, 'HEX_STRING', 25, 'UNDEFINED', 26, 'UNKNOWN', 27, 'TINYTEXT', 28, 'TEXT', 29, 'MEDIUMTEXT', 30, DECODE(TC.COLLATION_TYPE, 63, 'BLOB', 'CLOB'), 31, 'BIT', 32, 'ENUM', 33, 'SET', 34, 'ENUM_INNER', 35, 'SET_INNER', 36, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH TIME ZONE')), 37, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH LOCAL TIME ZONE')), 38, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ')')), 39, 'RAW', 40, CONCAT('INTERVAL YEAR(', CONCAT(TC.DATA_SCALE, ') TO MONTH')), 41, CONCAT('INTERVAL DAY(', CONCAT(TRUNC(TC.DATA_SCALE/10), CONCAT(') TO SECOND(', CONCAT(MOD(TC.DATA_SCALE, 10), ')')))), 42, 'FLOAT', 43, 'NVARCHAR2', 44, 'NCHAR', 45, 'UROWID', 46, 'LOB', 47, 'JSON', 48, 'GEOMETRY', 49, DECODE(TC.SUB_DATA_TYPE, 300001, 'XMLTYPE', 'UDT'), 50, 'NUMBER', 'UNDEFINED') AS VARCHAR2(128)) AS DATA_TYPE, CAST(NULL AS VARCHAR2(3)) AS DATA_TYPE_MOD, CAST(NULL AS VARCHAR2(128)) AS DATA_TYPE_OWNER, CAST(CASE WHEN TC.DATA_TYPE in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 42, 50) THEN 22 WHEN TC.DATA_TYPE = 11 THEN 4 WHEN TC.DATA_TYPE = 12 THEN 8 WHEN TC.DATA_TYPE in (17, 19) THEN 7 WHEN TC.DATA_TYPE in (18, 37, 38) THEN CASE WHEN TC.DATA_SCALE = 0 THEN 7 ELSE 11 END WHEN TC.DATA_TYPE = 41 THEN 11 WHEN TC.DATA_TYPE = 40 THEN 5 WHEN TC.DATA_TYPE = 30 THEN 4000 WHEN TC.DATA_TYPE = 36 THEN 13 WHEN TC.DATA_TYPE IN (0,22,43,46) AND TC.DATA_PRECISION = 1 THEN LEAST(32767, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE IN (23,44) AND TC.DATA_PRECISION = 1 THEN LEAST(2000, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) ELSE TC.DATA_LENGTH END AS NUMBER) AS DATA_LENGTH, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,18,19,22,23,27,28,29,30,36,37,38,43,44) THEN NULL ELSE CASE WHEN TC.DATA_PRECISION < 0 THEN NULL ELSE TC.DATA_PRECISION END END AS NUMBER) AS DATA_PRECISION, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,19,22,23,27,28,29,30,42,43,44) THEN NULL ELSE CASE WHEN TC.DATA_SCALE < -84 THEN NULL ELSE TC.DATA_SCALE END END AS NUMBER) AS DATA_SCALE, CAST(DECODE(TC.NULLABLE, 0, 'N', DECODE(BITAND(TC.COLUMN_FLAGS, 5 * POWER(2, 13)), 5 * POWER(2, 13), 'N', 'Y')) AS VARCHAR2(1)) AS NULLABLE, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, TC.COLUMN_ID, NULL) AS NUMBER) AS COLUMN_ID, CAST(LENGTHB(TC.CUR_DEFAULT_VALUE_V2) AS NUMBER) AS DEFAULT_LENGTH, CAST(TC.CUR_DEFAULT_VALUE_V2 AS /* TODO: LONG() */ VARCHAR(32767)) AS DATA_DEFAULT, CAST(STAT.DISTINCT_CNT AS NUMBER) AS NUM_DISTINCT, CAST(STAT.MIN_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS LOW_VALUE, CAST(STAT.MAX_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS HIGH_VALUE, CAST(STAT.DENSITY AS NUMBER) AS DENSITY, CAST(STAT.NULL_CNT AS NUMBER) AS NUM_NULLS, CAST(STAT.BUCKET_CNT AS NUMBER) AS NUM_BUCKETS, CAST(STAT.LAST_ANALYZED AS DATE) AS LAST_ANALYZED, CAST(STAT.SAMPLE_SIZE AS NUMBER) AS SAMPLE_SIZE, CAST(DECODE(TC.DATA_TYPE, 22, 'CHAR_CS', 23, 'CHAR_CS', 30, DECODE(TC.COLLATION_TYPE, 63, 'NULL', 'CHAR_CS'), 43, 'NCHAR_CS', 44, 'NCHAR_CS', '') AS VARCHAR2(44)) AS CHARACTER_SET_NAME, CAST(NULL AS NUMBER) AS CHAR_COL_DECL_LENGTH, CAST(DECODE(STAT.GLOBAL_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS GLOBAL_STATS, CAST(DECODE(STAT.USER_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS USER_STATS, CAST(NULL AS VARCHAR2(80)) AS NOTES, CAST(STAT.AVG_LEN AS NUMBER) AS AVG_COL_LEN, CAST(CASE WHEN TC.DATA_TYPE IN (22,23,43,44) THEN TC.DATA_LENGTH ELSE 0 END AS NUMBER) AS CHAR_LENGTH, CAST(DECODE(TC.DATA_TYPE, 22, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 23, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 43, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 44, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), NULL) AS VARCHAR2(1)) AS CHAR_USED, CAST(NULL AS VARCHAR2(3)) AS V80_FMT_IMAGE, CAST(NULL AS VARCHAR2(3)) AS DATA_UPGRADED, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, 'NO', 'YES') AS VARCHAR2(3)) AS HIDDEN_COLUMN, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 1), 1, 'YES', 'NO') AS VARCHAR2(3)) AS VIRTUAL_COLUMN, CAST(NULL AS NUMBER) AS SEGMENT_COLUMN_ID, CAST(NULL AS NUMBER) AS INTERNAL_COLUMN_ID, CAST((CASE WHEN STAT.HISTOGRAM_TYPE = 1 THEN 'FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 3 THEN 'TOP-FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 4 THEN 'HYBRID' ELSE NULL END) AS VARCHAR2(15)) AS HISTOGRAM, CAST(TC.COLUMN_NAME AS VARCHAR2(4000)) AS QUALIFIED_COL_NAME, CAST('YES' AS VARCHAR2(3)) AS USER_GENERATED, CAST(NULL AS VARCHAR2(3)) AS DEFAULT_ON_NULL, CAST(NULL AS VARCHAR2(3)) AS IDENTITY_COLUMN, CAST(NULL AS VARCHAR2(128)) AS EVALUATION_EDITION, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEFORE, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEGINNING, CAST(NULL AS VARCHAR2(100)) AS COLLATION, CAST(NULL AS NUMBER) AS COLLATED_COLUMN_ID FROM (SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_CORE_ALL_TABLE T, SYS.ALL_VIRTUAL_CORE_COLUMN_TABLE C WHERE C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0 UNION ALL SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_TABLE_REAL_AGENT T, SYS.ALL_VIRTUAL_COLUMN_REAL_AGENT C WHERE T.TENANT_ID = EFFECTIVE_TENANT_ID() AND C.TENANT_ID = EFFECTIVE_TENANT_ID() AND T.TABLE_TYPE IN (0,1,3,4,5,7,8,9,14,15) AND bitand((T.TABLE_MODE / 4096), 15) IN (0,1) AND C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0) TC JOIN SYS.ALL_VIRTUAL_DATABASE_REAL_AGENT DB ON DB.TENANT_ID = TC.TENANT_ID AND DB.DATABASE_ID = TC.DATABASE_ID AND DB.TENANT_ID = EFFECTIVE_TENANT_ID() AND (TC.DATABASE_ID = USERENV('SCHEMAID') OR USER_CAN_ACCESS_OBJ(1, TC.TABLE_ID, TC.DATABASE_ID) = 1) LEFT JOIN SYS.ALL_VIRTUAL_COLUMN_STAT_REAL_AGENT STAT ON TC.TENANT_ID = STAT.TENANT_ID AND TC.TABLE_ID = STAT.TABLE_ID AND TC.COLUMN_ID = STAT.COLUMN_ID AND STAT.OBJECT_TYPE = 1 AND STAT.TENANT_ID = EFFECTIVE_TENANT_ID() )__"))) { + if (OB_FAIL(table_schema.set_view_definition(R"__( SELECT CAST(DB.DATABASE_NAME AS VARCHAR2(128)) AS OWNER, CAST(TC.TABLE_NAME AS VARCHAR2(128)) AS TABLE_NAME, CAST(TC.COLUMN_NAME AS VARCHAR2(128)) AS COLUMN_NAME, CAST(DECODE(TC.DATA_TYPE, 0, 'VARCHAR2', 1, 'NUMBER', 2, 'NUMBER', 3, 'NUMBER', 4, 'NUMBER', 5, 'NUMBER', 6, 'NUMBER', 7, 'NUMBER', 8, 'NUMBER', 9, 'NUMBER', 10, 'NUMBER', 11, 'BINARY_FLOAT', 12, 'BINARY_DOUBLE', 13, 'NUMBER', 14, 'NUMBER', 15, 'NUMBER', 16, 'NUMBER', 17, 'DATE', 18, 'TIMESTAMP', 19, 'DATE', 20, 'TIME', 21, 'YEAR', 22, 'VARCHAR2', 23, 'CHAR', 24, 'HEX_STRING', 25, 'UNDEFINED', 26, 'UNKNOWN', 27, 'TINYTEXT', 28, 'TEXT', 29, 'MEDIUMTEXT', 30, DECODE(TC.COLLATION_TYPE, 63, 'BLOB', 'CLOB'), 31, 'BIT', 32, 'ENUM', 33, 'SET', 34, 'ENUM_INNER', 35, 'SET_INNER', 36, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH TIME ZONE')), 37, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH LOCAL TIME ZONE')), 38, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ')')), 39, 'RAW', 40, CONCAT('INTERVAL YEAR(', CONCAT(TC.DATA_SCALE, ') TO MONTH')), 41, CONCAT('INTERVAL DAY(', CONCAT(TRUNC(TC.DATA_SCALE/10), CONCAT(') TO SECOND(', CONCAT(MOD(TC.DATA_SCALE, 10), ')')))), 42, 'FLOAT', 43, 'NVARCHAR2', 44, 'NCHAR', 45, 'UROWID', 46, 'LOB', 47, 'JSON', 48, 'SDO_GEOMETRY', 49, DECODE(TC.SUB_DATA_TYPE, 300001, 'XMLTYPE', 'UDT'), 50, 'NUMBER', 'UNDEFINED') AS VARCHAR2(128)) AS DATA_TYPE, CAST(NULL AS VARCHAR2(3)) AS DATA_TYPE_MOD, CAST(NULL AS VARCHAR2(128)) AS DATA_TYPE_OWNER, CAST(CASE WHEN TC.DATA_TYPE in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 42, 50) THEN 22 WHEN TC.DATA_TYPE = 11 THEN 4 WHEN TC.DATA_TYPE = 12 THEN 8 WHEN TC.DATA_TYPE in (17, 19) THEN 7 WHEN TC.DATA_TYPE in (18, 37, 38) THEN CASE WHEN TC.DATA_SCALE = 0 THEN 7 ELSE 11 END WHEN TC.DATA_TYPE = 41 THEN 11 WHEN TC.DATA_TYPE = 40 THEN 5 WHEN TC.DATA_TYPE = 30 THEN 4000 WHEN TC.DATA_TYPE = 36 THEN 13 WHEN TC.DATA_TYPE IN (0,22,43,46) AND TC.DATA_PRECISION = 1 THEN LEAST(32767, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE IN (23,44) AND TC.DATA_PRECISION = 1 THEN LEAST(2000, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE = 48 THEN 1 ELSE TC.DATA_LENGTH END AS NUMBER) AS DATA_LENGTH, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,18,19,22,23,27,28,29,30,36,37,38,43,44) THEN NULL ELSE CASE WHEN TC.DATA_PRECISION < 0 THEN NULL ELSE TC.DATA_PRECISION END END AS NUMBER) AS DATA_PRECISION, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,19,22,23,27,28,29,30,42,43,44) THEN NULL ELSE CASE WHEN TC.DATA_SCALE < -84 THEN NULL ELSE TC.DATA_SCALE END END AS NUMBER) AS DATA_SCALE, CAST(DECODE(TC.NULLABLE, 0, 'N', DECODE(BITAND(TC.COLUMN_FLAGS, 5 * POWER(2, 13)), 5 * POWER(2, 13), 'N', 'Y')) AS VARCHAR2(1)) AS NULLABLE, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, TC.COLUMN_ID, NULL) AS NUMBER) AS COLUMN_ID, CAST(LENGTHB(TC.CUR_DEFAULT_VALUE_V2) AS NUMBER) AS DEFAULT_LENGTH, CAST(TC.CUR_DEFAULT_VALUE_V2 AS /* TODO: LONG() */ VARCHAR(32767)) AS DATA_DEFAULT, CAST(STAT.DISTINCT_CNT AS NUMBER) AS NUM_DISTINCT, CAST(STAT.MIN_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS LOW_VALUE, CAST(STAT.MAX_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS HIGH_VALUE, CAST(STAT.DENSITY AS NUMBER) AS DENSITY, CAST(STAT.NULL_CNT AS NUMBER) AS NUM_NULLS, CAST(STAT.BUCKET_CNT AS NUMBER) AS NUM_BUCKETS, CAST(STAT.LAST_ANALYZED AS DATE) AS LAST_ANALYZED, CAST(STAT.SAMPLE_SIZE AS NUMBER) AS SAMPLE_SIZE, CAST(DECODE(TC.DATA_TYPE, 22, 'CHAR_CS', 23, 'CHAR_CS', 30, DECODE(TC.COLLATION_TYPE, 63, 'NULL', 'CHAR_CS'), 43, 'NCHAR_CS', 44, 'NCHAR_CS', '') AS VARCHAR2(44)) AS CHARACTER_SET_NAME, CAST(NULL AS NUMBER) AS CHAR_COL_DECL_LENGTH, CAST(DECODE(STAT.GLOBAL_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS GLOBAL_STATS, CAST(DECODE(STAT.USER_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS USER_STATS, CAST(NULL AS VARCHAR2(80)) AS NOTES, CAST(STAT.AVG_LEN AS NUMBER) AS AVG_COL_LEN, CAST(CASE WHEN TC.DATA_TYPE IN (22,23,43,44) THEN TC.DATA_LENGTH ELSE 0 END AS NUMBER) AS CHAR_LENGTH, CAST(DECODE(TC.DATA_TYPE, 22, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 23, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 43, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 44, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), NULL) AS VARCHAR2(1)) AS CHAR_USED, CAST(NULL AS VARCHAR2(3)) AS V80_FMT_IMAGE, CAST(NULL AS VARCHAR2(3)) AS DATA_UPGRADED, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, 'NO', 'YES') AS VARCHAR2(3)) AS HIDDEN_COLUMN, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 1), 1, 'YES', 'NO') AS VARCHAR2(3)) AS VIRTUAL_COLUMN, CAST(NULL AS NUMBER) AS SEGMENT_COLUMN_ID, CAST(NULL AS NUMBER) AS INTERNAL_COLUMN_ID, CAST((CASE WHEN STAT.HISTOGRAM_TYPE = 1 THEN 'FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 3 THEN 'TOP-FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 4 THEN 'HYBRID' ELSE NULL END) AS VARCHAR2(15)) AS HISTOGRAM, CAST(TC.COLUMN_NAME AS VARCHAR2(4000)) AS QUALIFIED_COL_NAME, CAST('YES' AS VARCHAR2(3)) AS USER_GENERATED, CAST(NULL AS VARCHAR2(3)) AS DEFAULT_ON_NULL, CAST(NULL AS VARCHAR2(3)) AS IDENTITY_COLUMN, CAST(NULL AS VARCHAR2(128)) AS EVALUATION_EDITION, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEFORE, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEGINNING, CAST(NULL AS VARCHAR2(100)) AS COLLATION, CAST(NULL AS NUMBER) AS COLLATED_COLUMN_ID FROM (SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_CORE_ALL_TABLE T, SYS.ALL_VIRTUAL_CORE_COLUMN_TABLE C WHERE C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0 UNION ALL SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_TABLE_REAL_AGENT T, SYS.ALL_VIRTUAL_COLUMN_REAL_AGENT C WHERE T.TENANT_ID = EFFECTIVE_TENANT_ID() AND C.TENANT_ID = EFFECTIVE_TENANT_ID() AND T.TABLE_TYPE IN (0,1,3,4,5,7,8,9,14,15) AND bitand((T.TABLE_MODE / 4096), 15) IN (0,1) AND C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0) TC JOIN SYS.ALL_VIRTUAL_DATABASE_REAL_AGENT DB ON DB.TENANT_ID = TC.TENANT_ID AND DB.DATABASE_ID = TC.DATABASE_ID AND DB.TENANT_ID = EFFECTIVE_TENANT_ID() AND (TC.DATABASE_ID = USERENV('SCHEMAID') OR USER_CAN_ACCESS_OBJ(1, TC.TABLE_ID, TC.DATABASE_ID) = 1) LEFT JOIN SYS.ALL_VIRTUAL_COLUMN_STAT_REAL_AGENT STAT ON TC.TENANT_ID = STAT.TENANT_ID AND TC.TABLE_ID = STAT.TABLE_ID AND TC.COLUMN_ID = STAT.COLUMN_ID AND STAT.OBJECT_TYPE = 1 AND STAT.TENANT_ID = EFFECTIVE_TENANT_ID() )__"))) { LOG_ERROR("fail to set view_definition", K(ret)); } } @@ -960,7 +960,7 @@ int ObInnerTableSchema::dba_tab_cols_v_schema(ObTableSchema &table_schema) table_schema.set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); if (OB_SUCC(ret)) { - if (OB_FAIL(table_schema.set_view_definition(R"__( SELECT CAST(DB.DATABASE_NAME AS VARCHAR2(128)) AS OWNER, CAST(TC.TABLE_NAME AS VARCHAR2(128)) AS TABLE_NAME, CAST(TC.COLUMN_NAME AS VARCHAR2(128)) AS COLUMN_NAME, CAST(DECODE(TC.DATA_TYPE, 0, 'VARCHAR2', 1, 'NUMBER', 2, 'NUMBER', 3, 'NUMBER', 4, 'NUMBER', 5, 'NUMBER', 6, 'NUMBER', 7, 'NUMBER', 8, 'NUMBER', 9, 'NUMBER', 10, 'NUMBER', 11, 'BINARY_FLOAT', 12, 'BINARY_DOUBLE', 13, 'NUMBER', 14, 'NUMBER', 15, 'NUMBER', 16, 'NUMBER', 17, 'DATE', 18, 'TIMESTAMP', 19, 'DATE', 20, 'TIME', 21, 'YEAR', 22, 'VARCHAR2', 23, 'CHAR', 24, 'HEX_STRING', 25, 'UNDEFINED', 26, 'UNKNOWN', 27, 'TINYTEXT', 28, 'TEXT', 29, 'MEDIUMTEXT', 30, DECODE(TC.COLLATION_TYPE, 63, 'BLOB', 'CLOB'), 31, 'BIT', 32, 'ENUM', 33, 'SET', 34, 'ENUM_INNER', 35, 'SET_INNER', 36, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH TIME ZONE')), 37, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH LOCAL TIME ZONE')), 38, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ')')), 39, 'RAW', 40, CONCAT('INTERVAL YEAR(', CONCAT(TC.DATA_SCALE, ') TO MONTH')), 41, CONCAT('INTERVAL DAY(', CONCAT(TRUNC(TC.DATA_SCALE/10), CONCAT(') TO SECOND(', CONCAT(MOD(TC.DATA_SCALE, 10), ')')))), 42, 'FLOAT', 43, 'NVARCHAR2', 44, 'NCHAR', 45, 'UROWID', 46, 'LOB', 47, 'JSON', 48, 'GEOMETRY', 49, DECODE(TC.SUB_DATA_TYPE, 300001, 'XMLTYPE', 'UDT'), 50, 'NUMBER', 'UNDEFINED') AS VARCHAR2(128)) AS DATA_TYPE, CAST(NULL AS VARCHAR2(3)) AS DATA_TYPE_MOD, CAST(NULL AS VARCHAR2(128)) AS DATA_TYPE_OWNER, CAST(CASE WHEN TC.DATA_TYPE in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 42, 50) THEN 22 WHEN TC.DATA_TYPE = 11 THEN 4 WHEN TC.DATA_TYPE = 12 THEN 8 WHEN TC.DATA_TYPE in (17, 19) THEN 7 WHEN TC.DATA_TYPE in (18, 37, 38) THEN CASE WHEN TC.DATA_SCALE = 0 THEN 7 ELSE 11 END WHEN TC.DATA_TYPE = 41 THEN 11 WHEN TC.DATA_TYPE = 40 THEN 5 WHEN TC.DATA_TYPE = 30 THEN 4000 WHEN TC.DATA_TYPE = 36 THEN 13 WHEN TC.DATA_TYPE IN (0,22,43,46) AND TC.DATA_PRECISION = 1 THEN LEAST(32767, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE IN (23,44) AND TC.DATA_PRECISION = 1 THEN LEAST(2000, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) ELSE TC.DATA_LENGTH END AS NUMBER) AS DATA_LENGTH, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,18,19,22,23,27,28,29,30,36,37,38,43,44) THEN NULL ELSE CASE WHEN TC.DATA_PRECISION < 0 THEN NULL ELSE TC.DATA_PRECISION END END AS NUMBER) AS DATA_PRECISION, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,19,22,23,27,28,29,30,42,43,44) THEN NULL ELSE CASE WHEN TC.DATA_SCALE < -84 THEN NULL ELSE TC.DATA_SCALE END END AS NUMBER) AS DATA_SCALE, CAST(DECODE(TC.NULLABLE, 0, 'N', DECODE(BITAND(TC.COLUMN_FLAGS, 5 * POWER(2, 13)), 5 * POWER(2, 13), 'N', 'Y')) AS VARCHAR2(1)) AS NULLABLE, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, TC.COLUMN_ID, NULL) AS NUMBER) AS COLUMN_ID, CAST(LENGTHB(TC.CUR_DEFAULT_VALUE_V2) AS NUMBER) AS DEFAULT_LENGTH, CAST(TC.CUR_DEFAULT_VALUE_V2 AS /* TODO: LONG() */ VARCHAR(32767)) AS DATA_DEFAULT, CAST(STAT.DISTINCT_CNT AS NUMBER) AS NUM_DISTINCT, CAST(STAT.MIN_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS LOW_VALUE, CAST(STAT.MAX_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS HIGH_VALUE, CAST(STAT.DENSITY AS NUMBER) AS DENSITY, CAST(STAT.NULL_CNT AS NUMBER) AS NUM_NULLS, CAST(STAT.BUCKET_CNT AS NUMBER) AS NUM_BUCKETS, CAST(STAT.LAST_ANALYZED AS DATE) AS LAST_ANALYZED, CAST(STAT.SAMPLE_SIZE AS NUMBER) AS SAMPLE_SIZE, CAST(DECODE(TC.DATA_TYPE, 22, 'CHAR_CS', 23, 'CHAR_CS', 30, DECODE(TC.COLLATION_TYPE, 63, 'NULL', 'CHAR_CS'), 43, 'NCHAR_CS', 44, 'NCHAR_CS', '') AS VARCHAR2(44)) AS CHARACTER_SET_NAME, CAST(NULL AS NUMBER) AS CHAR_COL_DECL_LENGTH, CAST(DECODE(STAT.GLOBAL_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS GLOBAL_STATS, CAST(DECODE(STAT.USER_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS USER_STATS, CAST(NULL AS VARCHAR2(80)) AS NOTES, CAST(STAT.AVG_LEN AS NUMBER) AS AVG_COL_LEN, CAST(CASE WHEN TC.DATA_TYPE IN (22,23,43,44) THEN TC.DATA_LENGTH ELSE 0 END AS NUMBER) AS CHAR_LENGTH, CAST(DECODE(TC.DATA_TYPE, 22, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 23, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 43, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 44, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), NULL) AS VARCHAR2(1)) AS CHAR_USED, CAST(NULL AS VARCHAR2(3)) AS V80_FMT_IMAGE, CAST(NULL AS VARCHAR2(3)) AS DATA_UPGRADED, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, 'NO', 'YES') AS VARCHAR2(3)) AS HIDDEN_COLUMN, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 1), 1, 'YES', 'NO') AS VARCHAR2(3)) AS VIRTUAL_COLUMN, CAST(NULL AS NUMBER) AS SEGMENT_COLUMN_ID, CAST(NULL AS NUMBER) AS INTERNAL_COLUMN_ID, CAST((CASE WHEN STAT.HISTOGRAM_TYPE = 1 THEN 'FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 3 THEN 'TOP-FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 4 THEN 'HYBRID' ELSE NULL END) AS VARCHAR2(15)) AS HISTOGRAM, CAST(TC.COLUMN_NAME AS VARCHAR2(4000)) AS QUALIFIED_COL_NAME, CAST('YES' AS VARCHAR2(3)) AS USER_GENERATED, CAST(NULL AS VARCHAR2(3)) AS DEFAULT_ON_NULL, CAST(NULL AS VARCHAR2(3)) AS IDENTITY_COLUMN, CAST(NULL AS VARCHAR2(128)) AS EVALUATION_EDITION, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEFORE, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEGINNING, CAST(NULL AS VARCHAR2(100)) AS COLLATION, CAST(NULL AS NUMBER) AS COLLATED_COLUMN_ID FROM (SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_CORE_ALL_TABLE T, SYS.ALL_VIRTUAL_CORE_COLUMN_TABLE C WHERE C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0 UNION ALL SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_TABLE_REAL_AGENT T, SYS.ALL_VIRTUAL_COLUMN_REAL_AGENT C WHERE T.TENANT_ID = EFFECTIVE_TENANT_ID() AND C.TENANT_ID = EFFECTIVE_TENANT_ID() AND T.TABLE_TYPE IN (0,1,3,4,5,7,8,9,14,15) AND bitand((T.TABLE_MODE / 4096), 15) IN (0,1) AND C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0) TC JOIN SYS.ALL_VIRTUAL_DATABASE_REAL_AGENT DB ON DB.TENANT_ID = TC.TENANT_ID AND DB.DATABASE_ID = TC.DATABASE_ID AND DB.TENANT_ID = EFFECTIVE_TENANT_ID() LEFT JOIN SYS.ALL_VIRTUAL_COLUMN_STAT_REAL_AGENT STAT ON TC.TENANT_ID = STAT.TENANT_ID AND TC.TABLE_ID = STAT.TABLE_ID AND TC.COLUMN_ID = STAT.COLUMN_ID AND STAT.OBJECT_TYPE = 1 AND STAT.TENANT_ID = EFFECTIVE_TENANT_ID() )__"))) { + if (OB_FAIL(table_schema.set_view_definition(R"__( SELECT CAST(DB.DATABASE_NAME AS VARCHAR2(128)) AS OWNER, CAST(TC.TABLE_NAME AS VARCHAR2(128)) AS TABLE_NAME, CAST(TC.COLUMN_NAME AS VARCHAR2(128)) AS COLUMN_NAME, CAST(DECODE(TC.DATA_TYPE, 0, 'VARCHAR2', 1, 'NUMBER', 2, 'NUMBER', 3, 'NUMBER', 4, 'NUMBER', 5, 'NUMBER', 6, 'NUMBER', 7, 'NUMBER', 8, 'NUMBER', 9, 'NUMBER', 10, 'NUMBER', 11, 'BINARY_FLOAT', 12, 'BINARY_DOUBLE', 13, 'NUMBER', 14, 'NUMBER', 15, 'NUMBER', 16, 'NUMBER', 17, 'DATE', 18, 'TIMESTAMP', 19, 'DATE', 20, 'TIME', 21, 'YEAR', 22, 'VARCHAR2', 23, 'CHAR', 24, 'HEX_STRING', 25, 'UNDEFINED', 26, 'UNKNOWN', 27, 'TINYTEXT', 28, 'TEXT', 29, 'MEDIUMTEXT', 30, DECODE(TC.COLLATION_TYPE, 63, 'BLOB', 'CLOB'), 31, 'BIT', 32, 'ENUM', 33, 'SET', 34, 'ENUM_INNER', 35, 'SET_INNER', 36, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH TIME ZONE')), 37, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH LOCAL TIME ZONE')), 38, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ')')), 39, 'RAW', 40, CONCAT('INTERVAL YEAR(', CONCAT(TC.DATA_SCALE, ') TO MONTH')), 41, CONCAT('INTERVAL DAY(', CONCAT(TRUNC(TC.DATA_SCALE/10), CONCAT(') TO SECOND(', CONCAT(MOD(TC.DATA_SCALE, 10), ')')))), 42, 'FLOAT', 43, 'NVARCHAR2', 44, 'NCHAR', 45, 'UROWID', 46, 'LOB', 47, 'JSON', 48, 'SDO_GEOMETRY', 49, DECODE(TC.SUB_DATA_TYPE, 300001, 'XMLTYPE', 'UDT'), 50, 'NUMBER', 'UNDEFINED') AS VARCHAR2(128)) AS DATA_TYPE, CAST(NULL AS VARCHAR2(3)) AS DATA_TYPE_MOD, CAST(NULL AS VARCHAR2(128)) AS DATA_TYPE_OWNER, CAST(CASE WHEN TC.DATA_TYPE in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 42, 50) THEN 22 WHEN TC.DATA_TYPE = 11 THEN 4 WHEN TC.DATA_TYPE = 12 THEN 8 WHEN TC.DATA_TYPE in (17, 19) THEN 7 WHEN TC.DATA_TYPE in (18, 37, 38) THEN CASE WHEN TC.DATA_SCALE = 0 THEN 7 ELSE 11 END WHEN TC.DATA_TYPE = 41 THEN 11 WHEN TC.DATA_TYPE = 40 THEN 5 WHEN TC.DATA_TYPE = 30 THEN 4000 WHEN TC.DATA_TYPE = 36 THEN 13 WHEN TC.DATA_TYPE IN (0,22,43,46) AND TC.DATA_PRECISION = 1 THEN LEAST(32767, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE IN (23,44) AND TC.DATA_PRECISION = 1 THEN LEAST(2000, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE = 48 THEN 1 ELSE TC.DATA_LENGTH END AS NUMBER) AS DATA_LENGTH, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,18,19,22,23,27,28,29,30,36,37,38,43,44) THEN NULL ELSE CASE WHEN TC.DATA_PRECISION < 0 THEN NULL ELSE TC.DATA_PRECISION END END AS NUMBER) AS DATA_PRECISION, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,19,22,23,27,28,29,30,42,43,44) THEN NULL ELSE CASE WHEN TC.DATA_SCALE < -84 THEN NULL ELSE TC.DATA_SCALE END END AS NUMBER) AS DATA_SCALE, CAST(DECODE(TC.NULLABLE, 0, 'N', DECODE(BITAND(TC.COLUMN_FLAGS, 5 * POWER(2, 13)), 5 * POWER(2, 13), 'N', 'Y')) AS VARCHAR2(1)) AS NULLABLE, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, TC.COLUMN_ID, NULL) AS NUMBER) AS COLUMN_ID, CAST(LENGTHB(TC.CUR_DEFAULT_VALUE_V2) AS NUMBER) AS DEFAULT_LENGTH, CAST(TC.CUR_DEFAULT_VALUE_V2 AS /* TODO: LONG() */ VARCHAR(32767)) AS DATA_DEFAULT, CAST(STAT.DISTINCT_CNT AS NUMBER) AS NUM_DISTINCT, CAST(STAT.MIN_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS LOW_VALUE, CAST(STAT.MAX_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS HIGH_VALUE, CAST(STAT.DENSITY AS NUMBER) AS DENSITY, CAST(STAT.NULL_CNT AS NUMBER) AS NUM_NULLS, CAST(STAT.BUCKET_CNT AS NUMBER) AS NUM_BUCKETS, CAST(STAT.LAST_ANALYZED AS DATE) AS LAST_ANALYZED, CAST(STAT.SAMPLE_SIZE AS NUMBER) AS SAMPLE_SIZE, CAST(DECODE(TC.DATA_TYPE, 22, 'CHAR_CS', 23, 'CHAR_CS', 30, DECODE(TC.COLLATION_TYPE, 63, 'NULL', 'CHAR_CS'), 43, 'NCHAR_CS', 44, 'NCHAR_CS', '') AS VARCHAR2(44)) AS CHARACTER_SET_NAME, CAST(NULL AS NUMBER) AS CHAR_COL_DECL_LENGTH, CAST(DECODE(STAT.GLOBAL_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS GLOBAL_STATS, CAST(DECODE(STAT.USER_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS USER_STATS, CAST(NULL AS VARCHAR2(80)) AS NOTES, CAST(STAT.AVG_LEN AS NUMBER) AS AVG_COL_LEN, CAST(CASE WHEN TC.DATA_TYPE IN (22,23,43,44) THEN TC.DATA_LENGTH ELSE 0 END AS NUMBER) AS CHAR_LENGTH, CAST(DECODE(TC.DATA_TYPE, 22, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 23, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 43, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 44, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), NULL) AS VARCHAR2(1)) AS CHAR_USED, CAST(NULL AS VARCHAR2(3)) AS V80_FMT_IMAGE, CAST(NULL AS VARCHAR2(3)) AS DATA_UPGRADED, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, 'NO', 'YES') AS VARCHAR2(3)) AS HIDDEN_COLUMN, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 1), 1, 'YES', 'NO') AS VARCHAR2(3)) AS VIRTUAL_COLUMN, CAST(NULL AS NUMBER) AS SEGMENT_COLUMN_ID, CAST(NULL AS NUMBER) AS INTERNAL_COLUMN_ID, CAST((CASE WHEN STAT.HISTOGRAM_TYPE = 1 THEN 'FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 3 THEN 'TOP-FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 4 THEN 'HYBRID' ELSE NULL END) AS VARCHAR2(15)) AS HISTOGRAM, CAST(TC.COLUMN_NAME AS VARCHAR2(4000)) AS QUALIFIED_COL_NAME, CAST('YES' AS VARCHAR2(3)) AS USER_GENERATED, CAST(NULL AS VARCHAR2(3)) AS DEFAULT_ON_NULL, CAST(NULL AS VARCHAR2(3)) AS IDENTITY_COLUMN, CAST(NULL AS VARCHAR2(128)) AS EVALUATION_EDITION, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEFORE, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEGINNING, CAST(NULL AS VARCHAR2(100)) AS COLLATION, CAST(NULL AS NUMBER) AS COLLATED_COLUMN_ID FROM (SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_CORE_ALL_TABLE T, SYS.ALL_VIRTUAL_CORE_COLUMN_TABLE C WHERE C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0 UNION ALL SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_TABLE_REAL_AGENT T, SYS.ALL_VIRTUAL_COLUMN_REAL_AGENT C WHERE T.TENANT_ID = EFFECTIVE_TENANT_ID() AND C.TENANT_ID = EFFECTIVE_TENANT_ID() AND T.TABLE_TYPE IN (0,1,3,4,5,7,8,9,14,15) AND bitand((T.TABLE_MODE / 4096), 15) IN (0,1) AND C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0) TC JOIN SYS.ALL_VIRTUAL_DATABASE_REAL_AGENT DB ON DB.TENANT_ID = TC.TENANT_ID AND DB.DATABASE_ID = TC.DATABASE_ID AND DB.TENANT_ID = EFFECTIVE_TENANT_ID() LEFT JOIN SYS.ALL_VIRTUAL_COLUMN_STAT_REAL_AGENT STAT ON TC.TENANT_ID = STAT.TENANT_ID AND TC.TABLE_ID = STAT.TABLE_ID AND TC.COLUMN_ID = STAT.COLUMN_ID AND STAT.OBJECT_TYPE = 1 AND STAT.TENANT_ID = EFFECTIVE_TENANT_ID() )__"))) { LOG_ERROR("fail to set view_definition", K(ret)); } } @@ -1010,7 +1010,7 @@ int ObInnerTableSchema::user_tab_cols_v_schema(ObTableSchema &table_schema) table_schema.set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); if (OB_SUCC(ret)) { - if (OB_FAIL(table_schema.set_view_definition(R"__( SELECT CAST(TC.TABLE_NAME AS VARCHAR2(128)) AS TABLE_NAME, CAST(TC.COLUMN_NAME AS VARCHAR2(128)) AS COLUMN_NAME, CAST(DECODE(TC.DATA_TYPE, 0, 'VARCHAR2', 1, 'NUMBER', 2, 'NUMBER', 3, 'NUMBER', 4, 'NUMBER', 5, 'NUMBER', 6, 'NUMBER', 7, 'NUMBER', 8, 'NUMBER', 9, 'NUMBER', 10, 'NUMBER', 11, 'BINARY_FLOAT', 12, 'BINARY_DOUBLE', 13, 'NUMBER', 14, 'NUMBER', 15, 'NUMBER', 16, 'NUMBER', 17, 'DATE', 18, 'TIMESTAMP', 19, 'DATE', 20, 'TIME', 21, 'YEAR', 22, 'VARCHAR2', 23, 'CHAR', 24, 'HEX_STRING', 25, 'UNDEFINED', 26, 'UNKNOWN', 27, 'TINYTEXT', 28, 'TEXT', 29, 'MEDIUMTEXT', 30, DECODE(TC.COLLATION_TYPE, 63, 'BLOB', 'CLOB'), 31, 'BIT', 32, 'ENUM', 33, 'SET', 34, 'ENUM_INNER', 35, 'SET_INNER', 36, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH TIME ZONE')), 37, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH LOCAL TIME ZONE')), 38, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ')')), 39, 'RAW', 40, CONCAT('INTERVAL YEAR(', CONCAT(TC.DATA_SCALE, ') TO MONTH')), 41, CONCAT('INTERVAL DAY(', CONCAT(TRUNC(TC.DATA_SCALE/10), CONCAT(') TO SECOND(', CONCAT(MOD(TC.DATA_SCALE, 10), ')')))), 42, 'FLOAT', 43, 'NVARCHAR2', 44, 'NCHAR', 45, 'UROWID', 46, 'LOB', 47, 'JSON', 48, 'GEOMETRY', 49, DECODE(TC.SUB_DATA_TYPE, 300001, 'XMLTYPE', 'UDT'), 50, 'NUMBER', 'UNDEFINED') AS VARCHAR2(128)) AS DATA_TYPE, CAST(NULL AS VARCHAR2(3)) AS DATA_TYPE_MOD, CAST(NULL AS VARCHAR2(128)) AS DATA_TYPE_OWNER, CAST(CASE WHEN TC.DATA_TYPE in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 42, 50) THEN 22 WHEN TC.DATA_TYPE = 11 THEN 4 WHEN TC.DATA_TYPE = 12 THEN 8 WHEN TC.DATA_TYPE in (17, 19) THEN 7 WHEN TC.DATA_TYPE in (18, 37, 38) THEN CASE WHEN TC.DATA_SCALE = 0 THEN 7 ELSE 11 END WHEN TC.DATA_TYPE = 41 THEN 11 WHEN TC.DATA_TYPE = 40 THEN 5 WHEN TC.DATA_TYPE = 30 THEN 4000 WHEN TC.DATA_TYPE = 36 THEN 13 WHEN TC.DATA_TYPE IN (0,22,43,46) AND TC.DATA_PRECISION = 1 THEN LEAST(32767, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE IN (23,44) AND TC.DATA_PRECISION = 1 THEN LEAST(2000, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) ELSE TC.DATA_LENGTH END AS NUMBER) AS DATA_LENGTH, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,18,19,22,23,27,28,29,30,36,37,38,43,44) THEN NULL ELSE CASE WHEN TC.DATA_PRECISION < 0 THEN NULL ELSE TC.DATA_PRECISION END END AS NUMBER) AS DATA_PRECISION, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,19,22,23,27,28,29,30,42,43,44) THEN NULL ELSE CASE WHEN TC.DATA_SCALE < -84 THEN NULL ELSE TC.DATA_SCALE END END AS NUMBER) AS DATA_SCALE, CAST(DECODE(TC.NULLABLE, 0, 'N', DECODE(BITAND(TC.COLUMN_FLAGS, 5 * POWER(2, 13)), 5 * POWER(2, 13), 'N', 'Y')) AS VARCHAR2(1)) AS NULLABLE, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, TC.COLUMN_ID, NULL) AS NUMBER) AS COLUMN_ID, CAST(LENGTHB(TC.CUR_DEFAULT_VALUE_V2) AS NUMBER) AS DEFAULT_LENGTH, CAST(TC.CUR_DEFAULT_VALUE_V2 AS /* TODO: LONG() */ VARCHAR(32767)) AS DATA_DEFAULT, CAST(STAT.DISTINCT_CNT AS NUMBER) AS NUM_DISTINCT, CAST(STAT.MIN_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS LOW_VALUE, CAST(STAT.MAX_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS HIGH_VALUE, CAST(STAT.DENSITY AS NUMBER) AS DENSITY, CAST(STAT.NULL_CNT AS NUMBER) AS NUM_NULLS, CAST(STAT.BUCKET_CNT AS NUMBER) AS NUM_BUCKETS, CAST(STAT.LAST_ANALYZED AS DATE) AS LAST_ANALYZED, CAST(STAT.SAMPLE_SIZE AS NUMBER) AS SAMPLE_SIZE, CAST(DECODE(TC.DATA_TYPE, 22, 'CHAR_CS', 23, 'CHAR_CS', 30, DECODE(TC.COLLATION_TYPE, 63, 'NULL', 'CHAR_CS'), 43, 'NCHAR_CS', 44, 'NCHAR_CS', '') AS VARCHAR2(44)) AS CHARACTER_SET_NAME, CAST(NULL AS NUMBER) AS CHAR_COL_DECL_LENGTH, CAST(DECODE(STAT.GLOBAL_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS GLOBAL_STATS, CAST(DECODE(STAT.USER_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS USER_STATS, CAST(NULL AS VARCHAR2(80)) AS NOTES, CAST(STAT.AVG_LEN AS NUMBER) AS AVG_COL_LEN, CAST(CASE WHEN TC.DATA_TYPE IN (22,23,43,44) THEN TC.DATA_LENGTH ELSE 0 END AS NUMBER) AS CHAR_LENGTH, CAST(DECODE(TC.DATA_TYPE, 22, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 23, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 43, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 44, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), NULL) AS VARCHAR2(1)) AS CHAR_USED, CAST(NULL AS VARCHAR2(3)) AS V80_FMT_IMAGE, CAST(NULL AS VARCHAR2(3)) AS DATA_UPGRADED, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, 'NO', 'YES') AS VARCHAR2(3)) AS HIDDEN_COLUMN, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 1), 1, 'YES', 'NO') AS VARCHAR2(3)) AS VIRTUAL_COLUMN, CAST(NULL AS NUMBER) AS SEGMENT_COLUMN_ID, CAST(NULL AS NUMBER) AS INTERNAL_COLUMN_ID, CAST((CASE WHEN STAT.HISTOGRAM_TYPE = 1 THEN 'FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 3 THEN 'TOP-FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 4 THEN 'HYBRID' ELSE NULL END) AS VARCHAR2(15)) AS HISTOGRAM, CAST(TC.COLUMN_NAME AS VARCHAR2(4000)) AS QUALIFIED_COL_NAME, CAST('YES' AS VARCHAR2(3)) AS USER_GENERATED, CAST(NULL AS VARCHAR2(3)) AS DEFAULT_ON_NULL, CAST(NULL AS VARCHAR2(3)) AS IDENTITY_COLUMN, CAST(NULL AS VARCHAR2(128)) AS EVALUATION_EDITION, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEFORE, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEGINNING, CAST(NULL AS VARCHAR2(100)) AS COLLATION, CAST(NULL AS NUMBER) AS COLLATED_COLUMN_ID FROM (SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_CORE_ALL_TABLE T, SYS.ALL_VIRTUAL_CORE_COLUMN_TABLE C WHERE C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0 UNION ALL SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_TABLE_REAL_AGENT T, SYS.ALL_VIRTUAL_COLUMN_REAL_AGENT C WHERE T.TENANT_ID = EFFECTIVE_TENANT_ID() AND C.TENANT_ID = EFFECTIVE_TENANT_ID() AND T.TABLE_TYPE IN (0,1,3,4,5,7,8,9,14,15) AND bitand((T.TABLE_MODE / 4096), 15) IN (0,1) AND C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0) TC JOIN SYS.ALL_VIRTUAL_DATABASE_REAL_AGENT DB ON DB.TENANT_ID = TC.TENANT_ID AND DB.DATABASE_ID = TC.DATABASE_ID AND DB.TENANT_ID = EFFECTIVE_TENANT_ID() AND TC.DATABASE_ID = USERENV('SCHEMAID') LEFT JOIN SYS.ALL_VIRTUAL_COLUMN_STAT_REAL_AGENT STAT ON TC.TENANT_ID = STAT.TENANT_ID AND TC.TABLE_ID = STAT.TABLE_ID AND TC.COLUMN_ID = STAT.COLUMN_ID AND STAT.OBJECT_TYPE = 1 AND STAT.TENANT_ID = EFFECTIVE_TENANT_ID() )__"))) { + if (OB_FAIL(table_schema.set_view_definition(R"__( SELECT CAST(TC.TABLE_NAME AS VARCHAR2(128)) AS TABLE_NAME, CAST(TC.COLUMN_NAME AS VARCHAR2(128)) AS COLUMN_NAME, CAST(DECODE(TC.DATA_TYPE, 0, 'VARCHAR2', 1, 'NUMBER', 2, 'NUMBER', 3, 'NUMBER', 4, 'NUMBER', 5, 'NUMBER', 6, 'NUMBER', 7, 'NUMBER', 8, 'NUMBER', 9, 'NUMBER', 10, 'NUMBER', 11, 'BINARY_FLOAT', 12, 'BINARY_DOUBLE', 13, 'NUMBER', 14, 'NUMBER', 15, 'NUMBER', 16, 'NUMBER', 17, 'DATE', 18, 'TIMESTAMP', 19, 'DATE', 20, 'TIME', 21, 'YEAR', 22, 'VARCHAR2', 23, 'CHAR', 24, 'HEX_STRING', 25, 'UNDEFINED', 26, 'UNKNOWN', 27, 'TINYTEXT', 28, 'TEXT', 29, 'MEDIUMTEXT', 30, DECODE(TC.COLLATION_TYPE, 63, 'BLOB', 'CLOB'), 31, 'BIT', 32, 'ENUM', 33, 'SET', 34, 'ENUM_INNER', 35, 'SET_INNER', 36, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH TIME ZONE')), 37, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ') WITH LOCAL TIME ZONE')), 38, CONCAT('TIMESTAMP(', CONCAT(TC.DATA_SCALE, ')')), 39, 'RAW', 40, CONCAT('INTERVAL YEAR(', CONCAT(TC.DATA_SCALE, ') TO MONTH')), 41, CONCAT('INTERVAL DAY(', CONCAT(TRUNC(TC.DATA_SCALE/10), CONCAT(') TO SECOND(', CONCAT(MOD(TC.DATA_SCALE, 10), ')')))), 42, 'FLOAT', 43, 'NVARCHAR2', 44, 'NCHAR', 45, 'UROWID', 46, 'LOB', 47, 'JSON', 48, 'SDO_GEOMETRY', 49, DECODE(TC.SUB_DATA_TYPE, 300001, 'XMLTYPE', 'UDT'), 50, 'NUMBER', 'UNDEFINED') AS VARCHAR2(128)) AS DATA_TYPE, CAST(NULL AS VARCHAR2(3)) AS DATA_TYPE_MOD, CAST(NULL AS VARCHAR2(128)) AS DATA_TYPE_OWNER, CAST(CASE WHEN TC.DATA_TYPE in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 16, 42, 50) THEN 22 WHEN TC.DATA_TYPE = 11 THEN 4 WHEN TC.DATA_TYPE = 12 THEN 8 WHEN TC.DATA_TYPE in (17, 19) THEN 7 WHEN TC.DATA_TYPE in (18, 37, 38) THEN CASE WHEN TC.DATA_SCALE = 0 THEN 7 ELSE 11 END WHEN TC.DATA_TYPE = 41 THEN 11 WHEN TC.DATA_TYPE = 40 THEN 5 WHEN TC.DATA_TYPE = 30 THEN 4000 WHEN TC.DATA_TYPE = 36 THEN 13 WHEN TC.DATA_TYPE IN (0,22,43,46) AND TC.DATA_PRECISION = 1 THEN LEAST(32767, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE IN (23,44) AND TC.DATA_PRECISION = 1 THEN LEAST(2000, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE = 48 THEN 1 ELSE TC.DATA_LENGTH END AS NUMBER) AS DATA_LENGTH, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,18,19,22,23,27,28,29,30,36,37,38,43,44) THEN NULL ELSE CASE WHEN TC.DATA_PRECISION < 0 THEN NULL ELSE TC.DATA_PRECISION END END AS NUMBER) AS DATA_PRECISION, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,19,22,23,27,28,29,30,42,43,44) THEN NULL ELSE CASE WHEN TC.DATA_SCALE < -84 THEN NULL ELSE TC.DATA_SCALE END END AS NUMBER) AS DATA_SCALE, CAST(DECODE(TC.NULLABLE, 0, 'N', DECODE(BITAND(TC.COLUMN_FLAGS, 5 * POWER(2, 13)), 5 * POWER(2, 13), 'N', 'Y')) AS VARCHAR2(1)) AS NULLABLE, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, TC.COLUMN_ID, NULL) AS NUMBER) AS COLUMN_ID, CAST(LENGTHB(TC.CUR_DEFAULT_VALUE_V2) AS NUMBER) AS DEFAULT_LENGTH, CAST(TC.CUR_DEFAULT_VALUE_V2 AS /* TODO: LONG() */ VARCHAR(32767)) AS DATA_DEFAULT, CAST(STAT.DISTINCT_CNT AS NUMBER) AS NUM_DISTINCT, CAST(STAT.MIN_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS LOW_VALUE, CAST(STAT.MAX_VALUE AS /* TODO: RAW */ VARCHAR(128)) AS HIGH_VALUE, CAST(STAT.DENSITY AS NUMBER) AS DENSITY, CAST(STAT.NULL_CNT AS NUMBER) AS NUM_NULLS, CAST(STAT.BUCKET_CNT AS NUMBER) AS NUM_BUCKETS, CAST(STAT.LAST_ANALYZED AS DATE) AS LAST_ANALYZED, CAST(STAT.SAMPLE_SIZE AS NUMBER) AS SAMPLE_SIZE, CAST(DECODE(TC.DATA_TYPE, 22, 'CHAR_CS', 23, 'CHAR_CS', 30, DECODE(TC.COLLATION_TYPE, 63, 'NULL', 'CHAR_CS'), 43, 'NCHAR_CS', 44, 'NCHAR_CS', '') AS VARCHAR2(44)) AS CHARACTER_SET_NAME, CAST(NULL AS NUMBER) AS CHAR_COL_DECL_LENGTH, CAST(DECODE(STAT.GLOBAL_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS GLOBAL_STATS, CAST(DECODE(STAT.USER_STATS, 0, 'NO', 1, 'YES', NULL) AS VARCHAR2(3)) AS USER_STATS, CAST(NULL AS VARCHAR2(80)) AS NOTES, CAST(STAT.AVG_LEN AS NUMBER) AS AVG_COL_LEN, CAST(CASE WHEN TC.DATA_TYPE IN (22,23,43,44) THEN TC.DATA_LENGTH ELSE 0 END AS NUMBER) AS CHAR_LENGTH, CAST(DECODE(TC.DATA_TYPE, 22, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 23, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 43, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), 44, DECODE(TC.DATA_PRECISION, 1, 'C', 'B'), NULL) AS VARCHAR2(1)) AS CHAR_USED, CAST(NULL AS VARCHAR2(3)) AS V80_FMT_IMAGE, CAST(NULL AS VARCHAR2(3)) AS DATA_UPGRADED, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 64), 0, 'NO', 'YES') AS VARCHAR2(3)) AS HIDDEN_COLUMN, CAST(DECODE(BITAND(TC.COLUMN_FLAGS, 1), 1, 'YES', 'NO') AS VARCHAR2(3)) AS VIRTUAL_COLUMN, CAST(NULL AS NUMBER) AS SEGMENT_COLUMN_ID, CAST(NULL AS NUMBER) AS INTERNAL_COLUMN_ID, CAST((CASE WHEN STAT.HISTOGRAM_TYPE = 1 THEN 'FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 3 THEN 'TOP-FREQUENCY' WHEN STAT.HISTOGRAM_TYPE = 4 THEN 'HYBRID' ELSE NULL END) AS VARCHAR2(15)) AS HISTOGRAM, CAST(TC.COLUMN_NAME AS VARCHAR2(4000)) AS QUALIFIED_COL_NAME, CAST('YES' AS VARCHAR2(3)) AS USER_GENERATED, CAST(NULL AS VARCHAR2(3)) AS DEFAULT_ON_NULL, CAST(NULL AS VARCHAR2(3)) AS IDENTITY_COLUMN, CAST(NULL AS VARCHAR2(128)) AS EVALUATION_EDITION, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEFORE, CAST(NULL AS VARCHAR2(128)) AS UNUSABLE_BEGINNING, CAST(NULL AS VARCHAR2(100)) AS COLLATION, CAST(NULL AS NUMBER) AS COLLATED_COLUMN_ID FROM (SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_CORE_ALL_TABLE T, SYS.ALL_VIRTUAL_CORE_COLUMN_TABLE C WHERE C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0 UNION ALL SELECT T.TENANT_ID, T.TABLE_ID, T.DATABASE_ID, T.TABLE_NAME, T.TABLE_TYPE, C.COLUMN_ID, C.COLUMN_NAME, C.DATA_TYPE, C.SUB_DATA_TYPE, C.COLLATION_TYPE, C.DATA_SCALE, C.DATA_LENGTH, C.DATA_PRECISION, C.NULLABLE, C.COLUMN_FLAGS, C.CUR_DEFAULT_VALUE_V2 FROM SYS.ALL_VIRTUAL_TABLE_REAL_AGENT T, SYS.ALL_VIRTUAL_COLUMN_REAL_AGENT C WHERE T.TENANT_ID = EFFECTIVE_TENANT_ID() AND C.TENANT_ID = EFFECTIVE_TENANT_ID() AND T.TABLE_TYPE IN (0,1,3,4,5,7,8,9,14,15) AND bitand((T.TABLE_MODE / 4096), 15) IN (0,1) AND C.TENANT_ID = T.TENANT_ID AND C.TABLE_ID = T.TABLE_ID AND C.IS_HIDDEN = 0) TC JOIN SYS.ALL_VIRTUAL_DATABASE_REAL_AGENT DB ON DB.TENANT_ID = TC.TENANT_ID AND DB.DATABASE_ID = TC.DATABASE_ID AND DB.TENANT_ID = EFFECTIVE_TENANT_ID() AND TC.DATABASE_ID = USERENV('SCHEMAID') LEFT JOIN SYS.ALL_VIRTUAL_COLUMN_STAT_REAL_AGENT STAT ON TC.TENANT_ID = STAT.TENANT_ID AND TC.TABLE_ID = STAT.TABLE_ID AND TC.COLUMN_ID = STAT.COLUMN_ID AND STAT.OBJECT_TYPE = 1 AND STAT.TENANT_ID = EFFECTIVE_TENANT_ID() )__"))) { LOG_ERROR("fail to set view_definition", K(ret)); } } diff --git a/src/share/inner_table/ob_inner_table_schema_def.py b/src/share/inner_table/ob_inner_table_schema_def.py index 7cd93fedf0..4cec18caa6 100644 --- a/src/share/inner_table/ob_inner_table_schema_def.py +++ b/src/share/inner_table/ob_inner_table_schema_def.py @@ -36109,7 +36109,7 @@ SELECT 45, 'UROWID', 46, 'LOB', 47, 'JSON', - 48, 'GEOMETRY', + 48, 'SDO_GEOMETRY', 49, DECODE(TC.SUB_DATA_TYPE, 300001, 'XMLTYPE', 'UDT'), 50, 'NUMBER', 'UNDEFINED') AS VARCHAR2(128)) AS DATA_TYPE, @@ -36126,6 +36126,7 @@ SELECT WHEN TC.DATA_TYPE = 36 THEN 13 WHEN TC.DATA_TYPE IN (0,22,43,46) AND TC.DATA_PRECISION = 1 THEN LEAST(32767, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE IN (23,44) AND TC.DATA_PRECISION = 1 THEN LEAST(2000, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) + WHEN TC.DATA_TYPE = 48 THEN 1 ELSE TC.DATA_LENGTH END AS NUMBER) AS DATA_LENGTH, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,18,19,22,23,27,28,29,30,36,37,38,43,44) THEN NULL @@ -36323,7 +36324,7 @@ SELECT 45, 'UROWID', 46, 'LOB', 47, 'JSON', - 48, 'GEOMETRY', + 48, 'SDO_GEOMETRY', 49, DECODE(TC.SUB_DATA_TYPE, 300001, 'XMLTYPE', 'UDT'), 50, 'NUMBER', 'UNDEFINED') AS VARCHAR2(128)) AS DATA_TYPE, @@ -36340,6 +36341,7 @@ SELECT WHEN TC.DATA_TYPE = 36 THEN 13 WHEN TC.DATA_TYPE IN (0,22,43,46) AND TC.DATA_PRECISION = 1 THEN LEAST(32767, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE IN (23,44) AND TC.DATA_PRECISION = 1 THEN LEAST(2000, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) + WHEN TC.DATA_TYPE = 48 THEN 1 ELSE TC.DATA_LENGTH END AS NUMBER) AS DATA_LENGTH, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,18,19,22,23,27,28,29,30,36,37,38,43,44) THEN NULL @@ -36534,7 +36536,7 @@ SELECT 45, 'UROWID', 46, 'LOB', 47, 'JSON', - 48, 'GEOMETRY', + 48, 'SDO_GEOMETRY', 49, DECODE(TC.SUB_DATA_TYPE, 300001, 'XMLTYPE', 'UDT'), 50, 'NUMBER', 'UNDEFINED') AS VARCHAR2(128)) AS DATA_TYPE, @@ -36551,6 +36553,7 @@ SELECT WHEN TC.DATA_TYPE = 36 THEN 13 WHEN TC.DATA_TYPE IN (0,22,43,46) AND TC.DATA_PRECISION = 1 THEN LEAST(32767, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) WHEN TC.DATA_TYPE IN (23,44) AND TC.DATA_PRECISION = 1 THEN LEAST(2000, TC.DATA_LENGTH * DECODE(TC.COLLATION_TYPE, 63, 1, 249, 4, 248, 4, 87, 2,28, 2, 55, 2, 54, 4, 101, 2, 46, 4, 45, 4, 224, 4, 1)) + WHEN TC.DATA_TYPE = 48 THEN 1 ELSE TC.DATA_LENGTH END AS NUMBER) AS DATA_LENGTH, CAST(CASE WHEN TC.DATA_TYPE IN (0,11,12,17,18,19,22,23,27,28,29,30,36,37,38,43,44) THEN NULL diff --git a/src/share/inner_table/sys_package/sdo_geometry.sql b/src/share/inner_table/sys_package/sdo_geometry.sql index e6f8cd5b5c..9202926bb9 100644 --- a/src/share/inner_table/sys_package/sdo_geometry.sql +++ b/src/share/inner_table/sys_package/sdo_geometry.sql @@ -30,4 +30,4 @@ CREATE OR REPLACE TYPE SDO_GEOMETRY OID '300028' IS OBJECT ( CONSTRUCTOR FUNCTION SDO_GEOMETRY(wkt IN CLOB, srid IN NUMBER DEFAULT NULL) RETURN SELF AS RESULT DETERMINISTIC, CONSTRUCTOR FUNCTION SDO_GEOMETRY(wkt IN VARCHAR2, srid IN NUMBER DEFAULT NULL) RETURN SELF AS RESULT DETERMINISTIC ); -// \ No newline at end of file +// diff --git a/src/share/inner_table/sys_package/sdo_geometry_body.sql b/src/share/inner_table/sys_package/sdo_geometry_body.sql new file mode 100644 index 0000000000..c2210e3f25 --- /dev/null +++ b/src/share/inner_table/sys_package/sdo_geometry_body.sql @@ -0,0 +1,37 @@ +#type_name:sdo_geometry +#package_name:sdo_geometry + +CREATE OR REPLACE TYPE BODY SDO_GEOMETRY AS + + -- extraction functions + MEMBER FUNCTION GET_WKB RETURN BLOB DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_get_wkb); + + MEMBER FUNCTION GET_WKT RETURN CLOB DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_get_wkt); + + MEMBER FUNCTION Get_GType RETURN NUMBER DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_get_gtype); + + MEMBER FUNCTION ST_CoordDim RETURN NUMBER DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_st_coorddim); + + MEMBER FUNCTION Get_Dims RETURN NUMBER DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_get_dims); + + MEMBER FUNCTION ST_IsValid RETURN NUMBER DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_st_isvalid); + + MEMBER FUNCTION Get_GeoJson RETURN CLOB DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_get_geojson); + + CONSTRUCTOR FUNCTION SDO_GEOMETRY(wkb IN BLOB, srid IN NUMBER DEFAULT NULL) RETURN SELF AS RESULT DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_constructor); + + CONSTRUCTOR FUNCTION SDO_GEOMETRY(wkt IN CLOB, srid IN NUMBER DEFAULT NULL) RETURN SELF AS RESULT DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_constructor); + + CONSTRUCTOR FUNCTION SDO_GEOMETRY(wkt IN VARCHAR2, srid IN NUMBER DEFAULT NULL) RETURN SELF AS RESULT DETERMINISTIC; + PRAGMA INTERFACE(c, sdo_geometry_constructor); +END; +// diff --git a/src/share/ob_lob_access_utils.cpp b/src/share/ob_lob_access_utils.cpp index 3f445964f8..e46b0719a3 100644 --- a/src/share/ob_lob_access_utils.cpp +++ b/src/share/ob_lob_access_utils.cpp @@ -1060,6 +1060,61 @@ int ObTextStringResult::calc_buffer_len(int64_t res_len) return ret; } +int ObTextStringResult::calc_inrow_templob_len(uint32 inrow_data_len, int64_t &templob_len) +{ + int ret = OB_SUCCESS; + if (inrow_data_len < OB_MAX_LONGTEXT_LENGTH - MAX_TMP_LOB_HEADER_LEN) { + bool has_extern = lib::is_oracle_mode(); + ObMemLobExternFlags extern_flags(has_extern); + inrow_data_len += sizeof(ObLobCommon); + templob_len = ObLobLocatorV2::calc_locator_full_len(extern_flags, 0, inrow_data_len, false); + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("Lob: not support length bigger than 512M", K(ret), K(inrow_data_len)); + } + return ret; +} + +int64_t ObTextStringResult::calc_inrow_templob_locator_len() +{ + ObMemLobExternFlags extern_flags(lib::is_oracle_mode()); + return static_cast(ObLobLocatorV2::calc_locator_full_len(extern_flags, 0, 0, false)); +} + +int ObTextStringResult::fill_inrow_templob_header(const int64_t inrow_data_len, char *buf, int64_t buf_len) +{ + int ret = OB_SUCCESS; + + if (OB_ISNULL(buf) || (buf_len == 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Lob: try to fill inrow templob header with empty buffer", + K(ret), K(inrow_data_len), K(buf), K(buf_len)); + } else if (inrow_data_len <= OB_MAX_LONGTEXT_LENGTH - MAX_TMP_LOB_HEADER_LEN) { + ObLobLocatorV2 locator(buf, static_cast(buf_len), true); + // temp lob in oracle mode not need extern neither, for it does not have rowkey + // However we mock extern failed in case of return it to old client + ObMemLobExternFlags extern_flags(lib::is_oracle_mode()); + ObString rowkey_str; + ObString empty_str; + ObLobCommon lob_common; + if (OB_FAIL(locator.fill(TEMP_FULL_LOB, + extern_flags, + rowkey_str, + &lob_common, + static_cast(inrow_data_len + sizeof(ObLobCommon)), + 0, + false))) { + LOG_WARN("Lob: fill temp lob locator failed", K(ret), K(inrow_data_len), K(buf), K(buf_len)); + } else if (OB_FAIL((locator.set_payload_data(&lob_common, empty_str)))) { + LOG_WARN("Lob: set temp lob locator payload failed", K(ret), K(inrow_data_len), K(buf), K(buf_len)); + } + } else { // oversized + ret = OB_NOT_SUPPORTED; + LOG_WARN("Lob: not support length bigger than 512M", K(ret), K(inrow_data_len), K(buf), K(buf_len)); + } + return ret; +} + int ObTextStringResult::fill_temp_lob_header(const int64_t res_len) { int ret = OB_SUCCESS; diff --git a/src/share/ob_lob_access_utils.h b/src/share/ob_lob_access_utils.h index e8f350d2d0..334b1a5c58 100644 --- a/src/share/ob_lob_access_utils.h +++ b/src/share/ob_lob_access_utils.h @@ -278,6 +278,9 @@ public: const ObObjMeta &in_obj_meta, const ObObjMeta &out_obj_meta, ObIAllocator &allocator); + static int calc_inrow_templob_len(uint32 inrow_data_len, int64_t &templob_len); + static int64_t calc_inrow_templob_locator_len(); + static int fill_inrow_templob_header(const int64_t inrow_data_len, char *buf, int64_t buf_len); protected: int calc_buffer_len(const int64_t res_len); diff --git a/src/share/object/ob_obj_cast.cpp b/src/share/object/ob_obj_cast.cpp index 097a36634d..73134bbf5f 100644 --- a/src/share/object/ob_obj_cast.cpp +++ b/src/share/object/ob_obj_cast.cpp @@ -30,12 +30,17 @@ #include "lib/json_type/ob_json_parse.h" #include "share/ob_lob_access_utils.h" #include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_expr_sql_udt_utils.h" +#include "sql/engine/ob_exec_context.h" #include "lib/charset/ob_charset.h" #include "lib/geo/ob_geometry_cast.h" #include "sql/engine/expr/ob_datum_cast.h" #include "sql/engine/expr/ob_expr_util.h" #include "src/storage/lob/ob_lob_manager.h" #include "sql/engine/expr/ob_expr_json_func_helper.h" +#ifdef OB_BUILD_ORACLE_PL +#include "pl/sys_package/ob_sdo_geometry.h" +#endif #ifdef OB_BUILD_ORACLE_XML #include "lib/xml/ob_xml_util.h" #include "lib/xml/ob_xml_parser.h" @@ -1595,7 +1600,7 @@ static int common_build_geometry(ObIAllocator &allocator, { int ret = OB_SUCCESS; ObGeoErrLogInfo log_info; - if (OB_FAIL(ObGeoTypeUtil::build_geometry(allocator, wkb, geo, srs, log_info))) { + if (OB_FAIL(ObGeoTypeUtil::build_geometry(allocator, wkb, geo, srs, log_info, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { if (OB_ERR_GIS_INVALID_DATA == ret && OB_NOT_NULL(cast_name)) { LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, cast_name); } else if (OB_ERR_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE == ret && OB_NOT_NULL(cast_name)) { @@ -6334,9 +6339,10 @@ static int string_geometry(const ObObjType expect_type, ObObjCastParams ¶ms, ObString res_wkb; if (OB_FAIL(ObGeoTypeUtil::add_geo_version(temp_allocator, in_str, res_wkb))) { LOG_WARN("fail to add version", K(ret), K(dst_geo_type)); + } else if (OB_FAIL(set_geo_res(¶ms, &out, res_wkb))) { + LOG_WARN("set geo result failed", K(ret)); } else { - out.set_string(expect_type, res_wkb.ptr(), res_wkb.length()); - SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_wkb.length()); + SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, static_cast(out.get_string_len())); } } else if (OB_FAIL(geometry_geometry(expect_type, params, in, out, cast_mode))) { LOG_WARN("fail to cast geometry", K(ret), K(dst_geo_type)); @@ -7020,11 +7026,20 @@ ObCastEnumOrSetFunc OB_CAST_ENUM_OR_SET[ObMaxTC][2] = cast_not_support_enum_set,/*enum*/ cast_not_support_enum_set,/*set*/ }, + {/*ObUserDefinedSQLTC -> enum_or_set*/ + cast_not_support_enum_set,/*enum*/ + cast_not_support_enum_set,/*set*/ + }, { /*Decimalint -> enum_or_set*/ decimalint_enum,/*enum*/ decimalint_set,/*set*/ - } + }, + { + /*ObCollectionSQLTC -> enum_or_set*/ + cast_not_support_enum_set,/*enum*/ + cast_not_support_enum_set,/*set*/ + }, }; //////////////////////////////////////////////////////////// @@ -9310,7 +9325,32 @@ static int sql_udt_pl_extend(const ObObjType expect_type, ObObjCastParams ¶m data->set_collation_type(CS_TYPE_UTF8MB4_BIN); xmltype->set_data(data); out.set_extend(reinterpret_cast(xmltype), pl::PL_OPAQUE_TYPE); - // need deep copy? + } + } + } else if (in.is_user_defined_sql_type()) { + if (OB_ISNULL(params.exec_ctx_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("need execute ctx to get subschema map on phyplan ctx", K(ret), K(in)); + } else { + const uint16_t subschema_id = in.get_meta().get_subschema_id(); + ObSqlUDTMeta udt_meta; + // Notice: udt_type_id (accuray) does not exist in output obj meta, + // should set subschema_id on input obj_meta in code generation + if (OB_FAIL(sql::ObSqlUdtUtils::get_sqludt_meta_by_subschema_id(params.exec_ctx_, + subschema_id, + udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (udt_meta.pl_type_ == pl::PL_RECORD_TYPE || udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) { + ObString udt_data = in.get_string(); + if (OB_FAIL(sql::ObSqlUdtUtils::cast_sql_record_to_pl_record(params.exec_ctx_, + out, + udt_data, + udt_meta))) { + LOG_WARN("failed to cast sql collection to pl collection", K(ret), K(udt_meta.udt_id_)); + } + } else { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("inconsistent datatypes", K(ret), K(in), K(subschema_id), K(udt_meta.udt_id_)); } } } else { @@ -9395,8 +9435,10 @@ static int pl_extend_sql_udt(const ObObjType expect_type, ObObjCastParams ¶m const ObObj &in, ObObj &out, const ObCastMode cast_mode) { int ret = OB_SUCCESS; -#ifdef OB_BUILD_ORACLE_XML - if (in.is_pl_extend()) { +#ifdef OB_BUILD_ORACLE_PL + if (in.is_null()) { + out.set_null(); + } else if (in.is_pl_extend()) { if (pl::PL_OPAQUE_TYPE == in.get_meta().get_extend_type()) { pl::ObPLOpaque *pl_src = reinterpret_cast(in.get_ext()); if (OB_ISNULL(pl_src)) { @@ -9408,7 +9450,6 @@ static int pl_extend_sql_udt(const ObObjType expect_type, ObObjCastParams ¶m if (OB_ISNULL(blob_obj) || blob_obj->is_null()) { out.set_sql_udt("", 0, ObXMLSqlType); } else { - // deep copy here or by the caller ? ObString xml_data = blob_obj->get_string(); int64_t xml_data_size = xml_data.length(); char *xml_data_buff = static_cast(params.alloc(xml_data_size)); @@ -9428,6 +9469,69 @@ static int pl_extend_sql_udt(const ObObjType expect_type, ObObjCastParams ¶m ret = OB_ERR_UNEXPECTED; LOG_WARN("not expected obj type convert", K(ret), K(expect_type), K(in), K(out), K(cast_mode)); } + } else { + uint64_t udt_id; + uint16_t subschema_id; + ObSqlUDT sql_udt; + ObSqlUDTMeta udt_meta; + ObString res_str; + bool is_null_res = false; + if (pl::PL_RECORD_TYPE == in.get_meta().get_extend_type()) { + pl::ObPLRecord *pl_src = reinterpret_cast(in.get_ext()); + if (OB_ISNULL(pl_src)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("failed to get pl data type info", K(ret), K(in)); + } else if (pl_src->is_null()) { + is_null_res = true; + } else { + udt_id = pl_src->get_id(); + } + } else if (pl::PL_VARRAY_TYPE == in.get_meta().get_extend_type()) { + pl::ObPLVArray *pl_src = reinterpret_cast(in.get_ext()); + if (OB_ISNULL(pl_src)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("failed to get pl data type info", K(ret), K(in)); + } else if (pl_src->is_null()) { + is_null_res = true; + } else { + udt_id = pl_src->get_id(); + } + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported extend type", K(ret), K(in.get_meta().get_extend_type())); + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + out.set_null(); + } else if (OB_FAIL(params.exec_ctx_->get_subschema_id_by_udt_id(udt_id, subschema_id))) { + LOG_WARN("Failed to get subshcema_meta_info", K(ret), K(udt_id)); + } else if (OB_FAIL(sql::ObSqlUdtUtils::get_sqludt_meta_by_subschema_id(params.exec_ctx_, + subschema_id, + udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_meta.udt_id_)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("inconsistent datatypes", K(ret), K(in), K(subschema_id), K(udt_meta.udt_id_)); + } else if (FALSE_IT(sql_udt.set_udt_meta(udt_meta))) { + } else if (sql_udt.get_udt_meta().pl_type_ == pl::PL_VARRAY_TYPE) { // single varray + if (OB_FAIL(sql::ObSqlUdtUtils::cast_pl_varray_to_sql_varray(*params.allocator_v2_, res_str, in))) { + LOG_WARN("convert pl record to sql record failed", K(ret), K(subschema_id), K(udt_meta.udt_id_)); + } else { + out.set_sql_udt(res_str.ptr(), static_cast(res_str.length()), subschema_id); + } + } else { // record + if (OB_FAIL(sql::ObSqlUdtUtils::cast_pl_record_to_sql_record(*params.allocator_v2_, + *params.allocator_v2_, + params.exec_ctx_, + res_str, + sql_udt, + in))) { + LOG_WARN("convert pl record to sql record failed", + K(ret), K(subschema_id), K(udt_meta.udt_id_)); + } else { + out.set_sql_udt(res_str.ptr(), static_cast(res_str.length()), subschema_id); + } + } } } else { ret = OB_ERR_UNEXPECTED; @@ -9439,6 +9543,68 @@ static int pl_extend_sql_udt(const ObObjType expect_type, ObObjCastParams ¶m return ret; } +static int pl_extend_geometry(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; +#ifdef OB_BUILD_ORACLE_PL + ObLength res_length = -1; + ObIAllocator &temp_allocator = *params.allocator_v2_; + uint64_t tenant_id = MTL_ID(); + ObString res_wkb; + + if (in.is_null()) { + out.set_null(); + } else if (in.is_pl_extend() && pl::PL_RECORD_TYPE == in.get_meta().get_extend_type()) { + pl::ObPLRecord *pl_src = reinterpret_cast(in.get_ext()); + if (OB_ISNULL(pl_src)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("failed to get pl data type info", K(ret), K(in)); + } else if (pl_src->is_null()) { + out.set_null(); + } else if (pl_src->get_id() == T_OBJ_SDO_GEOMETRY) { + if (OB_FAIL(pl::ObSdoGeometry::pl_extend_to_wkb(&temp_allocator, const_cast(in), tenant_id, res_wkb))) { + LOG_WARN("failed to get geometry wkb from pl extend", K(ret), K(cast_mode)); + } else if (OB_FAIL(set_geo_res(¶ms, &out, res_wkb))) { + LOG_WARN("set geo result failed", K(ret)); + } else { + res_length = static_cast(out.get_string_len()); + } + SET_RES_ACCURACY_STRING(expect_type, DEFAULT_PRECISION_FOR_STRING, res_length); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected type to convert format", K(ret), K(expect_type), K(in)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected type to convert format", K(ret), K(expect_type), K(in)); + } +#else + ret = OB_NOT_SUPPORTED; +#endif + return ret; +} + +static int geometry_pl_extend(const ObObjType expect_type, ObObjCastParams ¶ms, + const ObObj &in, ObObj &out, const ObCastMode cast_mode) +{ + int ret = OB_SUCCESS; +#ifdef OB_BUILD_ORACLE_PL + ObString res_wkb = in.get_string(); + if (OB_ISNULL(params.exec_ctx_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("exec ctx is null", K(ret)); + } else if (OB_FAIL(sql::ObTextStringHelper::read_real_string_data(params.allocator_v2_, in, res_wkb))) { + LOG_WARN("fail to get real data.", K(ret), K(res_wkb)); + } else if (OB_FAIL(pl::ObSdoGeometry::wkb_to_pl_extend(params.exec_ctx_->get_allocator(), params.exec_ctx_, res_wkb, out))) { + LOG_WARN("failed to get geometry wkb from pl extend", K(ret), K(cast_mode)); + } +#else + ret = OB_NOT_SUPPORTED; +#endif + return ret; +} + static int pl_extend_string(const ObObjType expect_type, ObObjCastParams ¶ms, const ObObj &in, ObObj &out, const ObCastMode cast_mode) { @@ -10468,6 +10634,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_identity,/*geometry*/ cast_not_expected,/*udt, mysql mode does not have udt*/ cast_identity,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*int -> XXX*/ @@ -10497,6 +10664,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = int_geometry,/*geometry*/ cast_not_expected,/*udt*/ int_decimalint,/*decimal int*/ + cast_not_expected,/*collection*/ }, { /*uint -> XXX*/ @@ -10526,6 +10694,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = uint_geometry,/*geometry*/ cast_not_expected,/*udt*/ uint_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*float -> XXX*/ @@ -10555,6 +10724,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = float_geometry,/*geometry*/ cast_not_expected,/*udt*/ float_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*double -> XXX*/ @@ -10584,6 +10754,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = double_geometry,/*geometry*/ cast_not_expected,/*udt*/ double_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*number -> XXX*/ @@ -10613,6 +10784,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = number_geometry,/*geometry*/ cast_not_expected,/*udt*/ number_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*datetime -> XXX*/ @@ -10642,6 +10814,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = datetime_geometry,/*geometry*/ cast_not_expected,/*udt*/ datetime_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*date -> XXX*/ @@ -10671,6 +10844,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = date_geometry,/*geometry*/ cast_not_expected,/*udt*/ date_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*time -> XXX*/ @@ -10700,6 +10874,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = time_geometry,/*geometry*/ cast_not_expected,/*udt*/ time_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*year -> XXX*/ @@ -10729,6 +10904,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = year_geometry,/*geometry*/ cast_not_expected,/*udt*/ year_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*string -> XXX*/ @@ -10758,6 +10934,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = string_geometry,/*geometry*/ cast_not_expected,/*udt*/ string_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*extend -> XXX*/ @@ -10787,6 +10964,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ pl_extend_sql_udt,/*udt*/ cast_not_support,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*unknown -> XXX*/ @@ -10816,6 +10994,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ cast_not_expected,/*udt*/ unknown_other,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*text -> XXX*/ @@ -10845,6 +11024,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = string_geometry,/*geometry*/ cast_not_expected,/*udt*/ text_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*bit -> XXX*/ @@ -10874,6 +11054,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = bit_geometry,/*geometry*/ cast_not_expected,/*udt*/ bit_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*enum -> XXX*/ @@ -10903,6 +11084,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt*/ enumset_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*enumset_inner -> XXX*/ @@ -10932,6 +11114,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ cast_not_expected,/*udt*/ enumset_inner_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*otimestamp -> XXX*/ @@ -10961,6 +11144,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt*/ cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*raw -> XXX*/ @@ -10990,6 +11174,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt*/ cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*interval -> XXX*/ @@ -11019,6 +11204,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt*/ cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*rowid -> XXX*/ @@ -11048,6 +11234,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt*/ cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*lob -> XXX*/ @@ -11077,6 +11264,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = lob_geometry,/*geometry*/ cast_not_expected,/*udt*/ lob_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*json -> XXX*/ @@ -11106,6 +11294,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = json_geometry,/*geometry*/ cast_not_expected,/*udt*/ json_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*geometry -> XXX*/ @@ -11135,6 +11324,7 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = geometry_geometry,/*geometry*/ cast_not_expected,/*udt*/ geometry_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ }, { /*udt -> XXX*/ @@ -11193,6 +11383,37 @@ ObObjCastFunc OB_OBJ_CAST[ObMaxTC][ObMaxTC] = decimalint_geometry,/*geometry*/ cast_not_expected, /*udt*/ decimalint_decimalint,/*decimalint*/ + cast_not_expected,/*collection*/ + }, + { + /*collection-> xxx*/ + cast_not_expected,/*null*/ + cast_not_expected,/*int*/ + cast_not_expected,/*uint*/ + cast_not_expected,/*float*/ + cast_not_expected,/*double*/ + cast_not_expected,/*number*/ + cast_not_expected,/*datetime*/ + cast_not_expected,/*date*/ + cast_not_expected,/*time*/ + cast_not_expected,/*year*/ + cast_not_expected,/*string*/ + cast_not_expected,/*extend*/ + cast_not_expected,/*unknown*/ + cast_not_expected,/*text*/ + cast_not_expected,/*bit*/ + cast_not_expected,/*enumset*/ + cast_not_expected,/*enumset_inner*/ + cast_not_expected,/*otimestamp*/ + cast_not_expected,/*raw*/ + cast_not_expected,/*interval*/ + cast_not_expected,/*rowid*/ + cast_not_expected,/*lob*/ + cast_not_expected,/*json*/ + cast_not_expected,/*geometry*/ + cast_not_expected, /*udt*/ + cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection*/ } }; @@ -11226,6 +11447,7 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_identity,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*int -> XXX*/ @@ -11252,9 +11474,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json not support oracle yet*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ int_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*uint -> XXX*/ @@ -11281,9 +11504,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/* json */ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ uint_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*float -> XXX*/ @@ -11310,9 +11534,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json */ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ float_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*double -> XXX*/ @@ -11339,9 +11564,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json */ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ double_decimalint, /*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*number -> XXX*/ @@ -11368,9 +11594,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json */ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ number_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*datetime -> XXX*/ @@ -11397,9 +11624,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json */ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*date -> XXX*/ @@ -11429,6 +11657,7 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ // geometry not support oracle mode now cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*time -> XXX*/ @@ -11455,9 +11684,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json */ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*year -> XXX*/ @@ -11484,9 +11714,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/* json */ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*string -> XXX*/ @@ -11513,9 +11744,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = string_rowid,/*rowid*/ cast_inconsistent_types,/*lob*/ string_json,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ string_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*extend -> XXX*/ @@ -11542,9 +11774,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_not_support,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + pl_extend_geometry,/*geometry*/ pl_extend_sql_udt,/*udt*/ cast_not_support,/*decimalint*/ + pl_extend_sql_udt,/*collection*/ }, { /*unknown -> XXX*/ @@ -11571,9 +11804,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = unknown_other,/*rowid*/ cast_not_support,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_not_support,/*geometry*/ cast_to_udt_not_support,/*udt*/ unknown_other,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*text -> XXX*/ @@ -11600,9 +11834,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ text_json,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ text_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*bit -> XXX*/ @@ -11629,9 +11864,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*enum -> XXX*/ @@ -11658,9 +11894,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*enumset_inner -> XXX*/ @@ -11687,9 +11924,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*otimestamp -> XXX*/ @@ -11716,9 +11954,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*raw -> XXX*/ @@ -11745,9 +11984,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*interval -> XXX*/ @@ -11774,9 +12014,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*rowid -> XXX*/ @@ -11803,9 +12044,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = rowid_rowid,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*lob -> XXX*/ @@ -11832,9 +12074,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ lob_json,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ lob_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*json -> XXX, not support oracle currently*/ @@ -11861,9 +12104,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ json_lob,/*lob*/ json_json,/*json*/ - cast_not_support,/*geometry*/ // geometry not support oracle mode now + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*geometry -> XXX, not support oracle currently*/ @@ -11878,7 +12122,7 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*time*/ cast_not_support,/*year*/ cast_not_support,/*string*/ - cast_not_support,/*extend*/ + geometry_pl_extend,/*extend*/ cast_not_support,/*unknown*/ cast_not_support,/*text*/ cast_not_support,/*bit*/ @@ -11890,9 +12134,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_not_support,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ + geometry_geometry,/*geometry*/ cast_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_not_support,/*collection*/ }, { /*udt -> XXX, not support oracle currently*/ @@ -11922,6 +12167,7 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_udt_to_other_not_support,/*geometry*/ cast_udt_to_other_not_support,/*udt*/ cast_udt_to_other_not_support,/*decimal int*/ + cast_udt_to_other_not_support,/*collection*/ }, { /*decimalint -> XXX*/ @@ -11951,8 +12197,38 @@ ObObjCastFunc OBJ_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ cast_to_udt_not_support, /*udt*/ decimalint_decimalint,/*decimalint*/ - } - + cast_to_udt_not_support, /*collection*/ + }, + { + /*collection -> XXX*/ + cast_udt_to_other_not_support,/*null*/ + cast_udt_to_other_not_support,/*int*/ + cast_udt_to_other_not_support,/*uint*/ + cast_udt_to_other_not_support,/*float*/ + cast_udt_to_other_not_support,/*double*/ + cast_udt_to_other_not_support,/*number*/ + cast_udt_to_other_not_support,/*datetime*/ + cast_udt_to_other_not_support,/*date*/ + cast_udt_to_other_not_support,/*time*/ + cast_udt_to_other_not_support,/*year*/ + udt_string,/*string*/ + sql_udt_pl_extend,/*extend*/ + cast_udt_to_other_not_support,/*unknown*/ + cast_udt_to_other_not_support,/*text*/ + cast_udt_to_other_not_support,/*bit*/ + cast_udt_to_other_not_support,/*enumset*/ + cast_udt_to_other_not_support,/*enumset_inner*/ + cast_udt_to_other_not_support,/*otimestamp*/ + cast_udt_to_other_not_support,/*raw*/ + cast_udt_to_other_not_support,/*interval*/ + cast_udt_to_other_not_support,/*rowid*/ + cast_udt_to_other_not_support,/*lob*/ + cast_udt_to_other_not_support,/*json*/ + cast_udt_to_other_not_support,/*geometry*/ + cast_udt_to_other_not_support,/*udt*/ + cast_not_expected,/*decimalint*/ + cast_udt_to_other_not_support,/*collection*/ + }, }; /* @@ -11991,9 +12267,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_identity, /*rowid*/ cast_identity,/*lob*/ cast_identity,/*json*/ - cast_not_support,/*geometry*/ + cast_identity,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_identity,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*int -> XXX*/ @@ -12020,9 +12297,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ int_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*uint -> XXX*/ @@ -12049,9 +12327,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ uint_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*float -> XXX*/ @@ -12078,9 +12357,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ float_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*double -> XXX*/ @@ -12107,9 +12387,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ double_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*number -> XXX*/ @@ -12136,9 +12417,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ number_lob,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ number_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*datetime -> XXX*/ @@ -12165,9 +12447,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*date -> XXX*/ @@ -12194,9 +12477,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*time -> XXX*/ @@ -12223,9 +12507,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*year -> XXX*/ @@ -12252,9 +12537,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*string -> XXX*/ @@ -12281,9 +12567,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = string_rowid,/*rowid*/ string_lob,/*lob*/ string_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ string_sql_udt,/*udt*/ string_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*extend -> XXX*/ @@ -12310,9 +12597,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_extend_types_not_support,/*lob*/ cast_inconsistent_type_json_explicit,/*json*/ - cast_not_support,/*geometry*/ + pl_extend_geometry,/*geometry*/ pl_extend_sql_udt,/*udt*/ cast_not_expected,/*decimalint*/ + pl_extend_sql_udt,/*collection*/ }, { /*unknown -> XXX*/ @@ -12339,9 +12627,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*text -> XXX*/ @@ -12368,9 +12657,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = text_rowid,/*rowid*/ text_lob,/*lob*/ text_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ text_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*bit -> XXX*/ @@ -12397,9 +12687,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*enum -> XXX*/ @@ -12426,9 +12717,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*enumset_inner -> XXX*/ @@ -12458,6 +12750,7 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*otimestamp -> XXX*/ @@ -12484,9 +12777,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*raw -> XXX*/ @@ -12513,9 +12807,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ raw_lob,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*interval -> XXX*/ @@ -12542,9 +12837,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /* rowid -> XXX */ @@ -12571,9 +12867,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = rowid_rowid,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*lob -> XXX*/ @@ -12600,9 +12897,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = lob_rowid,/*rowid*/ lob_lob,/*lob*/ lob_json,/*json*/ - cast_not_support,/*geometry*/ + lob_geometry,/*geometry*/ cast_to_udt_not_support,/*udt*/ lob_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*json -> XXX*/ @@ -12629,9 +12927,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ json_lob,/*lob*/ json_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*geoemtry -> XXX, not support oracle currently*/ @@ -12646,7 +12945,7 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*time*/ cast_not_support,/*year*/ cast_not_support,/*string*/ - cast_not_support,/*extend*/ + geometry_pl_extend,/*extend*/ cast_not_support,/*unknown*/ cast_not_support,/*text*/ cast_not_support,/*bit*/ @@ -12658,9 +12957,10 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_not_support,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ + geometry_geometry,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*udt -> XXX*/ @@ -12690,6 +12990,7 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_udt_to_other_not_support,/*geometry*/ cast_udt_to_other_not_support,/*udt*/ cast_udt_to_other_not_support,/*decimal int*/ + cast_udt_to_other_not_support,/*collection*/ }, { /*decimalint -> XXX*/ @@ -12716,10 +13017,41 @@ ObObjCastFunc OBJ_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ decimalint_lob,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support, /* udt */ decimalint_decimalint,/*decimalint*/ - } + cast_to_udt_not_support,/*collection*/ + }, + { + /*collection -> XXX*/ + cast_udt_to_other_not_support,/*null*/ + cast_udt_to_other_not_support,/*int*/ + cast_udt_to_other_not_support,/*uint*/ + cast_udt_to_other_not_support,/*float*/ + cast_udt_to_other_not_support,/*double*/ + cast_udt_to_other_not_support,/*number*/ + cast_udt_to_other_not_support,/*datetime*/ + cast_udt_to_other_not_support,/*date*/ + cast_udt_to_other_not_support,/*time*/ + cast_udt_to_other_not_support,/*year*/ + udt_string,/*string*/ + sql_udt_pl_extend,/*extend*/ + cast_udt_to_other_not_support,/*unknown*/ + cast_udt_to_other_not_support,/*text*/ + cast_udt_to_other_not_support,/*bit*/ + cast_udt_to_other_not_support,/*enumset*/ + cast_udt_to_other_not_support,/*enumset_inner*/ + cast_udt_to_other_not_support,/*otimestamp*/ + cast_udt_to_other_not_support,/*raw*/ + cast_udt_to_other_not_support,/*interval*/ + cast_udt_to_other_not_support,/*rowid*/ + cast_udt_to_other_not_support,/*lob*/ + cast_udt_to_other_not_support,/*json*/ + cast_udt_to_other_not_support,/*geometry*/ + cast_udt_to_other_not_support,/*udt*/ + cast_udt_to_other_not_support,/*decimalint*/ + cast_udt_to_other_not_support,/*collection*/ + }, }; //////////////////////////////////////////////////////////////// diff --git a/src/share/object/ob_obj_cast.h b/src/share/object/ob_obj_cast.h index d1325473fb..51a77cc824 100644 --- a/src/share/object/ob_obj_cast.h +++ b/src/share/object/ob_obj_cast.h @@ -171,7 +171,8 @@ struct ObObjCastParams res_accuracy_(NULL), dtc_params_(), format_number_with_limit_(true), - is_ignore_(false) + is_ignore_(false), + exec_ctx_(NULL) { set_compatible_cast_mode(); } @@ -190,7 +191,8 @@ struct ObObjCastParams res_accuracy_(res_accuracy), dtc_params_(), format_number_with_limit_(true), - is_ignore_(false) + is_ignore_(false), + exec_ctx_(NULL) { set_compatible_cast_mode(); if (NULL != dtc_params) { @@ -214,7 +216,8 @@ struct ObObjCastParams res_accuracy_(res_accuracy), dtc_params_(), format_number_with_limit_(true), - is_ignore_(false) + is_ignore_(false), + exec_ctx_(NULL) { set_compatible_cast_mode(); if (NULL != dtc_params) { @@ -270,6 +273,7 @@ struct ObObjCastParams ObDataTypeCastParams dtc_params_; bool format_number_with_limit_; bool is_ignore_; + sql::ObExecContext *exec_ctx_; }; class ObExpectType diff --git a/src/share/schema/ob_column_schema.h b/src/share/schema/ob_column_schema.h index 8d7f032e2d..9fdbf81dc7 100644 --- a/src/share/schema/ob_column_schema.h +++ b/src/share/schema/ob_column_schema.h @@ -201,7 +201,8 @@ int assign(const ObColumnSchemaV2 &src_schema); } inline bool is_extend() const { return meta_type_.is_ext() || meta_type_.is_user_defined_sql_type(); } inline bool is_udt_hidden_column() const { return get_udt_set_id() > 0 && is_hidden(); } - inline bool is_udt_related_column() const { return is_extend() || is_udt_hidden_column(); } + inline bool is_udt_related_column(bool is_oracle_mode) const { return is_extend() || is_udt_hidden_column() || + (is_oracle_mode && is_geometry()); } inline common::ObCharsetType get_charset_type() const { return charset_type_; } inline common::ObCollationType get_collation_type() const { return meta_type_.get_collation_type(); } inline const common::ObObj &get_orig_default_value() const { return orig_default_value_; } diff --git a/src/share/schema/ob_table_schema.cpp b/src/share/schema/ob_table_schema.cpp index d0fca24d2e..270c2ab391 100644 --- a/src/share/schema/ob_table_schema.cpp +++ b/src/share/schema/ob_table_schema.cpp @@ -2873,7 +2873,7 @@ ObColumnSchemaV2* ObTableSchema::get_xml_hidden_column_schema(uint64_t column_id } int ObTableSchema::get_column_schema_in_same_col_group(uint64_t column_id, uint64_t udt_set_id, - common::ObSEArray &column_group) const + common::ObIArray &column_group) const { int ret = OB_SUCCESS; for (int64_t i = 0; udt_set_id > 0 && OB_SUCC(ret) && i < column_cnt_; ++i) { diff --git a/src/share/schema/ob_table_schema.h b/src/share/schema/ob_table_schema.h index 0cc32fc84e..5db974379d 100644 --- a/src/share/schema/ob_table_schema.h +++ b/src/share/schema/ob_table_schema.h @@ -1601,7 +1601,7 @@ public: int get_column_schema_in_same_col_group(uint64_t column_id, uint64_t udt_set_id, - common::ObSEArray &column_group) const; + common::ObIArray &column_group) const; ObColumnSchemaV2* get_xml_hidden_column_schema(uint64_t column_id, uint64_t udt_set_id) const; bool is_same_type_category(const ObColumnSchemaV2 &src_column, const ObColumnSchemaV2 &dst_column) const; diff --git a/src/share/schema/ob_table_sql_service.cpp b/src/share/schema/ob_table_sql_service.cpp index 04ebad4397..dbbe3d312c 100644 --- a/src/share/schema/ob_table_sql_service.cpp +++ b/src/share/schema/ob_table_sql_service.cpp @@ -4056,8 +4056,18 @@ int ObTableSqlService::gen_column_dml( ObArenaAllocator allocator(ObModIds::OB_SCHEMA_OB_SCHEMA_ARENA); char *extended_type_info_buf = NULL; uint64_t tenant_data_version = 0; + lib::Worker::CompatMode compat_mode = lib::Worker::CompatMode::INVALID; if (OB_FAIL(GET_MIN_DATA_VERSION(exec_tenant_id, tenant_data_version))) { LOG_WARN("get tenant data version failed", K(ret)); + } else if (OB_FAIL(ObCompatModeGetter::get_table_compat_mode( + column.get_tenant_id(), column.get_table_id(), compat_mode))) { + LOG_WARN("fail to get tenant mode", K(ret), K(column)); + } else if ((tenant_data_version < DATA_VERSION_4_2_2_0 + || (tenant_data_version >= DATA_VERSION_4_3_0_0 && tenant_data_version < DATA_VERSION_4_3_1_0)) && + column.is_geometry() && compat_mode ==lib::Worker::CompatMode::ORACLE) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("sdo_geometry is not supported when data_version is below 4.2.2.0 or data version is above 4.3.0.0 but below 4.3.1.0", K(ret), K(tenant_data_version), K(column)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "tenant data version is less than 4.2.2 or data version is above 4.3.0.0 but below 4.3.1.0, sdo_geometry"); } else if (tenant_data_version < DATA_VERSION_4_2_0_0 && (column.is_xmltype() || column.get_udt_set_id() != 0 || column.get_sub_data_type() != 0)) { ret = OB_NOT_SUPPORTED; @@ -4108,15 +4118,11 @@ int ObTableSqlService::gen_column_dml( orig_default_value_buf = static_cast(allocator.alloc(value_buf_len)); cur_default_value_buf = static_cast(allocator.alloc(value_buf_len)); extended_type_info_buf = static_cast(allocator.alloc(OB_MAX_VARBINARY_LENGTH)); - lib::Worker::CompatMode compat_mode = lib::Worker::CompatMode::INVALID; if (OB_ISNULL(orig_default_value_buf) || OB_ISNULL(cur_default_value_buf) || OB_ISNULL(extended_type_info_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory for default value buffer failed"); - } else if (OB_FAIL(ObCompatModeGetter::get_table_compat_mode( - column.get_tenant_id(), column.get_table_id(), compat_mode))) { - LOG_WARN("fail to get tenant mode", K(ret), K(column)); } else { MEMSET(orig_default_value_buf, 0, value_buf_len); MEMSET(cur_default_value_buf, 0, value_buf_len); @@ -4215,7 +4221,6 @@ int ObTableSqlService::gen_column_dml( || OB_FAIL(dml.add_column("extended_type_info", ObHexEscapeSqlStr(bin_extended_type_info))) || OB_FAIL(dml.add_column("prev_column_id", column.get_prev_column_id())) || (tenant_data_version >= DATA_VERSION_4_1_0_0 && OB_FAIL(dml.add_column("srs_id", column.get_srs_id()))) - // todo : tenant_data_version >= DATA_VERSION_4_2_0_0 || (tenant_data_version >= DATA_VERSION_4_2_0_0 && OB_FAIL(dml.add_column("udt_set_id", column.get_udt_set_id()))) || (tenant_data_version >= DATA_VERSION_4_2_0_0 &&OB_FAIL(dml.add_column("sub_data_type", column.get_sub_data_type()))) || (tenant_data_version >= DATA_VERSION_4_3_0_0 diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt index cba4b560bc..c77758bcf1 100644 --- a/src/sql/CMakeLists.txt +++ b/src/sql/CMakeLists.txt @@ -672,6 +672,7 @@ ob_set_subtarget(ob_sql engine_expr engine/expr/ob_expr_sql_mode_convert.cpp engine/expr/ob_expr_prefix_pattern.cpp engine/expr/ob_expr_sys_makexml.cpp + engine/expr/ob_expr_xml_func_helper.cpp engine/expr/ob_expr_xmlparse.cpp engine/expr/ob_expr_xml_element.cpp engine/expr/ob_expr_xml_attributes.cpp @@ -681,6 +682,29 @@ ob_set_subtarget(ob_sql engine_expr engine/expr/ob_expr_extract_xml.cpp engine/expr/ob_expr_xmlcast.cpp engine/expr/ob_expr_update_xml.cpp + engine/expr/ob_expr_sql_udt_utils.cpp + engine/expr/ob_expr_temp_table_ssid.cpp + engine/expr/ob_expr_collection_construct.cpp + engine/expr/ob_expr_sql_udt_construct.cpp + engine/expr/ob_expr_priv_attribute_access.cpp + engine/expr/ob_expr_priv_st_numinteriorrings.cpp + engine/expr/ob_expr_priv_st_iscollection.cpp + engine/expr/ob_expr_priv_st_equals.cpp + engine/expr/ob_expr_priv_st_touches.cpp + engine/expr/ob_expr_priv_st_makeenvelope.cpp + engine/expr/ob_expr_priv_st_clipbybox2d.cpp + engine/expr/ob_expr_priv_st_pointonsurface.cpp + engine/expr/ob_expr_priv_st_geometrytype.cpp + engine/expr/ob_expr_st_crosses.cpp + engine/expr/ob_expr_st_overlaps.cpp + engine/expr/ob_expr_st_union.cpp + engine/expr/ob_expr_st_length.cpp + engine/expr/ob_expr_st_difference.cpp + engine/expr/ob_expr_st_asgeojson.cpp + engine/expr/ob_expr_st_centroid.cpp + engine/expr/ob_expr_st_symdifference.cpp + engine/expr/ob_expr_priv_st_asmvtgeom.cpp + engine/expr/ob_expr_priv_st_makevalid.cpp engine/expr/ob_expr_temp_table_ssid.cpp engine/expr/vector_cast/vector_cast.cpp engine/expr/ob_expr_extract_cert_expired_time.cpp @@ -1241,6 +1265,7 @@ ob_set_subtarget(ob_sql rewrite rewrite/ob_transform_subquery_coalesce.cpp rewrite/ob_transform_temp_table.cpp rewrite/ob_transform_utils.cpp + rewrite/ob_transform_udt_utils.cpp rewrite/ob_transform_view_merge.cpp rewrite/ob_transform_where_subquery_pullup.cpp rewrite/ob_transform_win_magic.cpp diff --git a/src/sql/code_generator/ob_expr_generator_impl.cpp b/src/sql/code_generator/ob_expr_generator_impl.cpp index fdabf9175b..51d724b9ec 100644 --- a/src/sql/code_generator/ob_expr_generator_impl.cpp +++ b/src/sql/code_generator/ob_expr_generator_impl.cpp @@ -44,6 +44,8 @@ #include "sql/engine/expr/ob_expr_cast.h" #include "sql/engine/expr/ob_expr_calc_partition_id.h" #include "sql/engine/expr/ob_pl_expr_subquery.h" +#include "sql/engine/expr/ob_expr_sql_udt_construct.h" +#include "sql/engine/expr/ob_expr_priv_attribute_access.h" namespace oceanbase { @@ -661,6 +663,15 @@ int ObExprGeneratorImpl::visit_simple_op(ObNonTerminalRawExpr &expr) LOG_DEBUG("cast debug, explicit or implicit", K(ret), K(is_implicit)); break; } + case T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT: { + ObExprUdtConstruct *object_op = static_cast(op); + ret = visit_sql_udt_construct_expr(expr, object_op); + break; + } + case T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS: { + ObExprUDTAttributeAccess *access_op = static_cast(op); + ret = visit_sql_udt_attr_access_expr(expr, access_op); + } default: { break; } @@ -1481,6 +1492,33 @@ int ObExprGeneratorImpl::visit_pl_assoc_index_expr(ObOpRawExpr &expr, return ret; } +int ObExprGeneratorImpl::visit_sql_udt_construct_expr(ObRawExpr &expr, + ObExprUdtConstruct *udt_construct) +{ + int ret = OB_SUCCESS; + ObUDTConstructorRawExpr &udt_raw_expr = static_cast(expr); + CK (OB_NOT_NULL(udt_construct)); + OX (udt_construct->set_udt_id(udt_raw_expr.get_udt_id())); + OX (udt_construct->set_root_udt_id(udt_raw_expr.get_root_udt_id())); + OX (udt_construct->set_attribute_pos(udt_raw_expr.get_attribute_pos())); + OX (udt_construct->set_real_param_num(static_cast(udt_raw_expr.get_param_count()))); + OX (udt_construct->set_row_dimension(ObExprOperator::NOT_ROW_DIMENSION)); + return ret; +} + +int ObExprGeneratorImpl::visit_sql_udt_attr_access_expr(ObRawExpr &expr, + ObExprUDTAttributeAccess *udt_attr_access) +{ + int ret = OB_SUCCESS; + ObUDTAttributeAccessRawExpr &udt_raw_expr = static_cast(expr); + CK (OB_NOT_NULL(udt_attr_access)); + OX (udt_attr_access->set_udt_id(udt_raw_expr.get_udt_id())); + OX (udt_attr_access->set_attribute_type(udt_raw_expr.get_attribute_type())); + OX (udt_attr_access->set_real_param_num(static_cast(udt_raw_expr.get_param_count()))); + OX (udt_attr_access->set_row_dimension(ObExprOperator::NOT_ROW_DIMENSION)); + return ret; +} + int ObExprGeneratorImpl::visit(ObOpRawExpr &expr) { int ret = OB_SUCCESS; @@ -1563,6 +1601,12 @@ int ObExprGeneratorImpl::visit(ObOpRawExpr &expr) } else if (T_FUN_PL_OBJECT_CONSTRUCT == expr.get_expr_type()) { ObExprObjectConstruct *object = static_cast(op); ret = visit_pl_object_construct_expr(expr, object); + } else if (T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT == expr.get_expr_type()) { + ObExprUdtConstruct *object_op = static_cast(op); + ret = visit_sql_udt_construct_expr(expr, object_op); + } else if (T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS == expr.get_expr_type()) { + ObExprUDTAttributeAccess *access_op = static_cast(op); + ret = visit_sql_udt_attr_access_expr(expr, access_op); } else { op->set_real_param_num(static_cast(expr.get_param_count())); op->set_row_dimension(ObExprOperator::NOT_ROW_DIMENSION); diff --git a/src/sql/code_generator/ob_expr_generator_impl.h b/src/sql/code_generator/ob_expr_generator_impl.h index 96b0aca97a..10196bfe05 100644 --- a/src/sql/code_generator/ob_expr_generator_impl.h +++ b/src/sql/code_generator/ob_expr_generator_impl.h @@ -48,7 +48,8 @@ class ObExprCollectionConstruct; class ObExprObjectConstruct; class ObExprCalcPartitionId; class ObExprOpSubQueryInPl; - +class ObExprUdtConstruct; +class ObExprUDTAttributeAccess; typedef common::ObSEArray PhyIterExprDesc; class ObExprGeneratorImpl: public ObExprGenerator, public ObRawExprVisitor @@ -132,6 +133,8 @@ private: inline int visit_pl_object_construct_expr(ObRawExpr &expr, ObExprObjectConstruct *pl_object_construct); inline int visit_pl_get_cursor_attr_expr( ObRawExpr &expr, ObExprPLGetCursorAttr *pl_get_cursor_attr); + inline int visit_sql_udt_construct_expr(ObRawExpr &expr, ObExprUdtConstruct *udt_construct); + inline int visit_sql_udt_attr_access_expr(ObRawExpr &expr, ObExprUDTAttributeAccess *udt_attr_access); // %item_pos is the position of %raw_expr (infix expr item) in infix_expr_.exprs_ array. int add_child_infix_expr(ObRawExpr &raw_expr, const int64_t item_pos, diff --git a/src/sql/code_generator/ob_static_engine_cg.cpp b/src/sql/code_generator/ob_static_engine_cg.cpp index 12e14b0eac..325f4eb79e 100644 --- a/src/sql/code_generator/ob_static_engine_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_cg.cpp @@ -1176,6 +1176,9 @@ int ObStaticEngineCG::generate_spec( } else if (is_oracle_mode() && OB_UNLIKELY(ObJsonType == raw_expr->get_data_type())) { ret = OB_ERR_INVALID_CMP_OP; LOG_WARN("select distinct json not allowed", K(ret)); + } else if (is_oracle_mode() && OB_UNLIKELY(ObGeometryType == raw_expr->get_data_type())) { + ret = OB_ERR_COMPARE_VARRAY_LOB_ATTR; + LOG_WARN("select distinct geometry not allowed", K(ret)); } else if (raw_expr->is_const_expr()) { // distinct const value, 这里需要注意:distinct 1被跳过了, // 但ObMergeDistinct中,如果没有distinct列,则默认所有值都相等,这个语义正好是符合预期的。 @@ -8040,6 +8043,18 @@ int ObStaticEngineCG::set_other_properties(const ObLogPlan &log_plan, ObPhysical } } #endif + // assgin subschema ctx + if (OB_SUCC(ret) + && (plan_ctx->get_subschema_ctx().is_inited() + && plan_ctx->get_subschema_ctx().get_subschema_count() > 0)) { + if (phy_plan.get_subschema_ctx_for_update().get_subschema_count() > 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("subschema ctx overwrite", K(ret)); + } else if (OB_FAIL(phy_plan.get_subschema_ctx_for_update().assgin(plan_ctx->get_subschema_ctx()))) { + LOG_WARN("fail to assgin subschema ctx", K(ret)); + } + } + if (OB_SUCC(ret)) { if (OB_ISNULL(log_plan.get_stmt())) { ret = OB_ERR_UNEXPECTED; diff --git a/src/sql/code_generator/ob_static_engine_expr_cg.cpp b/src/sql/code_generator/ob_static_engine_expr_cg.cpp index 965f96e5a0..781debe8aa 100644 --- a/src/sql/code_generator/ob_static_engine_expr_cg.cpp +++ b/src/sql/code_generator/ob_static_engine_expr_cg.cpp @@ -278,9 +278,14 @@ int ObStaticEngineExprCG::cg_expr_basic(const ObIArray &raw_exprs) rt_expr->obj_meta_ = result_meta; // pl extend type has its own explanation for scale if (ObExtendType != rt_expr->obj_meta_.get_type() - && ObUserDefinedSQLType != rt_expr->obj_meta_.get_type()) { + && ObUserDefinedSQLType != rt_expr->obj_meta_.get_type() + && ObCollectionSQLType != rt_expr->obj_meta_.get_type()) { rt_expr->obj_meta_.set_scale(rt_expr->datum_meta_.scale_); } + if (result_meta.is_xml_sql_type()) { + // set xml subschema id = ObXMLSqlType + rt_expr->datum_meta_.cs_type_ = CS_TYPE_INVALID; + } if (is_lob_storage(rt_expr->obj_meta_.get_type())) { if (cur_cluster_version_ >= CLUSTER_VERSION_4_1_0_0) { rt_expr->obj_meta_.set_has_lob_header(); diff --git a/src/sql/engine/aggregate/ob_aggregate_processor.cpp b/src/sql/engine/aggregate/ob_aggregate_processor.cpp index 25784af68e..b2d07cded2 100644 --- a/src/sql/engine/aggregate/ob_aggregate_processor.cpp +++ b/src/sql/engine/aggregate/ob_aggregate_processor.cpp @@ -1983,6 +1983,7 @@ int ObAggregateProcessor::generate_group_row(GroupRow *&new_group_row, case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_OBJECTAGG: case T_FUN_ORA_XMLAGG: + case T_FUN_SYS_ST_ASMVT: { void *tmp_buf = NULL; set_need_advance_collect(); @@ -2185,6 +2186,7 @@ int ObAggregateProcessor::fill_group_row(GroupRow *new_group_row, case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_OBJECTAGG: case T_FUN_ORA_XMLAGG: + case T_FUN_SYS_ST_ASMVT: { void *tmp_buf = NULL; set_need_advance_collect(); @@ -2620,6 +2622,7 @@ int ObAggregateProcessor::rollup_aggregation(AggrCell &aggr_cell, AggrCell &roll case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_OBJECTAGG: case T_FUN_ORA_XMLAGG: + case T_FUN_SYS_ST_ASMVT: { GroupConcatExtraResult *aggr_extra = NULL; GroupConcatExtraResult *rollup_extra = NULL; @@ -2899,6 +2902,7 @@ int ObAggregateProcessor::prepare_aggr_result(const ObChunkDatumStore::StoredRow case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_OBJECTAGG: case T_FUN_ORA_XMLAGG: + case T_FUN_SYS_ST_ASMVT: { GroupConcatExtraResult *extra = NULL; if (OB_ISNULL(extra = static_cast(aggr_cell.get_extra()))) { @@ -3212,6 +3216,7 @@ int ObAggregateProcessor::process_aggr_batch_result( case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_OBJECTAGG: case T_FUN_ORA_XMLAGG: + case T_FUN_SYS_ST_ASMVT: { GroupConcatExtraResult *extra_info = NULL; if (OB_ISNULL(extra_info = static_cast(aggr_cell.get_extra()))) { @@ -3474,6 +3479,7 @@ int ObAggregateProcessor::process_aggr_result(const ObChunkDatumStore::StoredRow case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_OBJECTAGG: case T_FUN_ORA_XMLAGG: + case T_FUN_SYS_ST_ASMVT: { GroupConcatExtraResult *extra = NULL; if (OB_ISNULL(extra = static_cast(aggr_cell.get_extra()))) { @@ -3865,6 +3871,14 @@ int ObAggregateProcessor::collect_aggr_result( break; } + case T_FUN_SYS_ST_ASMVT: { + GroupConcatExtraResult *extra = static_cast(aggr_cell.get_extra()); + if (OB_FAIL(get_asmvt_result(aggr_info, extra, result))) { + LOG_WARN("failed to get asmvt result", K(ret)); + } else { + } + break; + } case T_FUN_GROUP_CONCAT: { GroupConcatExtraResult *extra = NULL; ObString sep_str; @@ -8005,6 +8019,227 @@ int ObAggregateProcessor::fast_single_row_agg_batch(ObEvalCtx &eval_ctx, const i return ret; } +int ObAggregateProcessor::get_asmvt_result(const ObAggrInfo &aggr_info, + GroupConcatExtraResult *&extra, + ObDatum &concat_result) +{ + int ret = OB_SUCCESS; + common::ObArenaAllocator tmp_alloc(ObModIds::OB_SQL_AGGR_FUNC, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + if (OB_ISNULL(extra) || OB_UNLIKELY(extra->empty())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unpexcted null", K(ret), K(extra)); + } else if (extra->is_iterated() && OB_FAIL(extra->rewind())) { + // Group concat row may be iterated in rollup_process(), rewind here. + LOG_WARN("rewind failed", KPC(extra), K(ret)); + } else if (!extra->is_iterated() && OB_FAIL(extra->finish_add_row())) { + LOG_WARN("finish_add_row failed", KPC(extra), K(ret)); + } else { + const ObChunkDatumStore::StoredRow *storted_row = NULL; + bool inited_tmp_obj = false; + ObObj *tmp_obj = NULL; + mvt_agg_result mvt_res(tmp_alloc); + while (OB_SUCC(ret) && OB_SUCC(extra->get_next_row(storted_row))) { + if (OB_ISNULL(storted_row)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(storted_row)); + } else { + common::ObArenaAllocator single_row_alloc(ObModIds::OB_SQL_AGGR_FUNC, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + // get obj + if (!inited_tmp_obj + && OB_ISNULL(tmp_obj = static_cast(tmp_alloc.alloc(sizeof(ObObj) * (storted_row->cnt_))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory", K(ret), K(tmp_obj)); + } else if (!inited_tmp_obj && FALSE_IT(inited_tmp_obj = true)) { + } else if (OB_FAIL(convert_datum_to_obj(aggr_info, *storted_row, tmp_obj, storted_row->cnt_))) { + LOG_WARN("failed to convert datum to obj", K(ret)); + } else if (!mvt_res.is_inited() + && OB_FAIL(init_asmvt_result(tmp_alloc, aggr_info, tmp_obj, storted_row->cnt_, mvt_res))) { + LOG_WARN("failed to init asmvt result", K(ret)); + } else if (FALSE_IT(mvt_res.set_tmp_allocator(&single_row_alloc))) { + } else if (OB_FAIL(mvt_res.generate_feature(tmp_obj, storted_row->cnt_))) { + LOG_WARN("failed to generate mvt feature", K(ret)); + } + } + }//end of while + + if (ret != OB_ITER_END && ret != OB_SUCCESS) { + LOG_WARN("fail to get next row", K(ret)); + } else { + ret = OB_SUCCESS; + ObString mvt_str; + if (OB_FAIL(mvt_res.mvt_pack(mvt_str))) { + LOG_WARN("fail to pack mvt result", K(ret)); + } else { + ObString blob_locator; + ObExprStrResAlloc expr_res_alloc(*aggr_info.expr_, eval_ctx_); + ObTextStringResult blob_res(ObLongTextType, true, &expr_res_alloc); + int64_t total_length = mvt_str.length(); + if (OB_FAIL(ret)) { + } else if (OB_FAIL(blob_res.init(total_length))) { + LOG_WARN("failed to init blob res", K(ret), K(mvt_str), K(total_length)); + } else if (OB_FAIL(blob_res.append(mvt_str))) { + LOG_WARN("failed to append xml binary data", K(ret), K(mvt_str)); + } else { + blob_res.get_result_buffer(blob_locator); + concat_result.set_string(blob_locator.ptr(), blob_locator.length()); + } + } + } + } + return ret; +} + +int ObAggregateProcessor::init_asmvt_result(ObIAllocator &allocator, + const ObAggrInfo &aggr_info, + const ObObj *tmp_obj, + uint32_t obj_cnt, + mvt_agg_result &mvt_res) +{ + int ret = OB_SUCCESS; + uint32_t column_cnt = 0; + bool is_param_done = false; + int param_cnt = 0; + mvt_res.inited_ = true; + // try get first geom column and column number + for (uint32_t i = 0; i < aggr_info.param_exprs_.count() && OB_SUCC(ret); i++) { + if (i == 0) { + param_cnt = tmp_obj[i].get_int(); + mvt_res.column_offset_ = param_cnt + 1; + } + ObExpr *expr = aggr_info.param_exprs_.at(i); + if (i >= mvt_res.column_offset_ && expr->type_ == T_REF_COLUMN) { + ObString key_name; + is_param_done = true; + column_cnt++; + if (i + 1 >= obj_cnt) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid param", K(ret), K(i), K(obj_cnt)); + } else if (expr->obj_meta_.is_geometry() && mvt_res.geom_idx_ == UINT32_MAX) { + if (mvt_res.geom_name_.empty()) { + mvt_res.geom_idx_ = i; + if (OB_FAIL(ob_write_string(allocator, tmp_obj[i + 1].get_string(), mvt_res.geom_name_))) { + // geo_name + LOG_WARN("write string failed", K(ret), K(tmp_obj[i].get_string())); + } + } else if (mvt_res.geom_name_.case_compare(tmp_obj[i + 1].get_string()) == 0) { + mvt_res.geom_idx_ = i; + } else if (OB_FAIL(ob_write_string(allocator, tmp_obj[i + 1].get_string(), key_name, true))) { + LOG_WARN("write string failed", K(ret), K(tmp_obj[i + 1].get_string())); + } else if (OB_FAIL(mvt_res.keys_.push_back(key_name))) { + LOG_WARN("failed to push back col name to keys", K(ret), K(i), K(tmp_obj[i + 1].get_string())); + } + } else if (!mvt_res.feature_id_name_.empty() && mvt_res.feat_id_idx_ == UINT32_MAX + && mvt_res.feature_id_name_.case_compare(tmp_obj[i + 1].get_string()) == 0 + && ob_is_numeric_type(expr->obj_meta_.get_type())) { + // feature id column name won't add to keys + mvt_res.feat_id_idx_ = i; + } else if (!expr->obj_meta_.is_json() // json type will be expanded + && !expr->obj_meta_.is_enum_or_set() + && OB_FAIL(ob_write_string(allocator, tmp_obj[i + 1].get_string(), key_name, true))) { + LOG_WARN("write string failed", K(ret), K(tmp_obj[i + 1].get_string())); + } else if (!expr->obj_meta_.is_json() && !expr->obj_meta_.is_enum_or_set() && OB_FAIL(mvt_res.keys_.push_back(key_name))) { + LOG_WARN("failed to push back col name to keys", K(ret), K(i), K(tmp_obj[i + 1].get_string())); + } + } else if (!is_param_done) { + ObObjType type = tmp_obj[i].get_type(); + ObString content; + if (ob_is_null(type)) { + // do nothing, use default value + } else if (i == 1) { + // layer name + if (!ob_is_string_tc(type) && !ob_is_large_text(type) && !ob_is_geometry_tc(type)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid type for layer name", K(ret), K(type)); + } else if (ob_is_geometry_tc(type)) { + ObObj geo_hex; + ObObj obj; + ObCastCtx cast_ctx(&allocator, NULL, CM_NONE, ObCharset::get_system_collation()); + if (OB_FAIL(ObObjCaster::to_type(ObVarcharType, cast_ctx, tmp_obj[i], obj))) { + LOG_WARN("failed to cast number to double type", K(ret)); + } else if (OB_FAIL(ObHexUtils::hex(ObString(obj.get_string().length(), obj.get_string().ptr()), cast_ctx, geo_hex))) { + LOG_WARN("failed to cast to hex", K(ret), K(content)); + } else if (OB_FAIL(ob_write_string(allocator, geo_hex.get_string(), mvt_res.lay_name_, true))) { + LOG_WARN("write string failed", K(ret), K(content)); + } + } else if (OB_FAIL(tmp_obj[i].get_string(content))) { + LOG_WARN("get lay name string failed", K(ret)); + } else if (mvt_agg_result::is_upper_char_exist(content)) { + ret = OB_ERR_BAD_FIELD_ERROR; + LOG_WARN("column name can't be upper case", K(ret), K(type)); + } else if (OB_FAIL(ob_write_string(allocator, content, mvt_res.lay_name_, true))) { + LOG_WARN("write string failed", K(ret), K(content)); + } + } else if (i == 2) { + // extent + ObObj obj; + const ObObj *extent_res = &tmp_obj[i]; + if (!ob_is_int_tc(type) && !ob_is_uint_tc(type)) { + if (expr->is_static_const_) { + ObCastCtx cast_ctx(&allocator, NULL, CM_NONE, ObCharset::get_system_collation()); + if (OB_FAIL(ObObjCaster::to_type(ObInt32Type, cast_ctx, tmp_obj[i], obj))) { + LOG_WARN("failed to cast number to double type", K(ret)); + } else { + extent_res = &obj; + } + } else { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid type for extent", K(ret), K(type)); + } + } + if (OB_FAIL(ret)) { + } else if (extent_res->get_int() == 0 + || extent_res->is_overflow_integer(ObInt32Type)) { + ret = OB_ERR_INVALID_INPUT_VALUE; + LOG_WARN("invalid extent value", K(ret), K(extent_res->get_int())); + } else { + mvt_res.extent_ = extent_res->get_int(); + } + } else if (i == 3) { + // geo_name + if (!ob_is_string_tc(type)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid type for geom name", K(ret), K(type)); + } else if (tmp_obj[i].get_string().empty()) { + ret = OB_ERR_BAD_FIELD_ERROR; + LOG_WARN("invalid column name", K(ret), K(type)); + } else if (mvt_agg_result::is_upper_char_exist(tmp_obj[i].get_string())) { + ret = OB_ERR_BAD_FIELD_ERROR; + LOG_WARN("column name can't be upper case", K(ret), K(type)); + } else if (OB_FAIL(ob_write_string(allocator, tmp_obj[i].get_string(), mvt_res.geom_name_))) { + LOG_WARN("write string failed", K(ret), K(tmp_obj[i].get_string())); + } + } else if (i == 4) { + // feature id name + if (!ob_is_string_tc(type)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid type for layer name", K(ret), K(type)); + } else if (mvt_agg_result::is_upper_char_exist(tmp_obj[i].get_string())) { + ret = OB_ERR_BAD_FIELD_ERROR; + LOG_WARN("column name can't be upper case", K(ret), K(type)); + } else if (OB_FAIL(ob_write_string(allocator, tmp_obj[i].get_string(), mvt_res.feature_id_name_))) { + LOG_WARN("write string failed", K(ret), K(tmp_obj[i].get_string())); + } else if (mvt_res.feature_id_name_.empty()) { + ret = OB_WRONG_COLUMN_NAME; + LOG_WARN("input an empty feature id name", K(ret)); + } + } + } + } + if (OB_SUCC(ret)) { + if (!mvt_res.feature_id_name_.empty() && mvt_res.feat_id_idx_ == UINT32_MAX) { + // can't find feature id column + ret = OB_ERR_IDENTITY_COLUMN_MUST_BE_NUMERIC_TYPE; + LOG_WARN("invalid column type", K(ret)); + } else { + mvt_res.column_cnt_ = column_cnt; + if (OB_FAIL(mvt_res.init_layer())) { + LOG_WARN("failed to init layer", K(ret)); + } + } + } + return ret; +} + int ObAggregateProcessor::check_rows_prefix_str_equal_for_hybrid_hist(const ObChunkDatumStore::LastStoredRow &prev_row, const ObChunkDatumStore::StoredRow &cur_row, const ObAggrInfo &aggr_info, diff --git a/src/sql/engine/aggregate/ob_aggregate_processor.h b/src/sql/engine/aggregate/ob_aggregate_processor.h index c3323a382f..177f25d412 100644 --- a/src/sql/engine/aggregate/ob_aggregate_processor.h +++ b/src/sql/engine/aggregate/ob_aggregate_processor.h @@ -28,6 +28,7 @@ #include "sql/engine/user_defined_function/ob_pl_user_defined_agg_function.h" #include "sql/engine/expr/ob_expr_dll_udf.h" #include "sql/engine/expr/ob_rt_datum_arith.h" +#include "lib/geo/ob_geo_mvt.h" namespace oceanbase { @@ -986,7 +987,14 @@ private: int get_ora_xmlagg_result(const ObAggrInfo &aggr_info, GroupConcatExtraResult *&extra, ObDatum &concat_result); - + int get_asmvt_result(const ObAggrInfo &aggr_info, + GroupConcatExtraResult *&extra, + ObDatum &concat_result); + int init_asmvt_result(ObIAllocator &allocator, + const ObAggrInfo &aggr_info, + const ObObj *tmp_obj, + uint32_t obj_cnt, + mvt_agg_result &mvt_res); int check_key_valid(common::hash::ObHashSet &view_key_names, const ObString& key); int shadow_truncate_string_for_hist(const ObObjMeta obj_meta, @@ -1107,7 +1115,8 @@ public: case T_FUN_ORA_JSON_ARRAYAGG: case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_OBJECTAGG: - case T_FUN_ORA_XMLAGG: { + case T_FUN_ORA_XMLAGG: + case T_FUN_SYS_ST_ASMVT: { need_id = true; break; } @@ -1257,6 +1266,7 @@ OB_INLINE bool ObAggregateProcessor::need_extra_info(const ObExprOperatorType ex case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_OBJECTAGG: case T_FUN_ORA_XMLAGG: + case T_FUN_SYS_ST_ASMVT: { need_extra = true; break; diff --git a/src/sql/engine/basic/ob_expr_values_op.cpp b/src/sql/engine/basic/ob_expr_values_op.cpp index ddef4255cf..13b9bc1c2e 100644 --- a/src/sql/engine/basic/ob_expr_values_op.cpp +++ b/src/sql/engine/basic/ob_expr_values_op.cpp @@ -593,7 +593,7 @@ OB_INLINE int ObExprValuesOp::calc_next_row() } } else if (!dst_expr->obj_meta_.is_lob_storage()) { if (OB_FAIL(datum_caster_.to_type(dst_expr->datum_meta_, real_src_expr, - cm_, datum))) { + cm_, datum, 0, dst_expr->obj_meta_.get_subschema_id()))) { LOG_WARN("fail to dynamic cast", K(dst_expr->datum_meta_), K(real_src_expr), K(cm_), K(ret)); if (dst_expr->obj_meta_.is_geometry()) { diff --git a/src/sql/engine/expr/ob_datum_cast.cpp b/src/sql/engine/expr/ob_datum_cast.cpp index 5ab5cd3e22..77909e1a19 100644 --- a/src/sql/engine/expr/ob_datum_cast.cpp +++ b/src/sql/engine/expr/ob_datum_cast.cpp @@ -31,11 +31,16 @@ #include "lib/geo/ob_geometry_cast.h" #include "sql/engine/expr/ob_geo_expr_utils.h" #ifdef OB_BUILD_ORACLE_XML +#include "lib/udt/ob_udt_type.h" +#include "sql/engine/expr/ob_expr_sql_udt_utils.h" #include "lib/xml/ob_xml_util.h" #include "sql/engine/expr/ob_expr_xml_func_helper.h" #endif #include "pl/ob_pl.h" #include "pl/ob_pl_user_type.h" +#ifdef OB_BUILD_ORACLE_PL +#include "pl/sys_package/ob_sdo_geometry.h" +#endif namespace oceanbase { namespace sql @@ -458,7 +463,6 @@ int ObDatumHexUtils::rawtohex(const ObExpr &expr, const ObString &in_str, case ObCharType: case ObLongTextType: case ObJsonType: - case ObGeometryType: case ObRawType: { //https://www.techonthenet.com/oracle/functions/rawtohex.php //NOTE:: when convert string to raw, Oracle use utl_raw.cast_to_raw(), @@ -483,6 +487,16 @@ int ObDatumHexUtils::rawtohex(const ObExpr &expr, const ObString &in_str, } break; } + case ObGeometryType: { + ObString lob_data = in_str; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(&tmp_alloc, in_type, + expr.args_[0]->datum_meta_.cs_type_, expr.args_[0]->obj_meta_.has_lob_header(), + lob_data))) { + LOG_WARN("fail to get real data.", K(ret), K(lob_data)); + } else { + out_str = lob_data; + } + } default: { ret = OB_ERR_INVALID_HEX_NUMBER; LOG_WARN("invalid hex number", K(ret), K(in_str), "type", in_type); @@ -4072,7 +4086,7 @@ CAST_FUNC_NAME(string, geometry) LOG_WARN("fail to get real data.", K(ret), K(in_str)); } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, in_str, srs, true, cast_name))) { LOG_WARN("fail to get srs item", K(ret), K(in_str)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, in_str, geo, srs, cast_name))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, in_str, geo, srs, cast_name, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("fail to parse geometry", K(ret), K(in_str), K(dst_geo_type)); } else if (ObGeoType::GEOMETRY == dst_geo_type || ObGeoType::GEOTYPEMAX == dst_geo_type) { ObString res_wkb; @@ -8942,17 +8956,16 @@ int cast_to_udt_not_support(const sql::ObExpr &expr, sql::ObEvalCtx &ctx, sql::O const ObObjMeta &in_obj_meta = expr.args_[0]->obj_meta_; const ObObjMeta &out_obj_meta = expr.obj_meta_; if (out_obj_meta.is_xml_sql_type()) { - // only allow cast basic types to invalid CAST to a type that is not a nested table or VARRAY - ret = OB_ERR_INVALID_CAST_UDT; - LOG_WARN_RET(ret, "invalid CAST to a type that is not a nested table or VARRAY"); - } else { - // other udts - // ORA-00932: inconsistent datatypes: expected PLSQL INDEX TABLE got NUMBER - // currently other types to udt not supported ret = OB_ERR_INVALID_XML_DATATYPE; LOG_USER_ERROR(OB_ERR_INVALID_XML_DATATYPE, "ANYDATA", ob_obj_type_str(in_obj_meta.get_type())); LOG_WARN_RET(ret, "not expected obj type convert", K(in_obj_meta), K(out_obj_meta), K(out_obj_meta.get_subschema_id()), K(expr.extra_)); + } else { + // other udts + // ORA-00932: inconsistent datatypes: expected PLSQL INDEX TABLE got NUMBER + // currently other types to udt not supported + ret = OB_ERR_INVALID_CAST_UDT; + LOG_WARN_RET(ret, "invalid CAST to a type that is not a nested table or VARRAY"); } return ret; } @@ -9059,48 +9072,104 @@ CAST_FUNC_NAME(string, udt) CAST_FUNC_NAME(udt, string) { - // udt(xmltype) can be null: select dump(xmlparse(document NULL)) from dual; + int ret = OB_SUCCESS; + ObDatum *child_res = NULL; + const ObObjMeta &in_obj_meta = expr.args_[0]->obj_meta_; + const ObObjMeta &out_obj_meta = expr.obj_meta_; + if (!in_obj_meta.is_xml_sql_type()) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN_RET(OB_ERR_INVALID_TYPE_FOR_OP, "inconsistent datatypes", + "expected", out_obj_meta.get_type(), "got", in_obj_meta.get_type(), + K(in_obj_meta.get_subschema_id())); + } else if (OB_FAIL(expr.args_[0]->eval(ctx, child_res))) { + LOG_WARN("eval arg failed", K(ret), K(ctx)); + } else if (child_res->is_null() || + (lib::is_oracle_mode() && 0 == child_res->len_ + && ObLongTextType != expr.args_[0]->datum_meta_.type_)) { + // udt(xmltype) can be null: select dump(xmlparse(document NULL)) from dual; + res_datum.set_null(); + } else { +#ifdef OB_BUILD_ORACLE_XML + ObString blob_data = child_res->get_string(); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObIMulModeBase *xml_root = NULL; + ObStringBuffer xml_plain_text(&temp_allocator); + ObCollationType session_cs_type = CS_TYPE_UTF8MB4_BIN; + GET_SESSION() { + session_cs_type = session->get_nls_collation(); + } + if (OB_FAIL(ObTextStringHelper::read_real_string_data(&temp_allocator, + ObLongTextType, + CS_TYPE_BINARY, + true, + blob_data))) { + LOG_WARN("fail to get real data.", K(ret), K(blob_data)); + } else if (OB_FAIL(ObXmlUtil::cast_to_string(blob_data, temp_allocator, xml_plain_text, session_cs_type))) { + LOG_WARN("failed to convert xml to string", K(ret), KP(blob_data.ptr()), K(blob_data.length())); + } else { // use clob before xml binary implemented + ObObjType in_type = ObLongTextType; + ObObjType out_type = expr.datum_meta_.type_; + ObCollationType in_cs_type = CS_TYPE_UTF8MB4_BIN; + ObCollationType out_cs_type = expr.datum_meta_.cs_type_; + bool has_set_res = false; + OZ(common_string_string(expr, in_type, in_cs_type, out_type, + out_cs_type, xml_plain_text.string(), ctx, res_datum, has_set_res)); + const ObString res_str = res_datum.get_string(); // res str need deep copy in pl mode + if (OB_SUCC(ret) && OB_FAIL(common_copy_string(expr, res_str, ctx, res_datum))) { + LOG_WARN("fail to deep copy str", K(ret)); + } + } +#else + ret = OB_NOT_SUPPORTED; +#endif + } + return ret; +} + +int get_udt_id(sql::ObEvalCtx &ctx, const ObObjMeta &obj_meta, uint64_t &udt_id) { + int ret = OB_SUCCESS; + const ObObjType type = obj_meta.get_type(); + if (type != ObUserDefinedSQLType) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error input type", K(ret), K(obj_meta)); + } else { + const uint16_t subschema_id = obj_meta.get_subschema_id(); + ObSqlUDTMeta udt_meta; + // Notice: udt_type_id (accuray) does not exist in output obj meta, + // should set subschema_id on input obj_meta in code generation + if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else { + udt_id = udt_meta.udt_id_; + } + } + return ret; +} + +CAST_FUNC_NAME(udt, udt) +{ EVAL_STRING_ARG() { #ifdef OB_BUILD_ORACLE_XML const ObObjMeta &in_obj_meta = expr.args_[0]->obj_meta_; const ObObjMeta &out_obj_meta = expr.obj_meta_; - if (in_obj_meta.is_xml_sql_type()) { - ObString blob_data = child_res->get_string(); - ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); - common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); - ObIMulModeBase *xml_root = NULL; - ObStringBuffer xml_plain_text(&temp_allocator); - ObCollationType session_cs_type = CS_TYPE_UTF8MB4_BIN; - GET_SESSION() { - session_cs_type = session->get_nls_collation(); - } - if (OB_FAIL(ObTextStringHelper::read_real_string_data(&temp_allocator, - ObLongTextType, - CS_TYPE_BINARY, - true, - blob_data))) { - LOG_WARN("fail to get real data.", K(ret), K(blob_data)); - } else if (OB_FAIL(ObXmlUtil::cast_to_string(blob_data, temp_allocator, xml_plain_text, session_cs_type))) { - LOG_WARN("failed to convert xml to string", K(ret), KP(blob_data.ptr()), K(blob_data.length())); - } else { // use clob before xml binary implemented - ObObjType in_type = ObLongTextType; - ObObjType out_type = expr.datum_meta_.type_; - ObCollationType in_cs_type = CS_TYPE_UTF8MB4_BIN; - ObCollationType out_cs_type = expr.datum_meta_.cs_type_; - bool has_set_res = false; - OZ(common_string_string(expr, in_type, in_cs_type, out_type, - out_cs_type, xml_plain_text.string(), ctx, res_datum, has_set_res)); - const ObString res_str = res_datum.get_string(); // res str need deep copy in pl mode - if (OB_SUCC(ret) && OB_FAIL(common_copy_string(expr, res_str, ctx, res_datum))) { - LOG_WARN("fail to deep copy str", K(ret)); - } + uint64_t in_udt_id = T_OBJ_NOT_SUPPORTED; + uint64_t out_udt_id = T_OBJ_NOT_SUPPORTED; + if (OB_FAIL(get_udt_id(ctx, in_obj_meta, in_udt_id))) { + LOG_WARN("fail to get udt id from obj meta", K(ret)); + } else if (OB_FAIL(get_udt_id(ctx, out_obj_meta, out_udt_id))) { + LOG_WARN("fail to get udt id from obj meta", K(ret)); + } else if (ObGeometryTypeCastUtil::is_sdo_geometry_type_compatible(in_udt_id, out_udt_id)) { + ObDatum *child_res = NULL; + ObExprStrResAlloc expr_res_alloc(expr, ctx); + if (OB_FAIL(expr.args_[0]->eval(ctx, child_res))) { + LOG_WARN("eval arg failed", K(ret), K(ctx)); + } else if (OB_FAIL(res_datum.deep_copy(*child_res, expr_res_alloc))) { + LOG_WARN("Failed to deep copy from res datum", K(ret)); } } else { - ret = OB_ERR_INVALID_TYPE_FOR_OP; - LOG_WARN_RET(OB_ERR_INVALID_TYPE_FOR_OP, "inconsistent datatypes", - "expected", out_obj_meta.get_type(), "got", in_obj_meta.get_type(), - K(in_obj_meta.get_subschema_id())); + ret = cast_udt_to_other_not_support(expr, ctx, res_datum); } #else ret = OB_NOT_SUPPORTED; @@ -9180,64 +9249,98 @@ CAST_FUNC_NAME(pl_extend, string) return ret; } +#ifdef OB_BUILD_ORACLE_PL +int cast_sql_xml_pl_xml(const sql::ObExpr &expr, + sql::ObEvalCtx &ctx, + sql::ObDatum &res_datum, + sql::ObDatum *child_res) +{ + int ret = OB_SUCCESS; + pl::ObPLXmlType *xmltype = NULL; + void *ptr = NULL; + ObObj* data = NULL; // obobj for blob; + ObIAllocator &allocator = ctx.exec_ctx_.get_allocator(); + if (OB_ISNULL(data = static_cast(allocator.alloc(sizeof(ObObj))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for pl object", K(ret)); + } else if (OB_ISNULL(ptr = allocator.alloc(sizeof(pl::ObPLXmlType)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("Failed to allocate memory for pl xml data type", K(ret), K(sizeof(pl::ObPLXmlType))); + } else if (FALSE_IT(xmltype = new (ptr)pl::ObPLXmlType())) { + } else if (OB_ISNULL(data = static_cast(allocator.alloc(sizeof(ObObj))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for pl object", K(ret)); + } else { + ObString xml_data; + if (!child_res->is_null() && !child_res->get_string().empty()) { + /* + We believe that the memory in child_res is reliable, + and the content in it can be passed to the next layer without copying. + Therefore, there is no deep copy of row-level memory here. + If you find that the memory of xml_data is unstable later, + you can add a deep copy here to copy the data to the memory of expr: get_str_res_mem(). + */ + xml_data = child_res->get_string(); + data->set_string(ObLongTextType, xml_data.ptr(), xml_data.length()); + data->set_has_lob_header(); // must has lob header + data->set_collation_type(CS_TYPE_UTF8MB4_BIN); + } else { + data->set_null(); + } + if (OB_SUCC(ret)) { + ObObj result_obj; + xmltype->set_data(data); + result_obj.set_extend(reinterpret_cast(xmltype), pl::PL_OPAQUE_TYPE); + if (OB_FAIL(res_datum.from_obj(result_obj, expr.obj_datum_map_))) { // check obj_datum_map_ + LOG_WARN("failed to set extend datum from obj", K(ret)); + } + } + } + + return ret; +} +#endif + CAST_FUNC_NAME(sql_udt, pl_extend) { - // Convert sql udt type to pl udt type, currently only xmltype is supported - // check source type subschema id for validation - // For PL extend type, detaield udt id is stored in accurcy_ before code generation, - // then only existed in the data after cg. + // Convert sql udt type to pl udt type, currently only some system defined types are supported int ret = OB_SUCCESS; -#ifdef OB_BUILD_ORACLE_XML +#ifdef OB_BUILD_ORACLE_PL + const ObObjMeta &in_obj_meta = expr.args_[0]->obj_meta_; + const ObObjMeta &out_obj_meta = expr.obj_meta_; + const ObObjType in_type = in_obj_meta.get_type(); ObDatum *child_res = NULL; - if (OB_FAIL(expr.args_[0]->eval(ctx, child_res))) { + if (in_type != ObUserDefinedSQLType && in_type != ObCollectionSQLType) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error input type", K(ret), K(in_obj_meta), K(out_obj_meta)); + } else if (OB_FAIL(expr.args_[0]->eval(ctx, child_res))) { LOG_WARN("eval arg failed", K(ret), K(ctx)); } else { - const ObObjMeta &in_obj_meta = expr.args_[0]->obj_meta_; - const ObObjMeta &out_obj_meta = expr.obj_meta_; - if (in_obj_meta.is_xml_sql_type()) { - pl::ObPLXmlType *xmltype = NULL; - void *ptr = NULL; - ObObj* data = NULL; // obobj for blob; - ObIAllocator &allocator = ctx.exec_ctx_.get_allocator(); - if (OB_ISNULL(ptr = allocator.alloc(sizeof(pl::ObPLXmlType)))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("Failed to allocate memory for pl xml data type", K(ret), K(sizeof(pl::ObPLXmlType))); - } else if (FALSE_IT(xmltype = new (ptr)pl::ObPLXmlType())) { - } else if (OB_ISNULL(data = static_cast(allocator.alloc(sizeof(ObObj))))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("failed to allocate memory for pl object", K(ret)); - } else { - ObString xml_data; - - if (!child_res->is_null() && !child_res->get_string().empty()) { - /* - We believe that the memory in child_res is reliable, - and the content in it can be passed to the next layer without copying. - Therefore, there is no deep copy of row-level memory here. - If you find that the memory of xml_data is unstable later, - you can add a deep copy here to copy the data to the memory of expr: get_str_res_mem(). - */ - xml_data = child_res->get_string(); - data->set_string(ObLongTextType, xml_data.ptr(), xml_data.length()); - data->set_has_lob_header(); // must has lob header - data->set_collation_type(CS_TYPE_UTF8MB4_BIN); - } else { - data->set_null(); - } - if (OB_SUCC(ret)) { - ObObj result_obj; - xmltype->set_data(data); - result_obj.set_extend(reinterpret_cast(xmltype), pl::PL_OPAQUE_TYPE); - if (OB_FAIL(res_datum.from_obj(result_obj, expr.obj_datum_map_))) { // check obj_datum_map_ - LOG_WARN("failed to set extend datum from obj", K(ret)); - } - } + const uint16_t subschema_id = in_obj_meta.get_subschema_id(); + ObSqlUDTMeta udt_meta; + // Notice: udt_type_id (accuray) does not exist in output obj meta, + // should set subschema_id on input obj_meta in code generation + if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (udt_meta.udt_id_ == T_OBJ_XML) { + if (OB_FAIL(cast_sql_xml_pl_xml(expr, ctx, res_datum, child_res))) { + LOG_WARN("failed to cast sql xmltype to pl xmltype", K(ret)); + } + } else if (udt_meta.pl_type_ == pl::PL_RECORD_TYPE || udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) { + ObString udt_data = child_res->get_string(); + ObObj result; + if (OB_FAIL(ObSqlUdtUtils::cast_sql_record_to_pl_record(&ctx.exec_ctx_, + result, + udt_data, + udt_meta))) { + LOG_WARN("failed to cast sql collection to pl collection", K(ret), K(udt_meta.udt_id_)); + } else if (OB_FAIL(res_datum.from_obj(result, expr.obj_datum_map_))) { + LOG_WARN("Failed to deep copy element object value", K(ret), K(result)); } } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; - LOG_WARN_RET(OB_ERR_INVALID_TYPE_FOR_OP, "inconsistent datatypes", - "expected", out_obj_meta.get_type(), "got", in_obj_meta.get_type(), - K(in_obj_meta.get_subschema_id())); + LOG_WARN("inconsistent datatypes", K(ret), K(out_obj_meta.get_type()), + K(in_obj_meta.get_type()), K(subschema_id), K(udt_meta.udt_id_)); } } #else @@ -9246,56 +9349,190 @@ CAST_FUNC_NAME(sql_udt, pl_extend) return ret; } +#ifdef OB_BUILD_ORACLE_PL +int covert_pl_xml_to_sql_xml(const sql::ObExpr &expr, + sql::ObEvalCtx &ctx, + sql::ObDatum &res_datum, + const ObObjMeta &in_obj_meta, + sql::ObDatum *child_res) +{ + int ret = OB_SUCCESS; + + if (pl::PL_OPAQUE_TYPE == in_obj_meta.get_extend_type()) { + pl::ObPLOpaque *pl_src = reinterpret_cast(child_res->get_ext()); + if (OB_ISNULL(pl_src)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("failed to get pl data type info", K(ret), K(in_obj_meta)); + } else if (pl_src->get_type() == pl::ObPLOpaqueType::PL_XML_TYPE) { + pl::ObPLXmlType * xmltype = static_cast(pl_src); + ObObj *blob_obj = xmltype->get_data(); + if (OB_ISNULL(blob_obj) || blob_obj->is_null()) { + res_datum.set_null(); + } else { + ObString xml_data = blob_obj->get_string(); + int64_t xml_data_size = xml_data.length(); + char *xml_data_buff = expr.get_str_res_mem(ctx, xml_data_size); + if (OB_ISNULL(xml_data_buff)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for xmldata", K(ret), K(xml_data_size)); + } else { + MEMCPY(xml_data_buff, xml_data.ptr(), xml_data_size); + res_datum.set_string(ObString(xml_data_size , xml_data_buff)); + } + } + } else if (pl_src->get_type() == pl::ObPLOpaqueType::PL_INVALID) { + // un-initiated pl opaque variable + res_datum.set_null(); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected type to convert pl format", K(ret), K(pl_src->get_type()), K(in_obj_meta)); + } + } else { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("Unexpected type to convert pl udt to sql udt format", K(ret), K(in_obj_meta)); + } + return ret; +} +#endif + CAST_FUNC_NAME(pl_extend, sql_udt) { // Convert sql udt type to pl udt type, currently only xmltype is supported + // Notice: udt_type_id (accuray) does not exist in input obj meta, + // should set subschema_id on output obj_meta in code generation EVAL_STRING_ARG() { #ifdef OB_BUILD_ORACLE_XML const ObObjMeta &in_obj_meta = expr.args_[0]->obj_meta_; + const ObObjType in_type = in_obj_meta.get_type(); const ObObjMeta &out_obj_meta = expr.obj_meta_; - if (pl::PL_OPAQUE_TYPE == in_obj_meta.get_extend_type()) { - pl::ObPLOpaque *pl_src = reinterpret_cast(child_res->get_ext()); - if (OB_ISNULL(pl_src)) { + const uint16_t subschema_id = out_obj_meta.get_subschema_id(); + + ObSqlUDT sql_udt; + ObSqlUDTMeta udt_meta; + ObObj root_obj; + ObString res_str; + ObExprStrResAlloc expr_res_alloc(expr, ctx); + + if (in_type != ObExtendType) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error input type", K(ret), K(in_obj_meta), K(out_obj_meta)); + } else if (OB_FAIL(child_res->to_obj(root_obj, in_obj_meta))) { + LOG_WARN("failed to get root obj", K(ret), K(in_obj_meta), K(child_res)); + } else if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (udt_meta.udt_id_ == T_OBJ_XML) { + if (OB_FAIL(covert_pl_xml_to_sql_xml(expr, ctx, res_datum, in_obj_meta, child_res))) { + LOG_WARN("failed to cast pl xml to sql xml", K(ret), K(in_obj_meta)); + } + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_meta.udt_id_)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("inconsistent datatypes", K(ret), K(out_obj_meta.get_type()), + K(in_obj_meta.get_type()), K(subschema_id), K(udt_meta.udt_id_)); + } else if (FALSE_IT(sql_udt.set_udt_meta(udt_meta))) { + } else if (root_obj.get_ext() == 0) { + res_datum.set_null(); + } else if (sql_udt.get_udt_meta().pl_type_ == pl::PL_VARRAY_TYPE) { // single varray + pl::ObPLVArray *varray = reinterpret_cast(root_obj.get_ext()); + if (OB_ISNULL(varray)) { ret = OB_ERR_NULL_VALUE; - LOG_WARN("failed to get pl data type info", K(ret), K(in_obj_meta)); - } else if (pl_src->get_type() == pl::ObPLOpaqueType::PL_XML_TYPE) { - if(!out_obj_meta.is_xml_sql_type()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("Unexpected pl xml to sql udt type", K(ret), K(in_obj_meta), K(out_obj_meta)); - } else { - pl::ObPLXmlType * xmltype = static_cast(pl_src); - ObObj *blob_obj = xmltype->get_data(); - if (OB_ISNULL(blob_obj) || blob_obj->is_null()) { - res_datum.set_null(); - } else { - // deep copy here or by the caller ? - ObString xml_data = blob_obj->get_string(); - int64_t xml_data_size = xml_data.length(); - char *xml_data_buff = expr.get_str_res_mem(ctx, xml_data_size); - if (OB_ISNULL(xml_data_buff)) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("failed to allocate memory for xmldata", - K(ret), K(out_obj_meta), K(xml_data_size)); - } else { - MEMCPY(xml_data_buff, xml_data.ptr(), xml_data_size); - res_datum.set_string(ObString(xml_data_size, xml_data_buff)); - // should not destroy input extends - } - } - } - } else if (pl_src->get_type() == pl::ObPLOpaqueType::PL_INVALID) { - // un-initiated pl opaque variable + LOG_WARN("failed to get pl data type info", K(ret)); + } else if (varray->is_null()) { + res_datum.set_null(); + } else if (OB_FAIL(ObSqlUdtUtils::cast_pl_varray_to_sql_varray(expr_res_alloc, res_str, root_obj))) { + LOG_WARN("convert pl record to sql record failed", + K(ret), K(subschema_id), K(udt_meta.udt_id_)); + } else { + res_datum.set_string(res_str); + } + } else { // record + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + pl::ObPLRecord *record = reinterpret_cast(root_obj.get_ext()); + if (OB_ISNULL(record)) { + ret = OB_ERR_NULL_VALUE; + LOG_WARN("failed to get pl data type info", K(ret)); + } else if (record->is_null()) { + res_datum.set_null(); + } else if (OB_FAIL(ObSqlUdtUtils::cast_pl_record_to_sql_record(temp_allocator, + expr_res_alloc, + &ctx.exec_ctx_, + res_str, + sql_udt, + root_obj))) { + LOG_WARN("convert pl record to sql record failed", + K(ret), K(subschema_id), K(udt_meta.udt_id_)); + } else { + res_datum.set_string(res_str); + } + } +#else + ret = OB_NOT_SUPPORTED; +#endif + } + return ret; +} + +CAST_FUNC_NAME(pl_extend, geometry) +{ + // Convert sql udt type to pl udt type, currently only xmltype is supported + // Notice: udt_type_id (accuray) does not exist in input obj meta, + // should set subschema_id on output obj_meta in code generation + EVAL_STRING_ARG() + { +#ifdef OB_BUILD_ORACLE_PL + const ObObjMeta &in_obj_meta = expr.args_[0]->obj_meta_; + const ObObjType in_type = in_obj_meta.get_type(); + const ObObjMeta &out_obj_meta = expr.obj_meta_; + ObObj root_obj; + ObIAllocator &allocator = ctx.exec_ctx_.get_allocator(); + uint64_t tenant_id = ctx.exec_ctx_.get_my_session()->get_effective_tenant_id(); + ObString res_wkb; + + if (in_type != ObExtendType) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error input type", K(ret), K(in_obj_meta), K(out_obj_meta)); + } else if (OB_FAIL(child_res->to_obj(root_obj, in_obj_meta))) { + LOG_WARN("failed to get root obj", K(ret), K(in_obj_meta), K(child_res)); + } else { + pl::ObPLRecord *pl_src = reinterpret_cast(root_obj.get_ext()); + if (pl_src->is_null()) { res_datum.set_null(); } else { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("Unexpected type to convert pl format", - K(ret), K(pl_src->get_type()), K(in_obj_meta), K(out_obj_meta)); + if (OB_FAIL(pl::ObSdoGeometry::pl_extend_to_wkb(&allocator, root_obj, tenant_id, res_wkb))) { + LOG_WARN("failed to get geometry wkb from pl extend", K(ret), K(in_obj_meta), K(child_res)); + } else if (OB_FAIL(common_gis_wkb(expr, ctx, res_datum, res_wkb))){ + LOG_WARN("fail to copy string", K(ret)); + } } - } else { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("Unexpected type to convert pl udt to sql udt format", - K(ret), K(in_obj_meta), K(out_obj_meta)); + } +#else + ret = OB_NOT_SUPPORTED; +#endif + } + return ret; +} + +CAST_FUNC_NAME(geometry, pl_extend) +{ + // Convert sql udt type to pl udt type, currently only xmltype is supported + // Notice: udt_type_id (accuray) does not exist in input obj meta, + // should set subschema_id on output obj_meta in code generation + EVAL_STRING_ARG() + { +#ifdef OB_BUILD_ORACLE_PL + ObIAllocator &allocator = ctx.exec_ctx_.get_allocator(); + ObString wkb = child_res->get_string(); + ObObj result; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + if (OB_FAIL(ObTextStringHelper::read_real_string_data(temp_allocator, *child_res, + expr.args_[0]->datum_meta_, expr.args_[0]->obj_meta_.has_lob_header(), wkb))) { + LOG_WARN("fail to get real data.", K(ret), K(wkb)); + } else if (OB_FAIL(pl::ObSdoGeometry::wkb_to_pl_extend(allocator, &ctx.exec_ctx_, wkb, result))) { + LOG_WARN("failed to get geometry wkb from pl extend", K(ret)); + } else if (OB_FAIL(res_datum.from_obj(result, expr.obj_datum_map_))) { + LOG_WARN("Failed to deep copy element object value", K(ret), K(result)); } #else ret = OB_NOT_SUPPORTED; @@ -11477,6 +11714,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_eval_arg,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*int -> XXX*/ @@ -11503,9 +11741,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ int_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*uint -> XXX*/ @@ -11532,9 +11771,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ uint_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*float -> XXX*/ @@ -11561,9 +11801,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ float_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*double -> XXX*/ @@ -11590,9 +11831,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ double_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*number -> XXX*/ @@ -11619,9 +11861,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ number_lob,/*lob*/ number_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ number_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*datetime -> XXX*/ @@ -11648,9 +11891,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ date_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*date -> XXX*/ @@ -11677,9 +11921,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*time -> XXX*/ @@ -11706,9 +11951,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ time_json,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*year -> XXX*/ @@ -11735,9 +11981,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*string -> XXX*/ @@ -11764,9 +12011,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = string_rowid,/*rowid*/ string_lob,/*lob*/ string_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ string_udt,/*udt*/ string_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*extend -> XXX*/ @@ -11793,9 +12041,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + pl_extend_geometry,/*geometry*/ pl_extend_sql_udt,/*udt*/ cast_not_expected,/*decimalint*/ + pl_extend_sql_udt,/*collection*/ }, { /*unknown -> XXX*/ @@ -11822,9 +12071,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*text -> XXX*/ @@ -11851,9 +12101,9 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = text_rowid,/*rowid*/ text_lob,/*lob*/ string_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ - text_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*bit -> XXX*/ @@ -11880,9 +12130,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*enum -> XXX*/ @@ -11909,9 +12160,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected, /*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*enumset_inner -> XXX*/ @@ -11938,9 +12190,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*otimestamp -> XXX*/ @@ -11967,9 +12220,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*raw -> XXX*/ @@ -11996,9 +12250,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ raw_lob,/*lob*/ raw_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*interval -> XXX*/ @@ -12025,9 +12280,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /* rowid -> XXX */ @@ -12054,9 +12310,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = rowid_rowid,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_inconsistent_types,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*lob -> XXX*/ @@ -12083,9 +12340,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = lob_rowid,/*rowid*/ lob_lob,/*lob*/ lob_json,/*json*/ - cast_not_support,/*geometry*/ + lob_geometry,/*geometry*/ cast_to_udt_not_support,/*udt*/ lob_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*json -> XXX*/ @@ -12112,9 +12370,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ json_lob,/*lob*/ json_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*geometry -> XXX*/ @@ -12129,7 +12388,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*time*/ cast_not_support,/*year*/ cast_not_support,/*string*/ - cast_not_support,/*extend*/ + geometry_pl_extend,/*extend*/ cast_not_support,/*unknown*/ cast_not_support,/*text*/ cast_not_support,/*bit*/ @@ -12141,9 +12400,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_not_support,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ + geometry_geometry,/*geometry*/ cast_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_not_support,/*collection*/ }, { /*udt -> XXX*/ @@ -12171,8 +12431,9 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_udt_to_other_not_support,/*lob*/ cast_udt_to_other_not_support,/*json*/ cast_udt_to_other_not_support,/*geometry*/ - cast_udt_to_other_not_support,/*udt*/ - cast_udt_to_other_not_support,/*decimal int*/ + udt_udt,/*udt*/ + cast_not_expected,/*decimalint*/ + cast_udt_to_other_not_support,/*collection*/ }, { /*decimalint -> XXX*/ @@ -12199,9 +12460,40 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_IMPLICIT[ObMaxTC][ObMaxTC] = cast_inconsistent_types,/*rowid*/ decimalint_lob,/*lob*/ decimalint_json,/*json*/ - cast_not_support,/*decimalint*/ + cast_inconsistent_types,/*decimalint*/ cast_to_udt_not_support, /*udt*/ decimalint_decimalint,/*decimalint*/ + cast_not_expected, /*udt*/ + }, + { + /*collection -> XXX*/ + cast_udt_to_other_not_support,/*null*/ + cast_udt_to_other_not_support,/*int*/ + cast_udt_to_other_not_support,/*uint*/ + cast_udt_to_other_not_support,/*float*/ + cast_udt_to_other_not_support,/*double*/ + cast_udt_to_other_not_support,/*number*/ + cast_udt_to_other_not_support,/*datetime*/ + cast_udt_to_other_not_support,/*date*/ + cast_udt_to_other_not_support,/*time*/ + cast_udt_to_other_not_support,/*year*/ + cast_udt_to_other_not_support,/*string*/ + sql_udt_pl_extend,/*extend*/ + cast_udt_to_other_not_support,/*unknown*/ + cast_udt_to_other_not_support,/*text*/ + cast_udt_to_other_not_support,/*bit*/ + cast_udt_to_other_not_support,/*enumset*/ + cast_udt_to_other_not_support,/*enumset_inner*/ + cast_udt_to_other_not_support,/*otimestamp*/ + cast_udt_to_other_not_support,/*raw*/ + cast_udt_to_other_not_support,/*interval*/ + cast_udt_to_other_not_support,/*rowid*/ + cast_udt_to_other_not_support,/*lob*/ + cast_udt_to_other_not_support,/*json*/ + cast_udt_to_other_not_support,/*geometry*/ + cast_udt_to_other_not_support,/*udt*/ + cast_udt_to_other_not_support,/*decimal int*/ + cast_udt_to_other_not_support,/*collection*/ } }; @@ -12234,9 +12526,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_eval_arg,/*rowid*/ cast_eval_arg,/*lob*/ cast_eval_arg,/*json*/ - cast_not_support,/*geometry*/ + cast_eval_arg,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_eval_arg,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*int -> XXX*/ @@ -12263,9 +12556,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ int_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*uint -> XXX*/ @@ -12292,9 +12586,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ uint_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*float -> XXX*/ @@ -12321,9 +12616,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ float_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*double -> XXX*/ @@ -12350,9 +12646,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ double_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*number -> XXX*/ @@ -12379,9 +12676,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ number_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*datetime -> XXX*/ @@ -12408,9 +12706,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*date -> XXX*/ @@ -12437,9 +12736,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*time -> XXX*/ @@ -12466,9 +12766,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*year -> XXX*/ @@ -12495,9 +12796,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*string -> XXX*/ @@ -12524,9 +12826,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = string_rowid, /*rowid*/ cast_inconsistent_types,/*lob*/ cast_inconsistent_types,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ string_udt,/*udt*/ string_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*extend -> XXX*/ @@ -12553,9 +12856,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_not_support,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ + pl_extend_geometry,/*geometry*/ pl_extend_sql_udt,/*udt*/ cast_not_support,/*decimalint*/ + pl_extend_sql_udt,/*collection*/ }, { /*unknown -> XXX*/ @@ -12585,6 +12889,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ cast_to_udt_not_support,/*udt*/ unknown_other,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*text -> XXX*/ @@ -12611,9 +12916,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ string_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ text_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*bit -> XXX*/ @@ -12640,9 +12946,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*enum -> XXX*/ @@ -12669,9 +12976,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*enumset_inner -> XXX*/ @@ -12698,9 +13006,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*rowid*/ cast_not_expected,/*lob*/ cast_not_expected,/*json*/ - cast_not_support,/*geometry*/ + cast_not_expected,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*otimestamp -> XXX*/ @@ -12727,9 +13036,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*raw -> XXX*/ @@ -12756,9 +13066,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*interval -> XXX*/ @@ -12785,9 +13096,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_expected,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*rowid -> XXX*/ @@ -12814,9 +13126,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = rowid_rowid,/*rowid*/ cast_inconsistent_types,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*lob -> XXX*/ @@ -12843,9 +13156,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_inconsistent_types,/*lob*/ string_json,/*json*/ - cast_not_support,/*geometry*/ + lob_geometry,/*geometry*/ cast_to_udt_not_support,/*udt*/ lob_decimalint,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*json -> XXX*/ @@ -12872,9 +13186,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ json_lob,/*lob*/ json_json,/*json*/ - cast_not_support,/*geometry*/ + cast_inconsistent_types,/*geometry*/ cast_to_udt_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_to_udt_not_support,/*collection*/ }, { /*geometry -> XXX*/ @@ -12889,7 +13204,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*time*/ cast_not_support,/*year*/ cast_not_support,/*string*/ - cast_not_support,/*extend*/ + geometry_pl_extend,/*extend*/ cast_not_support,/*unknown*/ cast_not_support,/*text*/ cast_not_support,/*bit*/ @@ -12901,9 +13216,10 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*rowid*/ cast_not_support,/*lob*/ cast_not_support,/*json*/ - cast_not_support,/*geometry*/ + geometry_geometry,/*geometry*/ cast_not_support,/*udt*/ cast_not_support,/*decimalint*/ + cast_not_support,/*collection*/ }, { /*udt -> XXX*/ @@ -12933,35 +13249,67 @@ ObExpr::EvalFunc OB_DATUM_CAST_ORACLE_EXPLICIT[ObMaxTC][ObMaxTC] = cast_udt_to_other_not_support,/*geometry*/ cast_udt_to_other_not_support,/*udt*/ cast_udt_to_other_not_support,/*decimal int*/ + cast_not_expected,/*collection*/ }, { - /*decimalint -> XXXX*/ - cast_not_support,/*null*/ + /*decimalint -> XXX*/ + cast_not_expected,/*null*/ decimalint_int,/*int*/ decimalint_uint,/*uint*/ decimalint_float,/*float*/ decimalint_double,/*double*/ decimalint_number,/*number*/ - cast_not_support,/*datetime*/ - cast_not_support,/*date*/ - cast_not_support,/*time*/ - cast_not_support,/*year*/ + cast_inconsistent_types,/*datetime*/ + cast_not_expected,/*date*/ + cast_not_expected,/*time*/ + cast_not_expected,/*year*/ decimalint_string,/*string*/ - cast_not_support,/*extend*/ - cast_not_support,/*unknown*/ + cast_not_expected,/*extend*/ + cast_not_expected,/*unknown*/ decimalint_text,/*text*/ - decimalint_bit,/*bit*/ + cast_not_expected,/*bit*/ cast_not_expected,/*enumset*/ cast_not_expected,/*enumset_inner*/ - cast_not_support,/*otimestamp*/ - cast_not_support,/*raw*/ - cast_not_support,/*interval*/ - cast_not_support,/*rowid*/ - cast_inconsistent_types,/*lob*/ - cast_inconsistent_types,/*json*/ - cast_not_support,/*decimalint*/ - cast_to_udt_not_support, /*decimal int*/ + cast_inconsistent_types,/*otimestamp*/ + cast_inconsistent_types,/*raw*/ + cast_inconsistent_types,/*interval*/ + cast_inconsistent_types,/*rowid*/ + decimalint_lob,/*lob*/ + decimalint_json,/*json*/ + cast_not_support,/*geometry*/ + cast_to_udt_not_support, /*udt*/ decimalint_decimalint,/*decimalint*/ + cast_to_udt_not_support, /*collection*/ + }, + { + /*collection -> XXX*/ + cast_udt_to_other_not_support,/*null*/ + cast_udt_to_other_not_support,/*int*/ + cast_udt_to_other_not_support,/*uint*/ + cast_udt_to_other_not_support,/*float*/ + cast_udt_to_other_not_support,/*double*/ + cast_udt_to_other_not_support,/*number*/ + cast_udt_to_other_not_support,/*datetime*/ + cast_udt_to_other_not_support,/*date*/ + cast_udt_to_other_not_support,/*time*/ + cast_udt_to_other_not_support,/*year*/ + udt_string,/*string*/ + sql_udt_pl_extend,/*extend*/ + cast_udt_to_other_not_support,/*unknown*/ + cast_udt_to_other_not_support,/*text*/ + cast_udt_to_other_not_support,/*bit*/ + cast_udt_to_other_not_support,/*enumset*/ + cast_udt_to_other_not_support,/*enumset_inner*/ + cast_udt_to_other_not_support,/*otimestamp*/ + cast_udt_to_other_not_support,/*raw*/ + cast_udt_to_other_not_support,/*interval*/ + cast_udt_to_other_not_support,/*rowid*/ + cast_udt_to_other_not_support,/*lob*/ + cast_udt_to_other_not_support,/*json*/ + cast_udt_to_other_not_support,/*geometry*/ + cast_udt_to_other_not_support,/*udt*/ + cast_udt_to_other_not_support,/*decimalint*/ + cast_udt_to_other_not_support,/*collection*/ } }; @@ -12995,6 +13343,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_eval_arg,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ cast_eval_arg,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*int -> XXX*/ @@ -13024,6 +13373,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = int_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ int_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*uint -> XXX*/ @@ -13053,6 +13403,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = uint_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ uint_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*float -> XXX*/ @@ -13082,6 +13433,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = float_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ float_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*double -> XXX*/ @@ -13111,6 +13463,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = double_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ double_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*number -> XXX*/ @@ -13140,6 +13493,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = number_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ number_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*datetime -> XXX*/ @@ -13169,6 +13523,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = datetime_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ datetime_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*date -> XXX*/ @@ -13198,6 +13553,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = date_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ date_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*time -> XXX*/ @@ -13227,6 +13583,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = time_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ time_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*year -> XXX*/ @@ -13256,6 +13613,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = year_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ year_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*string -> XXX*/ @@ -13285,6 +13643,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = string_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ string_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*extend -> XXX*/ @@ -13314,6 +13673,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_support,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ cast_not_support,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*unknown -> XXX*/ @@ -13343,6 +13703,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ unknown_other,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*text -> XXX*/ @@ -13372,6 +13733,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = string_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ text_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*bit -> XXX*/ @@ -13401,6 +13763,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = bit_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ bit_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*enumset -> XXX*/ @@ -13430,6 +13793,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ enumset_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*enumset_inner -> XXX*/ @@ -13459,6 +13823,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ enumset_inner_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*otimestamp -> XXX*/ @@ -13488,6 +13853,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*raw -> XXX*/ @@ -13517,6 +13883,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*interval -> XXX*/ @@ -13546,6 +13913,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*rowid -> XXX*/ @@ -13575,6 +13943,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*lob -> XXX*/ @@ -13604,6 +13973,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*json -> XXX*/ @@ -13633,6 +14003,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = json_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ json_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*geometry -> XXX*/ @@ -13662,6 +14033,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = geometry_geometry,/*geometry*/ cast_not_expected, /*udt*/ geometry_decimalint,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, { /*udt -> XXX*/ @@ -13691,6 +14063,7 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = cast_not_expected,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ cast_not_expected, /*decimal int*/ + cast_not_expected,/*collection*/ }, { /*decimalint -> XXX*/ @@ -13720,6 +14093,37 @@ ObExpr::EvalFunc OB_DATUM_CAST_MYSQL_IMPLICIT[ObMaxTC][ObMaxTC] = decimalint_geometry,/*geometry*/ cast_not_expected,/*udt, not implemented in mysql mode*/ decimalint_decimalint, /*decimal int*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ + }, + { + /*collection -> XXX*/ + cast_not_expected,/*null*/ + cast_not_expected,/*int*/ + cast_not_expected,/*uint*/ + cast_not_expected,/*float*/ + cast_not_expected,/*double*/ + cast_not_expected,/*number*/ + cast_not_expected,/*datetime*/ + cast_not_expected,/*date*/ + cast_not_expected,/*time*/ + cast_not_expected,/*year*/ + cast_not_expected,/*string*/ + cast_not_expected,/*extend*/ + cast_not_expected,/*unknown*/ + cast_not_expected,/*text*/ + cast_not_expected,/*bit*/ + cast_not_expected,/*enumset*/ + cast_not_expected,/*enumset_inner*/ + cast_not_expected,/*otimestamp*/ + cast_not_expected,/*raw*/ + cast_not_expected,/*interval*/ + cast_not_expected,/*rowid*/ + cast_not_expected,/*lob*/ + cast_not_expected,/*json*/ + cast_not_expected,/*geometry*/ + cast_not_expected,/*udt, not implemented in mysql mode*/ + cast_not_expected,/*decimalint*/ + cast_not_expected,/*collection, not implemented in mysql mode*/ }, }; @@ -13855,6 +14259,11 @@ ObExpr::EvalEnumSetFunc OB_DATUM_CAST_MYSQL_ENUMSET_IMPLICIT[ObMaxTC][2] = decimalint_enum,/*enum*/ decimalint_set,/*set*/ }, + { + /*ObCollectionSQLTC -> enum_or_set*/ + cast_not_support_enum_set,/*enum*/ + cast_not_support_enum_set,/*set*/ + }, }; int string_collation_check(const bool is_strict_mode, @@ -14282,7 +14691,8 @@ int ObDatumCaster::to_type(const ObDatumMeta &dst_type, const ObExpr &src_expr, const ObCastMode &cm, ObDatum *&res, - int64_t batch_idx) + int64_t batch_idx, + const uint16_t subschema_id) { int ret = OB_SUCCESS; const ObDatumMeta &src_type = src_expr.datum_meta_; @@ -14341,7 +14751,7 @@ int ObDatumCaster::to_type(const ObDatumMeta &dst_type, LOG_WARN("setup_cast_expr failed", K(ret)); } } else { - if (OB_FAIL(setup_cast_expr(dst_type, src_expr, cm, *cast_expr_))) { + if (OB_FAIL(setup_cast_expr(dst_type, src_expr, cm, *cast_expr_, subschema_id))) { LOG_WARN("setup_cast_expr failed", K(ret)); } } @@ -14437,7 +14847,8 @@ int ObDatumCaster::destroy() int ObDatumCaster::setup_cast_expr(const ObDatumMeta &dst_type, const ObExpr &src_expr, const ObCastMode cm, - ObExpr &cast_expr) + ObExpr &cast_expr, + const uint16_t subschema_id) { int ret = OB_SUCCESS; const ObDatumMeta &src_type = src_expr.datum_meta_; @@ -14473,10 +14884,14 @@ int ObDatumCaster::setup_cast_expr(const ObDatumMeta &dst_type, cast_expr.obj_meta_.set_has_lob_header(); } } - // implicit cast donot use these, so we set it all invalid. - if (ob_is_user_defined_pl_type(src_expr.obj_meta_.get_type()) && dst_type.type_ == ObUserDefinedSQLType) { - cast_expr.obj_meta_.set_sql_udt(ObXMLSqlType); + // ObDatumMeta does not have cs_level, deduce subschema id from source + if (cast_expr.obj_meta_.is_user_defined_sql_type() || cast_expr.obj_meta_.is_collection_sql_type()) { + cast_expr.obj_meta_.set_subschema_id(subschema_id); } + if (ob_is_user_defined_pl_type(src_expr.obj_meta_.get_type()) && dst_type.type_ == ObUserDefinedSQLType) { + cast_expr.obj_meta_.set_subschema_id(subschema_id); + } + // implicit cast donot use these, so we set it all invalid. cast_expr.parents_ = NULL; cast_expr.parent_cnt_ = 0; cast_expr.basic_funcs_ = NULL; diff --git a/src/sql/engine/expr/ob_datum_cast.h b/src/sql/engine/expr/ob_datum_cast.h index 3c9ef78803..b9af939279 100644 --- a/src/sql/engine/expr/ob_datum_cast.h +++ b/src/sql/engine/expr/ob_datum_cast.h @@ -461,11 +461,14 @@ public: // same with ObObjCaster::to_type(). // input is ObExpr, and output is ObDatum, it's better if input is also ObDatum. // we will do this later if necessary. + // subschema id from sql udt type is a combination of (cs_type_ and cs_level_), + // datum meta does not have cs_level_, or we can use ObDatum precision_ as subschema id? int to_type(const ObDatumMeta &dst_type, const ObExpr &src_expr, const common::ObCastMode &cm, common::ObDatum *&res, - int64_t batch_idx = 0); + int64_t batch_idx = 0, + const uint16_t subschema_id = 0); // for xxx -> enumset. int to_type(const ObDatumMeta &dst_type, const common::ObIArray &str_values, @@ -484,7 +487,8 @@ private: int setup_cast_expr(const ObDatumMeta &dst_type, const ObExpr &src_expr, const common::ObCastMode cm, - ObExpr &cast_expr); + ObExpr &cast_expr, + const uint16_t subschema_id = 0); bool inited_; ObEvalCtx *eval_ctx_; ObExpr *cast_expr_; diff --git a/src/sql/engine/expr/ob_expr.cpp b/src/sql/engine/expr/ob_expr.cpp index 084c56e4aa..0e6b928af1 100644 --- a/src/sql/engine/expr/ob_expr.cpp +++ b/src/sql/engine/expr/ob_expr.cpp @@ -469,6 +469,11 @@ int ObDatumObjParam::to_objparam(common::ObObjParam &obj_param, ObIAllocator *al if (res_flags_ & HAS_LOB_HEADER_FLAG) { meta.set_has_lob_header(); } + if (ob_is_user_defined_sql_type(meta_.type_) && + meta_.cs_type_ == CS_TYPE_INVALID) { + // xmltype + meta.set_collation_level(CS_LEVEL_EXPLICIT); + } if (OB_UNLIKELY(meta_.is_ext_sql_array())) { if (OB_ISNULL(allocator)) { ret = OB_ERR_UNEXPECTED; @@ -1322,6 +1327,7 @@ int eval_assign_question_mark_func(const ObExpr &expr, ObEvalCtx &ctx, ObDatum & res_acc.precision_ = expr.datum_meta_.precision_; cast_ctx.res_accuracy_ = &res_acc; } + cast_ctx.exec_ctx_ = &ctx.exec_ctx_; if (OB_FAIL(ObObjCaster::to_type(dst_meta.get_type(), cast_ctx, v, dst_obj))) { LOG_WARN("failed to cast obj to dst type", K(ret), K(v), K(dst_meta)); } else if (OB_FAIL(datum_param.alloc_datum_reserved_buff( diff --git a/src/sql/engine/expr/ob_expr.h b/src/sql/engine/expr/ob_expr.h index c12cc68c8e..b621ad83dd 100644 --- a/src/sql/engine/expr/ob_expr.h +++ b/src/sql/engine/expr/ob_expr.h @@ -354,7 +354,8 @@ struct ObDynReserveBuf || common::ObLobTC == tc || common::ObJsonTC == tc || common::ObGeometryTC == tc - || common::ObUserDefinedSQLTC == tc; + || common::ObUserDefinedSQLTC == tc + || common::ObCollectionSQLTC == tc; } ObDynReserveBuf() = default; diff --git a/src/sql/engine/expr/ob_expr_abs_result_type.map b/src/sql/engine/expr/ob_expr_abs_result_type.map index a35289c2f9..e146bafe82 100644 --- a/src/sql/engine/expr/ob_expr_abs_result_type.map +++ b/src/sql/engine/expr/ob_expr_abs_result_type.map @@ -51,6 +51,7 @@ static constexpr ObObjType ABS_RESULT_TYPE[ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }; @@ -107,6 +108,7 @@ static constexpr ObObjType ABS_RESULT_TYPE_ORACLE[ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }; static_assert(is_array_fully_initialized(ABS_RESULT_TYPE_ORACLE), "ABS_RESULT_TYPE_ORACLE is partially initlized"); diff --git a/src/sql/engine/expr/ob_expr_arithmetic_result_type.map b/src/sql/engine/expr/ob_expr_arithmetic_result_type.map index dd3dfa0493..883190ffd2 100644 --- a/src/sql/engine/expr/ob_expr_arithmetic_result_type.map +++ b/src/sql/engine/expr/ob_expr_arithmetic_result_type.map @@ -53,6 +53,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*TinyIntType*/ @@ -108,6 +109,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*SmallIntType*/ @@ -163,6 +165,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*MediumIntType*/ @@ -218,6 +221,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*Int32Type*/ @@ -273,6 +277,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*IntType*/ @@ -328,6 +333,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UTinyIntType*/ @@ -383,6 +389,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*USmallIntType*/ @@ -438,6 +445,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UMediumIntType*/ @@ -493,6 +501,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UInt32Type*/ @@ -548,6 +557,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UInt64Type*/ @@ -603,6 +613,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*FloatType*/ @@ -658,6 +669,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*DoubleType*/ @@ -713,6 +725,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UFloatType*/ @@ -768,6 +781,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UDoubleType*/ @@ -823,6 +837,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*NumberType*/ @@ -878,6 +893,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UNumberType*/ @@ -933,6 +949,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*DateTimeType*/ @@ -988,6 +1005,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*TimestampType*/ @@ -1043,6 +1061,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*DateType*/ @@ -1098,6 +1117,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*TimeType*/ @@ -1153,6 +1173,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*YearType*/ @@ -1208,6 +1229,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*VarcharType*/ @@ -1263,6 +1285,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*CharType*/ @@ -1318,6 +1341,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*HexStringType*/ @@ -1373,6 +1397,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ExtendType*/ @@ -1428,6 +1453,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UnknownType*/ @@ -1483,6 +1509,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTinyTextType*/ { @@ -1537,6 +1564,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTextType*/ { @@ -1591,6 +1619,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObMediumTextType*/ { @@ -1645,6 +1674,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObLongTextType*/ { @@ -1699,6 +1729,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*BitType*/ { @@ -1753,6 +1784,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObEnumType*/ { @@ -1807,6 +1839,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObSetType*/ { @@ -1861,6 +1894,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObEnumInnerType*/ { @@ -1915,6 +1949,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObSetInnerType*/ { @@ -1969,6 +2004,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTimestampTZType*/ { @@ -2023,6 +2059,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTimestampLTZType*/ { @@ -2077,6 +2114,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /* ObTimestampNanoType*/ { @@ -2131,6 +2169,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObRawType*/ { @@ -2185,6 +2224,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObIntervalYMType*/ { @@ -2239,6 +2279,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObIntervalDSType*/ { @@ -2293,6 +2334,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObNumberFloatType*/ { @@ -2347,6 +2389,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObNVarchar2Type*/ { @@ -2401,6 +2444,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObNCharType*/ { @@ -2455,6 +2499,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObURowIDType*/ { @@ -2509,6 +2554,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObLobType*/ { @@ -2563,6 +2609,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObJsonType*/ { @@ -2617,6 +2664,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObGeometryType*/ { @@ -2671,6 +2719,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObUserDefinedSqlType*/ { @@ -2725,6 +2774,7 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSqlType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObDecimalIntType*/ { @@ -2779,6 +2829,62 @@ static constexpr ObObjType ARITH_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ + }, + /*ObCollectionSqlType*/ + { + ObMaxType, /* NullType */ + ObMaxType, /* TinyIntType */ + ObMaxType, /* SmallIntType */ + ObMaxType, /* MediumIntType */ + ObMaxType, /* Int32Type */ + ObMaxType, /* IntType */ + ObMaxType, /* UTinyIntType */ + ObMaxType, /* USmallIntType */ + ObMaxType, /* UMediumIntType */ + ObMaxType, /* UInt32Type */ + ObMaxType, /* UInt64Type */ + ObMaxType, /* FloatType */ + ObMaxType, /* DoubleType */ + ObMaxType, /* UFloatType */ + ObMaxType, /* UDoubleType */ + ObMaxType, /* NumberType */ + ObMaxType, /* UNumberType */ + ObMaxType, /* DateTimeType */ + ObMaxType, /* TimestampType */ + ObMaxType, /* DateType */ + ObMaxType, /* TimeType */ + ObMaxType, /* YearType */ + ObMaxType, /* VarcharType */ + ObMaxType, /* CharType */ + ObMaxType, /* HexStringType */ + ObMaxType, /* ExtendType */ + ObMaxType, /* UnknownType */ + ObMaxType, /* ObTinyTextType */ + ObMaxType, /* ObTextType */ + ObMaxType, /* ObMediumTextType */ + ObMaxType, /* ObLongTextType */ + ObMaxType, /* ObBitType */ + ObMaxType, /* ObEnumType */ + ObMaxType, /* ObSetType */ + ObMaxType, /* ObEnumInnerType */ + ObMaxType, /* ObSetInnerType */ + ObMaxType, /* ObTimestampTZType */ + ObMaxType, /* ObTimestampLTZType */ + ObMaxType, /* ObTimestampNanoType */ + ObMaxType, /* ObRawType */ + ObMaxType, /* ObIntervalYMType */ + ObMaxType, /* ObIntervalDSType */ + ObMaxType, /* ObNumberFloatType */ + ObMaxType, /* ObNVarchar2Type */ + ObMaxType, /* ObNCharType */ + ObMaxType, /* ObURowIDType */ + ObMaxType, /* ObLobType */ + ObMaxType, /* ObJsonType */ + ObMaxType, /* ObGeometryType */ + ObMaxType, /* ObUserDefinedSqlType */ + ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, }; diff --git a/src/sql/engine/expr/ob_expr_cast.cpp b/src/sql/engine/expr/ob_expr_cast.cpp index f7ab9e13c4..56c52398b4 100644 --- a/src/sql/engine/expr/ob_expr_cast.cpp +++ b/src/sql/engine/expr/ob_expr_cast.cpp @@ -348,13 +348,19 @@ int ObExprCast::calc_result_type2(ObExprResType &type, } else if (OB_FAIL(get_cast_type(enable_decimalint, type2, cast_raw_expr->get_extra(), dst_type))) { LOG_WARN("get cast dest type failed", K(ret)); - } else if (OB_FAIL(adjust_udt_cast_type(type1, dst_type))) { + } else if (OB_FAIL(adjust_udt_cast_type(type1, dst_type, type_ctx))) { LOG_WARN("adjust udt cast sub type failed", K(ret)); } else if (OB_UNLIKELY(!cast_supported(type1.get_type(), type1.get_collation_type(), dst_type.get_type(), dst_type.get_collation_type()))) { if (session->is_varparams_sql_prepare()) { type.set_null(); LOG_TRACE("ps prepare phase ignores type deduce error"); + } else if (const_cast(session)->is_pl_prepare_stage() + && dst_type.is_geometry() + && lib::is_oracle_mode()) { + // oracle gis ignore ignore type deduce error in pl prepare + type.set_geometry(); + LOG_TRACE("pl prepare phase ignores type deduce error"); } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("transition does not support", "src", ob_obj_type_str(type1.get_type()), @@ -409,7 +415,7 @@ int ObExprCast::calc_result_type2(ObExprResType &type, type.set_precision(float_precision); type.set_scale(float_scale); } - } else if (dst_type.is_user_defined_sql_type()) { + } else if (dst_type.is_user_defined_sql_type() || dst_type.is_collection_sql_type()) { type.set_type(dst_type.get_type()); type.set_subschema_id(dst_type.get_subschema_id()); } else { @@ -462,7 +468,9 @@ int ObExprCast::calc_result_type2(ObExprResType &type, type.set_collation_type(ob_is_nstring_type(dst_type.get_type()) ? collation_nation : collation_connection); } - } else if (ob_is_extend(dst_type.get_type())) { + } else if (ob_is_extend(dst_type.get_type()) + || dst_type.is_user_defined_sql_type() + || dst_type.is_collection_sql_type()) { type.set_udt_id(type2.get_udt_id()); } else { type.set_length(length); @@ -640,18 +648,15 @@ int ObExprCast::get_cast_type(const bool enable_decimal_int, } } else if (ob_is_raw(obj_type)) { dst_type.set_length(parse_node.int32_values_[OB_NODE_CAST_C_LEN_IDX]); - } else if (ob_is_extend(obj_type)) { + } else if (ob_is_extend(obj_type) + || ob_is_user_defined_sql_type(obj_type) + || ob_is_collection_sql_type(obj_type)) { dst_type.set_udt_id(param_type2.get_udt_id()); } else if (lib::is_mysql_mode() && ob_is_json(obj_type)) { dst_type.set_collation_type(CS_TYPE_UTF8MB4_BIN); } else if (ob_is_geometry(obj_type)) { - if (lib::is_mysql_mode()) { - dst_type.set_collation_type(CS_TYPE_BINARY); - dst_type.set_collation_level(CS_LEVEL_IMPLICIT); - } else { - ret = OB_NOT_SUPPORTED; - LOG_WARN("not support cast to geometry in oracle mode", K(ret)); - } + dst_type.set_collation_type(CS_TYPE_BINARY); + dst_type.set_collation_level(CS_LEVEL_IMPLICIT); } else if (ob_is_interval_tc(obj_type)) { if (CM_IS_EXPLICIT_CAST(cast_mode) && ((ObIntervalYMType != obj_type && !ObIntervalScaleUtil::scale_check(parse_node.int16_values_[OB_NODE_CAST_N_PREC_IDX])) || @@ -695,36 +700,140 @@ int ObExprCast::get_cast_type(const bool enable_decimal_int, return ret; } -int ObExprCast::adjust_udt_cast_type(const ObExprResType &src_type, ObExprResType &dst_type) const +int ObExprCast::adjust_udt_cast_type(const ObExprResType &src_type, + ObExprResType &dst_type, + ObExprTypeCtx &type_ctx) const { + // set subschema id in this function for cast int ret = OB_SUCCESS; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); if (src_type.is_ext()) { - if (dst_type.is_user_defined_sql_type()) { - if (src_type.get_udt_id() == T_OBJ_XML) { - dst_type.set_sql_udt(ObXMLSqlType); - } else { + if (dst_type.is_user_defined_sql_type() || dst_type.is_collection_sql_type()) { + // phy_plan_ctx_ may not exist during deduce, + // save subschema mapping on sql_ctx_ before phy_plan ready? + const uint64_t udt_type_id = src_type.get_udt_id(); + uint16_t subschema_id = ObMaxSystemUDTSqlType; + + if (udt_type_id == T_OBJ_XML) { + subschema_id = 0; + } else if (OB_ISNULL(exec_ctx)) { + ret = OB_BAD_NULL_ERROR; + LOG_WARN("need ctx to get subschema mapping", + K(ret), K(src_type), K(dst_type), KP(session), KP(exec_ctx)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_udt_id(udt_type_id, subschema_id))) { + LOG_WARN("failed to get subshcema_meta_info", + K(ret), K(src_type), K(dst_type), K(udt_type_id)); + } else if (dst_type.get_udt_id() != src_type.get_udt_id()) { + // not xmltype, udt id must setted in both pl types and sql types + ret = OB_ERR_UNEXPECTED; + LOG_WARN("udt id mismarch", K(ret), K(src_type), K(dst_type), + K(dst_type.get_udt_id()), K(src_type.get_udt_id())); + } + + if (OB_FAIL(ret)) { + } else if (subschema_id == ObMaxSystemUDTSqlType) { ret = OB_NOT_SUPPORTED; - LOG_WARN("cast unsupported pl udt type to sql udt type", K(ret), K(src_type), K(dst_type)); + LOG_WARN("cast unsupported pl udt type to sql udt type", + K(ret), K(src_type), K(dst_type), K(udt_type_id)); + } else { + dst_type.set_subschema_id(subschema_id); + dst_type.set_udt_id(udt_type_id); } } else if (dst_type.is_character_type() && !is_called_in_sql()) { ret = OB_ERR_EXPRESSION_WRONG_TYPE; LOG_WARN("PLS-00382: expression is of wrong type", K(ret), K(src_type), K(dst_type)); + } else if (dst_type.is_ext()) { + // disallow PL sdo_geometry cast + uint64_t src_udt_id = src_type.get_udt_id(); + uint64_t dst_udt_id = dst_type.get_udt_id(); + if (ObGeometryTypeCastUtil::is_sdo_geometry_udt(src_udt_id) + && ObGeometryTypeCastUtil::is_sdo_geometry_udt(dst_udt_id)) { + if (!ObGeometryTypeCastUtil::is_sdo_geometry_type_compatible(src_udt_id, dst_udt_id)) { + ret = OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("udt id mismatch", K(ret), K(src_type), K(dst_type), + K(src_udt_id), K(dst_udt_id)); + } + } } - } else if (src_type.is_user_defined_sql_type()) { + } else if (src_type.is_user_defined_sql_type() || src_type.is_collection_sql_type()) { + const uint16_t subschema_id = src_type.get_subschema_id(); // do not need subschema id ? + uint64_t udt_id = 0; + uint64_t src_udt_id = src_type.get_udt_id(); + uint64_t dst_udt_id = dst_type.get_udt_id(); if (dst_type.is_ext()) { - if (src_type.is_xml_sql_type()) { - dst_type.set_udt_id(T_OBJ_XML); - } else { + ObSqlUDTMeta udt_meta; + if (subschema_id == ObXMLSqlType) { + udt_id = T_OBJ_XML; + } else if (OB_ISNULL(exec_ctx)) { + ret = OB_BAD_NULL_ERROR; + LOG_WARN("need ctx to get subschema mapping", + K(ret), K(src_type), K(dst_type), KP(session), KP(exec_ctx)); + } else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("Failed to get subshcema_meta_info", + K(ret), K(src_type), K(dst_type), K(udt_meta.udt_id_)); + } else if (udt_meta.udt_id_ == T_OBJ_NOT_SUPPORTED) { ret = OB_NOT_SUPPORTED; - LOG_WARN("cast unsupported sql udt type to pl udt type", K(ret), K(src_type), K(dst_type)); + LOG_WARN("cast unsupported sql udt type to pl udt type", + K(ret), K(src_type), K(dst_type), K(subschema_id)); + } else if (ObGeometryTypeCastUtil::is_sdo_geometry_udt(src_udt_id) + && ObGeometryTypeCastUtil::is_sdo_geometry_udt(dst_udt_id)) { + uint16_t dst_subschema_id = ObInvalidSqlType; + if (!ObGeometryTypeCastUtil::is_sdo_geometry_type_compatible(src_udt_id, dst_udt_id)) { + ret = OB_ERR_EXPRESSION_WRONG_TYPE; + LOG_WARN("udt id mismatch", K(ret), K(src_type), K(dst_type), + K(src_udt_id), K(dst_udt_id)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_udt_id(dst_udt_id, dst_subschema_id))) { + LOG_WARN("unsupported udt id", K(ret), K(dst_subschema_id)); + } else { + dst_type.set_type(ObUserDefinedSQLType); + dst_type.set_subschema_id(dst_subschema_id); + udt_id = dst_udt_id; + } + } else if (dst_udt_id != src_udt_id) { + // not xmltype or sdo_geometry, udt id must setted in both pl types and sql types + ret = OB_ERR_UNEXPECTED; + LOG_WARN("udt id mismatch", K(ret), K(src_type), K(dst_type), + K(dst_udt_id), K(src_udt_id)); + } else { + udt_id = udt_meta.udt_id_; + } + + if (OB_SUCC(ret)) { + dst_type.set_udt_id(udt_id); } } else if (dst_type.is_user_defined_sql_type()) { - dst_type.set_subschema_id(ObXMLSqlType); + dst_type.set_subschema_id(subschema_id); + LOG_INFO("cast from sql udt to sql udt", K(src_type), K(dst_type), K(lbt())); } - } else if (src_type.is_null() || src_type.is_character_type()) { - // null or chararcter type can cast to xmltype (other udt types are not supported yet) - if (dst_type.get_type() == ObUserDefinedSQLType) { - dst_type.set_sql_udt(ObXMLSqlType); + } else if ((src_type.is_null() || src_type.is_character_type()) + && (dst_type.get_type() == ObUserDefinedSQLType + || dst_type.get_type() == ObCollectionSQLType)) { + const uint64_t udt_type_id = dst_type.get_udt_id(); + uint16_t subschema_id = ObMaxSystemUDTSqlType; + + if (!ObObjUDTUtil::ob_is_supported_sql_udt(dst_type.get_udt_id())) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported udt type for sql udt", K(ret), K(src_type), K(dst_type), + K(dst_type.get_udt_id()), K(src_type.get_udt_id())); + } else if (udt_type_id == T_OBJ_XML) { + subschema_id = 0; + } else if (OB_ISNULL(exec_ctx)) { + ret = OB_BAD_NULL_ERROR; + LOG_WARN("need ctx to get subschema mapping", + K(ret), K(src_type), K(dst_type), KP(session), KP(exec_ctx)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_udt_id(udt_type_id, subschema_id))) { + LOG_WARN("failed to get subshcema_meta_info", + K(ret), K(src_type), K(dst_type), K(udt_type_id)); + } else { /* do nothing */ } + + if (OB_FAIL(ret)) { + } else if (subschema_id == ObMaxSystemUDTSqlType) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("cast unsupported pl udt type to sql udt type", + K(ret), K(src_type), K(dst_type), K(udt_type_id)); + } else { + dst_type.set_subschema_id(subschema_id); } } return ret; diff --git a/src/sql/engine/expr/ob_expr_cast.h b/src/sql/engine/expr/ob_expr_cast.h index c8ade96dba..615c04fd4e 100644 --- a/src/sql/engine/expr/ob_expr_cast.h +++ b/src/sql/engine/expr/ob_expr_cast.h @@ -28,7 +28,7 @@ namespace sql { // The length of array need to be equal to the number of types defined at ObObjType -static const int32_t CAST_STRING_DEFUALT_LENGTH[52] = { +static const int32_t CAST_STRING_DEFUALT_LENGTH[53] = { 0, //null 4, //tinyint 6, //smallint @@ -80,6 +80,7 @@ static const int32_t CAST_STRING_DEFUALT_LENGTH[52] = { 1,//geometry 1,//udt 11, // decimal int + 1,//collection 0//max, invalid type, or count of obj type }; @@ -177,7 +178,7 @@ private: ObExpr **subquery_row, ObEvalCtx *subquery_ctx, ObSubQueryIterator *subquery_iter); - int adjust_udt_cast_type(const ObExprResType &src_type, ObExprResType &dst_type) const; + int adjust_udt_cast_type(const ObExprResType &src_type, ObExprResType &dst_type, ObExprTypeCtx &type_ctx) const; private: int get_cast_string_len(ObExprResType &type1, diff --git a/src/sql/engine/expr/ob_expr_collection_construct.cpp b/src/sql/engine/expr/ob_expr_collection_construct.cpp index 6d30409cf0..9ae22efd06 100644 --- a/src/sql/engine/expr/ob_expr_collection_construct.cpp +++ b/src/sql/engine/expr/ob_expr_collection_construct.cpp @@ -221,9 +221,16 @@ int ObExprCollectionConstruct::eval_collection_construct(const ObExpr &expr, const pl::ObCollectionType *collection_type = NULL; pl::ObElemDesc elem_desc; pl::ObPLPackageGuard package_guard(session->get_effective_tenant_id()); + ObSchemaGetterGuard *schema_guard = NULL; + // if called by check_default_value in ddl resolver, no sql ctx, get guard from session cache + if (OB_ISNULL(exec_ctx.get_sql_ctx()) || OB_ISNULL(exec_ctx.get_sql_ctx()->schema_guard_)) { + schema_guard = &session->get_cached_schema_guard_info().get_schema_guard(); + } else { + schema_guard = exec_ctx.get_sql_ctx()->schema_guard_; + } pl::ObPLResolveCtx resolve_ctx(alloc, *session, - *(exec_ctx.get_sql_ctx()->schema_guard_), + *(schema_guard), package_guard, *(exec_ctx.get_sql_proxy()), false); diff --git a/src/sql/engine/expr/ob_expr_column_conv.cpp b/src/sql/engine/expr/ob_expr_column_conv.cpp index 3cdb61f91b..83edd1db50 100644 --- a/src/sql/engine/expr/ob_expr_column_conv.cpp +++ b/src/sql/engine/expr/ob_expr_column_conv.cpp @@ -244,8 +244,24 @@ int ObExprColumnConv::calc_result_typeN(ObExprResType &type, ObCollationLevel coll_level = ObRawExprUtils::get_column_collation_level(types[0].get_type()); type.set_collation_level(coll_level); type.set_accuracy(types[2].get_accuracy()); - if (type.get_type() == ObUserDefinedSQLType) { - type.set_subschema_id(types[2].get_accuracy().get_accuracy()); + if (type.get_type() == ObUserDefinedSQLType + || type.get_type() == ObCollectionSQLType) { + uint64_t udt_id = types[2].get_accuracy().get_accuracy(); + uint16_t subschema_id = ObMaxSystemUDTSqlType; + // need const cast to modify subschema ctx, in physcial plan ctx belong to cur exec_ctx; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + if (udt_id == T_OBJ_XML) { + subschema_id = ObXMLSqlType; + } else if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("need context to search subschema mapping", K(ret), K(udt_id)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_udt_id(udt_id, subschema_id))) { + LOG_WARN("failed to get sub schema id", K(ret), K(udt_id)); + } + if (OB_SUCC(ret)) { + type.set_subschema_id(subschema_id); + } } if (types[3].is_not_null_for_read()) { type.set_result_flag(NOT_NULL_FLAG | NOT_NULL_WRITE_FLAG); @@ -253,7 +269,7 @@ int ObExprColumnConv::calc_result_typeN(ObExprResType &type, bool enumset_to_varchar = false; //here will wrap type_to_str if necessary - if (ob_is_enumset_tc(types[4].get_type())) { + if (OB_SUCC(ret) && ob_is_enumset_tc(types[4].get_type())) { ObObjType calc_type = enumset_calc_types_[OBJ_TYPE_TO_CLASS[types[0].get_type()]]; if (OB_UNLIKELY(ObMaxType == calc_type)) { ret = OB_ERR_UNEXPECTED; @@ -281,9 +297,12 @@ int ObExprColumnConv::calc_result_typeN(ObExprResType &type, //cast type when type not same. const ObObjTypeClass value_tc = ob_obj_type_class(types[4].get_type()); const ObObjTypeClass type_tc = ob_obj_type_class(types[0].get_type()); + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + bool is_prepare_stage = session->is_pl_prepare_stage(); if (lib::is_oracle_mode() && OB_UNLIKELY(!cast_supported(types[4].get_type(), types[4].get_collation_type(), - types[0].get_type(), types[1].get_collation_type()))) { + types[0].get_type(), types[1].get_collation_type())) + && !(is_prepare_stage && type_tc == ObGeometryTC)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("inconsistent datatypes", "expected", type_tc, "got", value_tc); } else { @@ -295,6 +314,9 @@ int ObExprColumnConv::calc_result_typeN(ObExprResType &type, // decimal/number int need to setup calc accuracy types[4].set_calc_accuracy(type.get_accuracy()); type.set_collation_level(common::CS_LEVEL_NUMERIC); + } else if (ob_is_user_defined_type(type.get_type()) + || ob_is_collection_sql_type(type.get_type())) { // if calc meta is udt, set calc udt id + types[4].set_calc_accuracy(type.get_accuracy()); } } } diff --git a/src/sql/engine/expr/ob_expr_div_result_type.map b/src/sql/engine/expr/ob_expr_div_result_type.map index 469828feaf..625c8bd083 100644 --- a/src/sql/engine/expr/ob_expr_div_result_type.map +++ b/src/sql/engine/expr/ob_expr_div_result_type.map @@ -53,6 +53,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*TinyIntType*/ @@ -108,6 +109,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*SmallIntType*/ @@ -163,6 +165,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*MediumIntType*/ @@ -218,6 +221,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*Int32Type*/ @@ -273,6 +277,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*IntType*/ @@ -328,6 +333,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UTinyIntType*/ @@ -383,6 +389,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*USmallIntType*/ @@ -438,6 +445,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UMediumIntType*/ @@ -493,6 +501,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UInt32Type*/ @@ -548,6 +557,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UIntType*/ @@ -603,6 +613,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*FloatType*/ @@ -658,6 +669,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*DoubleType*/ @@ -713,6 +725,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UFloatType*/ @@ -768,6 +781,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UDoubleType*/ @@ -823,6 +837,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*NumberType*/ @@ -878,6 +893,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UNumberType*/ @@ -933,6 +949,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*DateTimeType*/ @@ -988,6 +1005,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*TimestampType*/ @@ -1043,6 +1061,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*DateType*/ @@ -1098,6 +1117,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*TimeType*/ @@ -1153,6 +1173,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*YearType*/ @@ -1208,6 +1229,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*VarcharType*/ @@ -1263,6 +1285,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*CharType*/ @@ -1318,6 +1341,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*HexStringType*/ @@ -1373,6 +1397,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ExtendType*/ @@ -1428,6 +1453,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UnknownType*/ @@ -1483,6 +1509,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTinyTextType*/ { @@ -1537,6 +1564,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTextType*/ { @@ -1591,6 +1619,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObMediumTextType*/ { @@ -1645,6 +1674,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObLongTextType*/ { @@ -1699,6 +1729,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*BitType*/ { @@ -1753,6 +1784,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObEnumType*/ { @@ -1807,6 +1839,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObSetType*/ { @@ -1861,6 +1894,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObEnumInnerType*/ { @@ -1915,6 +1949,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObSetInnerType*/ { @@ -1969,6 +2004,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTimestampTZType*/ { @@ -2023,6 +2059,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTimestampLTZType*/ { @@ -2077,6 +2114,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTimestampNanoType*/ { @@ -2131,6 +2169,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObRawType*/ { @@ -2185,6 +2224,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObIntervalYMType*/ { @@ -2239,6 +2279,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObIntervalDSType*/ { @@ -2293,6 +2334,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObNumberFloatType*/ { @@ -2347,6 +2389,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObNVarchar2Type*/ { @@ -2401,6 +2444,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObNCharType*/ { @@ -2455,6 +2499,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObURowIDType*/ { @@ -2509,6 +2554,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObLobType*/ { @@ -2563,6 +2609,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObJsonType*/ { @@ -2617,6 +2664,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObGeometryType*/ { @@ -2671,6 +2719,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObUserDefinedSQLType*/ { @@ -2725,6 +2774,7 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObDecimalIntType*/ { @@ -2779,6 +2829,62 @@ static constexpr ObObjType DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ + }, + /*ObCollectionSQLType*/ + { + ObMaxType, /* NullType */ + ObMaxType, /* TinyIntType */ + ObMaxType, /* SmallIntType */ + ObMaxType, /* MediumIntType */ + ObMaxType, /* Int32Type */ + ObMaxType, /* IntType */ + ObMaxType, /* UTinyIntType */ + ObMaxType, /* USmallIntType */ + ObMaxType, /* UMediumIntType */ + ObMaxType, /* UInt32Type */ + ObMaxType, /* UInt64Type */ + ObMaxType, /* FloatType */ + ObMaxType, /* DoubleType */ + ObMaxType, /* UFloatType */ + ObMaxType, /* UDoubleType */ + ObMaxType, /* NumberType */ + ObMaxType, /* UNumberType */ + ObMaxType, /* DateTimeType */ + ObMaxType, /* TimestampType */ + ObMaxType, /* DateType */ + ObMaxType, /* TimeType */ + ObMaxType, /* YearType */ + ObMaxType, /* VarcharType */ + ObMaxType, /* CharType */ + ObMaxType, /* HexStringType */ + ObMaxType, /* ExtendType */ + ObMaxType, /* UnknownType */ + ObMaxType, /* ObTinyTextType */ + ObMaxType, /* ObTextType */ + ObMaxType, /* ObMediumTextType */ + ObMaxType, /* ObLongTextType */ + ObMaxType, /* ObBitType */ + ObMaxType, /* ObEnumType */ + ObMaxType, /* ObSetType */ + ObMaxType, /* ObEnumInnerType */ + ObMaxType, /* ObSetInnerType */ + ObMaxType, /* ObTimestampTZType */ + ObMaxType, /* ObTimestampLTZType */ + ObMaxType, /* ObTimestampNanoType */ + ObMaxType, /* ObRawType */ + ObMaxType, /* ObIntervalYMType */ + ObMaxType, /* ObIntervalDSType */ + ObMaxType, /* ObNumberFloatType */ + ObMaxType, /* ObNVarchar2Type */ + ObMaxType, /* ObNCharType */ + ObMaxType, /* ObURowIDType */ + ObMaxType, /* ObLobType */ + ObMaxType, /* ObJsonType */ + ObMaxType, /* ObGeometryType */ + ObMaxType, /* ObUserDefinedSQLType*/ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, }; diff --git a/src/sql/engine/expr/ob_expr_eval_functions.cpp b/src/sql/engine/expr/ob_expr_eval_functions.cpp index 90eb1c1364..b7d134cb35 100644 --- a/src/sql/engine/expr/ob_expr_eval_functions.cpp +++ b/src/sql/engine/expr/ob_expr_eval_functions.cpp @@ -340,6 +340,28 @@ #include "ob_expr_extract_cert_expired_time.h" #include "ob_expr_transaction_id.h" #include "ob_expr_inner_row_cmp_val.h" +#include "ob_expr_sql_udt_construct.h" +#include "ob_expr_priv_attribute_access.h" +#include "ob_expr_temp_table_ssid.h" +#include "ob_expr_priv_st_numinteriorrings.h" +#include "ob_expr_priv_st_iscollection.h" +#include "ob_expr_priv_st_equals.h" +#include "ob_expr_priv_st_touches.h" +#include "ob_expr_align_date4cmp.h" +#include "ob_expr_priv_st_makeenvelope.h" +#include "ob_expr_priv_st_clipbybox2d.h" +#include "ob_expr_priv_st_pointonsurface.h" +#include "ob_expr_priv_st_geometrytype.h" +#include "ob_expr_st_crosses.h" +#include "ob_expr_st_overlaps.h" +#include "ob_expr_st_union.h" +#include "ob_expr_st_length.h" +#include "ob_expr_st_difference.h" +#include "ob_expr_st_asgeojson.h" +#include "ob_expr_st_centroid.h" +#include "ob_expr_st_symdifference.h" +#include "ob_expr_priv_st_asmvtgeom.h" +#include "ob_expr_priv_st_makevalid.h" namespace oceanbase { @@ -1074,26 +1096,26 @@ static ObExpr::EvalFunc g_expr_eval_functions[] = { NULL, //ObExprXmlSequence::eval_xml_sequence /* 630 */ NULL, //ObExprJsonAppend::eval_json_array_append /* 631 */ NULL, //unused /* 632 */ - NULL, //ObExprUdtConstruct::eval_udt_construct, /* 633 */ - NULL, //ObExprUDTAttributeAccess::eval_attr_access, /* 634 */ - NULL, //ObExprPrivSTNumInteriorRings::eval_priv_st_numinteriorrings,/* 635 */ - NULL, //ObExprPrivSTIsCollection::eval_priv_st_iscollection, /* 636 */ - NULL, //ObExprPrivSTEquals::eval_priv_st_equals, /* 637 */ - NULL, //ObExprPrivSTTouches::eval_priv_st_touches, /* 638 */ - NULL, //ObExprPrivSTMakeEnvelope::eval_priv_st_makeenvelope, /* 639 */ - NULL, //ObExprPrivSTClipByBox2D::eval_priv_st_clipbybox2d, /* 640 */ - NULL, //ObExprPrivSTPointOnSurface::eval_priv_st_pointonsurface, /* 641 */ - NULL, //ObExprPrivSTGeometryType::eval_priv_st_geometrytype, /* 642 */ - NULL, //ObExprSTCrosses::eval_st_crosses, /* 643 */ - NULL, //ObExprSTOverlaps::eval_st_overlaps, /* 644 */ - NULL, //ObExprSTUnion::eval_st_union, /* 645 */ - NULL, //ObExprSTLength::eval_st_length, /* 646 */ - NULL, //ObExprSTDifference::eval_st_difference, /* 647 */ - NULL, //ObExprSTAsGeoJson::eval_st_asgeojson, /* 648 */ - NULL, //ObExprSTCentroid::eval_st_centroid, /* 649 */ - NULL, //ObExprSTSymDifference::eval_st_symdifference, /* 650 */ - NULL, //ObExprPrivSTAsMVTGeom::eval_priv_st_asmvtgeom, /* 651 */ - NULL, //ObExprPrivSTMakeValid::eval_priv_st_makevalid, /* 652 */ + ObExprUdtConstruct::eval_udt_construct, /* 633 */ + ObExprUDTAttributeAccess::eval_attr_access, /* 634 */ + ObExprPrivSTNumInteriorRings::eval_priv_st_numinteriorrings, /* 635 */ + ObExprPrivSTIsCollection::eval_priv_st_iscollection, /* 636 */ + ObExprPrivSTEquals::eval_priv_st_equals, /* 637 */ + ObExprPrivSTTouches::eval_priv_st_touches, /* 638 */ + ObExprPrivSTMakeEnvelope::eval_priv_st_makeenvelope, /* 639 */ + ObExprPrivSTClipByBox2D::eval_priv_st_clipbybox2d, /* 640 */ + ObExprPrivSTPointOnSurface::eval_priv_st_pointonsurface, /* 641 */ + ObExprPrivSTGeometryType::eval_priv_st_geometrytype, /* 642 */ + ObExprSTCrosses::eval_st_crosses, /* 643 */ + ObExprSTOverlaps::eval_st_overlaps, /* 644 */ + ObExprSTUnion::eval_st_union, /* 645 */ + ObExprSTLength::eval_st_length, /* 646 */ + ObExprSTDifference::eval_st_difference, /* 647 */ + ObExprSTAsGeoJson::eval_st_asgeojson, /* 648 */ + ObExprSTCentroid::eval_st_centroid, /* 649 */ + ObExprSTSymDifference::eval_st_symdifference, /* 650 */ + ObExprPrivSTAsMVTGeom::eval_priv_st_asmvtgeom, /* 651 */ + ObExprPrivSTMakeValid::eval_priv_st_makevalid, /* 652 */ NULL, //ObExprAuditLogSetFilter::eval_set_filter, /* 653 */ NULL, //ObExprAuditLogRemoveFilter::eval_remove_filter, /* 654 */ NULL, //ObExprAuditLogSetUser::eval_set_user, /* 655 */ diff --git a/src/sql/engine/expr/ob_expr_extra_info_factory.cpp b/src/sql/engine/expr/ob_expr_extra_info_factory.cpp index 3955f972df..ef9782e066 100644 --- a/src/sql/engine/expr/ob_expr_extra_info_factory.cpp +++ b/src/sql/engine/expr/ob_expr_extra_info_factory.cpp @@ -30,6 +30,8 @@ #include "sql/engine/expr/ob_expr_plsql_variable.h" #include "sql/engine/expr/ob_pl_expr_subquery.h" #include "sql/engine/expr/ob_expr_cast.h" +#include "sql/engine/expr/ob_expr_sql_udt_construct.h" +#include "sql/engine/expr/ob_expr_priv_attribute_access.h" #include "sql/engine/expr/ob_expr_lrpad.h" namespace oceanbase @@ -99,6 +101,8 @@ void ObExprExtraInfoFactory::register_expr_extra_infos() REG_EXTRA_INFO(T_FUN_SYS_GREATEST, ObExprOperator::DatumCastExtraInfo); REG_EXTRA_INFO(T_FUN_SYS_NULLIF, ObExprOperator::DatumCastExtraInfo); REG_EXTRA_INFO(T_FUN_SYS_CAST, ObExprCast::CastMultisetExtraInfo); + REG_EXTRA_INFO(T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT, ObExprUdtConstructInfo); + REG_EXTRA_INFO(T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS, ObExprUdtAttrAccessInfo); REG_EXTRA_INFO(T_FUN_SYS_LPAD, ObExprOracleLRpadInfo); REG_EXTRA_INFO(T_FUN_SYS_RPAD, ObExprOracleLRpadInfo); } diff --git a/src/sql/engine/expr/ob_expr_int_div_result_type.map b/src/sql/engine/expr/ob_expr_int_div_result_type.map index 37c81dc811..16c233e62f 100644 --- a/src/sql/engine/expr/ob_expr_int_div_result_type.map +++ b/src/sql/engine/expr/ob_expr_int_div_result_type.map @@ -53,6 +53,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TinyIntType*/ @@ -108,6 +109,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*SmallIntType*/ @@ -163,6 +165,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*MediumIntType*/ @@ -218,6 +221,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*Int32Type*/ @@ -273,6 +277,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*IntType*/ @@ -328,6 +333,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UTinyIntType*/ @@ -383,6 +389,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*USmallIntType*/ @@ -438,6 +445,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UMediumIntType*/ @@ -493,6 +501,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UInt32Type*/ @@ -548,6 +557,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UInt64Type*/ @@ -603,6 +613,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*FloatType*/ @@ -658,6 +669,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DoubleType*/ @@ -713,6 +725,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UFloatType*/ @@ -768,6 +781,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UDoubleType*/ @@ -823,6 +837,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*NumberType*/ @@ -878,6 +893,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UNumberType*/ @@ -933,6 +949,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DateTimeType*/ @@ -988,6 +1005,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TimestampType*/ @@ -1043,6 +1061,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DateType*/ @@ -1098,6 +1117,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TimeType*/ @@ -1153,6 +1173,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*YearType*/ @@ -1208,6 +1229,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*VarcharType*/ @@ -1263,6 +1285,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*CharType*/ @@ -1318,6 +1341,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*HexStringType*/ @@ -1373,6 +1397,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ExtendType*/ @@ -1428,6 +1453,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UnknownType*/ @@ -1483,6 +1509,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObTinyTextType*/ { @@ -1537,6 +1564,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObTextType*/ { @@ -1591,6 +1619,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObMediumTextType*/ { @@ -1645,6 +1674,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObLongTextType*/ { @@ -1699,6 +1729,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*BitType*/ { @@ -1753,6 +1784,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObEnumType*/ { @@ -1807,6 +1839,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObSetType*/ { @@ -1861,6 +1894,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObUInt64Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObEnumInnerType*/ { @@ -1915,6 +1949,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObSetInnerType*/ { @@ -1969,6 +2004,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /* ObTimestampTZType*/ { @@ -2023,6 +2059,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /* ObTimestampLTZType*/ { @@ -2077,6 +2114,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /* ObTimestampNanoType*/ { @@ -2131,6 +2169,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /* ObRawType*/ { @@ -2185,6 +2224,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*IntervalYMType*/ { @@ -2239,6 +2279,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*IntervalDSType*/ { @@ -2293,6 +2334,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObNumberFloatType*/ { @@ -2347,6 +2389,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObNVarchar2Type*/ { @@ -2401,6 +2444,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObNCharType*/ { @@ -2455,6 +2499,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObURowIDType*/ { @@ -2509,6 +2554,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObLobType*/ { @@ -2563,6 +2609,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObJsonType*/ { @@ -2618,6 +2665,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObGeometryType*/ { @@ -2672,6 +2720,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObUserDefinedSQLType*/ { @@ -2726,6 +2775,7 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObDecimalIntType*/ { @@ -2780,6 +2830,62 @@ static constexpr ObObjType INT_DIV_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ + }, + /*ObCollectionSQLType*/ + { + ObMaxType, /* NullType */ + ObMaxType, /* TinyIntType */ + ObMaxType, /* SmallIntType */ + ObMaxType, /* MediumIntType */ + ObMaxType, /* Int32Type */ + ObMaxType, /* IntType */ + ObMaxType, /* UTinyIntType */ + ObMaxType, /* USmallIntType */ + ObMaxType, /* UMediumIntType */ + ObMaxType, /* UInt32Type */ + ObMaxType, /* UInt64Type */ + ObMaxType, /* FloatType */ + ObMaxType, /* DoubleType */ + ObMaxType, /* UFloatType */ + ObMaxType, /* UDoubleType */ + ObMaxType, /* NumberType */ + ObMaxType, /* UNumberType */ + ObMaxType, /* DateTimeType */ + ObMaxType, /* TimestampType */ + ObMaxType, /* DateType */ + ObMaxType, /* TimeType */ + ObMaxType, /* YearType */ + ObMaxType, /* VarcharType */ + ObMaxType, /* CharType */ + ObMaxType, /* HexStringType */ + ObMaxType, /* ExtendType */ + ObMaxType, /* UnknownType */ + ObMaxType, /* ObTinyTextType */ + ObMaxType, /* ObTextType */ + ObMaxType, /* ObMediumTextType */ + ObMaxType, /* ObLongTextType */ + ObMaxType, /* ObBitType */ + ObMaxType, /* ObEnumType */ + ObMaxType, /* ObSetType */ + ObMaxType, /* ObEnumInnerType */ + ObMaxType, /* ObSetInnerType */ + ObMaxType, /* ObTimestampTZType */ + ObMaxType, /* ObTimestampLTZType */ + ObMaxType, /* ObTimestampNanoType */ + ObMaxType, /* ObRawType */ + ObMaxType, /* ObIntervalYMType */ + ObMaxType, /* ObIntervalDSType */ + ObMaxType, /* ObNumberFloatType */ + ObMaxType, /* ObNVarchar2Type */ + ObMaxType, /* ObNCharType */ + ObMaxType, /* ObURowIDType */ + ObMaxType, /* ObLobType */ + ObMaxType, /* ObJsonType */ + ObMaxType, /* ObGeometryType */ + ObMaxType, /* ObUserDefinedSQLType*/ + ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ } }; diff --git a/src/sql/engine/expr/ob_expr_json_func_helper.cpp b/src/sql/engine/expr/ob_expr_json_func_helper.cpp index 5491e4d137..b8e8ac7981 100644 --- a/src/sql/engine/expr/ob_expr_json_func_helper.cpp +++ b/src/sql/engine/expr/ob_expr_json_func_helper.cpp @@ -1065,6 +1065,16 @@ int ObJsonExprHelper::transform_scalar_2jsonBase(const T &datum, } break; } + case ObGeometryType: { + ret = OB_ERR_INVALID_JSON_TEXT; + LOG_WARN("Internal JSON error", K(ret), K(type)); + break; + } + case ObUserDefinedSQLType: { + ret = OB_ERR_INVALID_CAST_TO_JSON; + LOG_WARN("UDT transform to json is not supported currently", K(ret), K(type)); + break; + } default: { ret = OB_INVALID_ARGUMENT; diff --git a/src/sql/engine/expr/ob_expr_least.cpp b/src/sql/engine/expr/ob_expr_least.cpp index 0247c63b09..971255a05e 100644 --- a/src/sql/engine/expr/ob_expr_least.cpp +++ b/src/sql/engine/expr/ob_expr_least.cpp @@ -159,7 +159,12 @@ int ObExprLeastGreatest::calc_result_typeN_oracle(ObExprResType &type, item_length = OB_MAX_TIMESTAMP_TZ_LENGTH; break; } - case ObUserDefinedSQLTC: { + case ObUserDefinedSQLTC: + case ObGeometryTC: { + item_length = types[i].get_length(); + break; + } + case ObCollectionSQLTC: { item_length = types[i].get_length(); break; } @@ -194,6 +199,10 @@ int ObExprLeastGreatest::calc_result_typeN_oracle(ObExprResType &type, } } + if (OB_SUCC(ret) && ob_is_geometry(type.get_type())) { + ret = OB_ERR_COMPARE_VARRAY_LOB_ATTR; + LOG_WARN("Incorrect cmp type with geometry arguments", K(ret)); + } //老执行引擎在类型推导时不为参数设置calc_type, 在执行期再对参数进行cast。 //新执行引擎需要在类型推导阶段为参数设置好calc_type, 在执行期不再显式执行cast。 if (OB_SUCC(ret) diff --git a/src/sql/engine/expr/ob_expr_merge_result_type_oracle.map b/src/sql/engine/expr/ob_expr_merge_result_type_oracle.map index 5b4fcc27ee..db47a1cd75 100644 --- a/src/sql/engine/expr/ob_expr_merge_result_type_oracle.map +++ b/src/sql/engine/expr/ob_expr_merge_result_type_oracle.map @@ -52,6 +52,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*NullType=>ObGeometryType*/ ObUserDefinedSQLType,/*NullType=>ObUserDefinedSQLType*/ ObDecimalIntType, /*NullType=>ObDecimalIntType*/ + ObCollectionSQLType, /* NullType=>ObCollectionSQLType*/ }, /*TinyIntType*/ @@ -107,6 +108,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*TinyInt=>ObGeometryType*/ ObMaxType, /*TinyInt=>ObUserDefinedSQLType*/ ObDecimalIntType, /*TinyInt=>ObDecimalIntType*/ + ObMaxType, /* TinyInt=>ObCollectionSQLType*/ }, /*SmallIntType*/ @@ -162,6 +164,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*SmallInt=>ObGeometryType*/ ObMaxType, /*SmallInt=>ObUserDefinedSQLType*/ ObDecimalIntType, + ObMaxType, /*SmallInt=>ObCollectionSQLType*/ }, /*MediumIntType*/ @@ -217,6 +220,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*MediumInt=>ObGeometryType*/ ObMaxType, /*MediumInt=>ObUserDefinedSQLType*/ ObDecimalIntType, + ObMaxType, /*MediumInt=>ObCollectionSQLType*/ }, /*Int32Type*/ @@ -271,7 +275,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*Int32Type=>ObJsonType*/ ObGeometryType, /*Int32Type=>ObGeometryType*/ ObMaxType, /*Int32Type=>ObUserDefinedSQLType*/ - ObDecimalIntType + ObDecimalIntType, + ObMaxType, /*Int32Type=>ObCollectionSQLType*/ }, /*IntType*/ @@ -326,7 +331,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*IntType=>ObJsonType*/ ObGeometryType, /*IntType=>ObGeometryType*/ ObMaxType, /*IntType=>ObUserDefinedSQLType*/ - ObDecimalIntType + ObDecimalIntType, + ObMaxType, /*IntType=>ObCollectionSQLType*/ }, /*UTinyIntType*/ @@ -381,7 +387,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*UTinyIntType=>ObJsonType*/ ObGeometryType, /*UTinyIntType=>ObGeometryType*/ ObMaxType, /*UTinyIntType=>ObUserDefinedSQLType*/ - ObDecimalIntType + ObDecimalIntType, + ObMaxType, /*UTinyIntType=>ObCollectionSQLType*/ }, /*USmallIntType*/ @@ -436,7 +443,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*USmallIntType=>ObJsonType*/ ObGeometryType, /*USmallIntType=>ObGeometryType*/ ObMaxType, /*USmallIntType=>ObUserDefinedSQLType*/ - ObDecimalIntType + ObDecimalIntType, + ObMaxType, /*USmallIntType=>ObCollectionSQLType*/ }, /*UMediumIntType*/ @@ -491,7 +499,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*UMediumIntType=>ObJsonType*/ ObGeometryType, /*UMediumIntType=>ObGeometryType*/ ObMaxType, /*UMediumIntType=>ObUserDefinedSQLType*/ - ObDecimalIntType + ObDecimalIntType, + ObMaxType, /*UMediumIntType=>ObCollectionSQLType*/ }, /*UInt32Type*/ @@ -547,6 +556,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*UInt32Type=>ObGeometryType*/ ObMaxType, /*UInt32Type=>ObUserDefinedSQLType*/ ObDecimalIntType, + ObMaxType, /*UInt32Type=>ObCollectionSQLType*/ }, /*UIntType*/ @@ -601,7 +611,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*UIntType=>ObJsonType*/ ObGeometryType, /*UIntType=>ObGeometryType*/ ObMaxType, /*UIntType=>ObUserDefinedSQLType*/ - ObDecimalIntType + ObDecimalIntType, + ObMaxType, /*UIntType=>ObCollectionSQLType*/ }, /*FloatType*/ @@ -656,7 +667,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*FloatType=>ObJsonType*/ ObGeometryType, /*FloatType=>ObGeometryType*/ ObMaxType, /*FloatType=>ObUserDefinedSQLType*/ - ObDoubleType + ObDoubleType, + ObMaxType, /*FloatType=>ObCollectionSQLType*/ }, /*DoubleType*/ @@ -711,7 +723,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*DoubleTYpe=>ObJsonType*/ ObGeometryType, /*DoubleTYpe=>ObGeometryType*/ ObMaxType, /*DoubleTYpe=>ObUserDefinedSQLType*/ - ObDoubleType + ObDoubleType, + ObMaxType, /*DoubleTYpe=>ObCollectionSQLType*/ }, /*UFloatType*/ @@ -766,7 +779,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*UFloatType=>ObJsonType*/ ObGeometryType, /*UFloatTYpe=>ObGeometryType*/ ObMaxType, /*UFloatTYpe=>ObUserDefinedSQLType*/ - ObDoubleType + ObDoubleType, + ObMaxType, /*UFloatTYpe=>ObCollectionSQLType*/ }, /*UDoubleType*/ @@ -821,7 +835,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*UDoubleType=>ObJsonType*/ ObGeometryType, /*UDoubleTYpe=>ObGeometryType*/ ObMaxType, /*UDoubleTYpe=>ObUserDefinedSQLType*/ - ObDoubleType + ObDoubleType, + ObMaxType, /*UDoubleTYpe=>ObCollectionSQLType*/ }, /*NumberType*/ @@ -876,7 +891,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*NumberType=>ObJsonType*/ ObGeometryType, /*NumberTYpe=>ObGeometryType*/ ObMaxType, /*NumberTYpe=>ObUserDefinedSQLType*/ - ObNumberType + ObNumberType, + ObMaxType, /*NumberTYpe=>ObCollectionSQLType*/ }, /*UNumberType*/ @@ -931,7 +947,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*UNumberType=>ObJsonType*/ ObGeometryType, /*UNumberTYpe=>ObGeometryType*/ ObMaxType, /*UNumberTYpe=>ObUserDefinedSQLType*/ - ObNumberType + ObNumberType, + ObMaxType, /*UNumberTYpe=>ObCollectionSQLType*/ }, /*DateTimeType*/ @@ -986,7 +1003,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*DateTimeType=>ObJsonType*/ ObGeometryType, /*DateTimeTYpe=>ObGeometryType*/ ObMaxType, /*DateTimeTYpe=>ObUserDefinedSQLType*/ - ObVarcharType + ObVarcharType, + ObMaxType, /*DateTimeTYpe=>ObCollectionSQLType*/ }, /*TimestampType*/ @@ -1041,7 +1059,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*TimestampType=>ObJsonType*/ ObGeometryType, /*TimestampTYpe=>ObGeometryType*/ ObMaxType, /*TimestampTYpe=>ObUserDefinedSQLType*/ - ObVarcharType + ObVarcharType, + ObMaxType, /*TimestampTYpe=>ObCollectionSQLType*/ }, /*DateType*/ @@ -1096,7 +1115,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*DateType=>ObJsonType*/ ObGeometryType, /*DateTYpe=>ObGeometryType*/ ObMaxType, /*DateTYpe=>ObUserDefinedSQLType*/ - ObVarcharType + ObVarcharType, + ObMaxType, /*DateTYpe=>ObCollectionSQLType*/ }, /*TimeType*/ @@ -1151,7 +1171,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*TimeType=>ObJsonType*/ ObGeometryType, /*TimeTYpe=>ObGeometryType*/ ObMaxType, /*TimeTYpe=>ObUserDefinedSQLType*/ - ObVarcharType + ObVarcharType, + ObMaxType, /*TimeTYpe=>ObCollectionSQLType*/ }, /*YearType*/ @@ -1206,7 +1227,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*YearType=>ObJsonType*/ ObGeometryType, /*YearTYpe=>ObGeometryType*/ ObMaxType, /*YearTYpe=>ObUserDefinedSQLType*/ - ObDecimalIntType + ObDecimalIntType, + ObMaxType, /*YearTYpe=>ObCollectionSQLType*/ }, /*VarcharType*/ @@ -1261,7 +1283,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*VarcharType=>ObJsonType*/ ObGeometryType, /*VarcharTYpe=>ObGeometryType*/ ObMaxType, /*VarcharTYpe=>ObUserDefinedSQLType*/ - ObVarcharType + ObVarcharType, + ObMaxType, /*VarcharTYpe=>ObCollectionSQLType*/ }, /*CharType*/ @@ -1316,7 +1339,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*CharType=>ObJsonType*/ ObGeometryType, /*CharType=>ObGeometryType*/ ObMaxType, /*CharType=>ObUserDefinedSQLType*/ - ObCharType + ObCharType, + ObMaxType, /*CharType=>ObCollectionSQLType*/ }, /*HexStringType*/ @@ -1371,7 +1395,8 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObJsonType, /*HexStringType=>ObJsonType*/ ObGeometryType, /*HexStringType=>ObGeometryType*/ ObMaxType, /*HexStringType=>ObUserDefinedSQLType*/ - ObVarcharType + ObVarcharType, + ObMaxType, /*HexStringType=>ObCollectionSQLType*/ }, /*ExtendType*/ @@ -1427,6 +1452,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*ExtendType=>ObGeometryType*/ ObUserDefinedSQLType, /*ExtendType=>ObUserDefinedSQLType*/ ObMaxType, + ObCollectionSQLType, /*ExtendType=>ObCollectionSQLType*/ }, /*UnknownType*/ @@ -1482,6 +1508,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*UnknownType=>ObGeometryType*/ ObMaxType, /*UnknownType=>ObUserDefinedSQLType*/ ObVarcharType, + ObMaxType, /*UnknownType=>ObCollectionSQLType*/ }, /*ObTinyTextType*/ { @@ -1536,6 +1563,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObTinyTextType=>ObGeometryType*/ ObMaxType, /*ObTinyTextType=>ObUserDefinedSQLType*/ ObTinyTextType, + ObMaxType, /*ObTinyTextType=>ObCollectionSQLType*/ }, /*ObTextType*/ { @@ -1590,6 +1618,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObTextType=>ObGeometryType*/ ObMaxType, /*ObTextType=>ObUserDefinedSQLType*/ ObTextType, + ObMaxType, /*ObTextType=>ObCollectionSQLType*/ }, /*ObMediumTextType*/ @@ -1645,6 +1674,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObMediumTextType=>ObGeometryType*/ ObMaxType, /*ObMediumTextType=>ObUserDefinedSQLType*/ ObMediumTextType, + ObMaxType, /*ObMediumTextType=>ObCollectionSQLType*/ }, /*ObLongTextType*/ @@ -1700,6 +1730,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObLongTextType=>ObGeometryType*/ ObMaxType, /*ObLongTextType=>ObUserDefinedSQLType*/ ObLongTextType, + ObMaxType, /*ObLongTextType=>ObCollectionSQLType*/ }, /*ObBitType*/ { @@ -1754,6 +1785,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObBitType=>ObGeometryType*/ ObMaxType, /*ObBitType=>ObUserDefinedSQLType*/ ObDecimalIntType, + ObMaxType, /*ObBitType=>ObCollectionSQLType*/ }, /*ObEnumType*/ { @@ -1808,6 +1840,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObEnumType=>ObGeometryType*/ ObMaxType, /*ObEnumType=>ObUserDefinedSQLType*/ ObVarcharType, + ObMaxType, /*ObEnumType=>ObCollectionSQLType*/ }, /*ObSetType*/ { @@ -1862,6 +1895,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObSetType=>ObGeometryType*/ ObMaxType, /*ObSetType=>ObUserDefinedSQLType*/ ObVarcharType, + ObMaxType, /*ObSetType=>ObCollectionSQLType*/ }, /*ObEnumInnerType*/ { @@ -1916,6 +1950,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObEnumInnerType=>ObGeometryType*/ ObMaxType, /*ObEnumInnerType=>ObUserDefinedSQLType*/ ObVarcharType, + ObMaxType, /*ObEnumInnerType=>ObCollectionSQLType*/ }, /*ObSetInnerType*/ { @@ -1970,6 +2005,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObSetInnerType=>ObGeometryType*/ ObMaxType, /*ObSetInnerType=>ObUserDefinedSQLType*/ ObVarcharType, + ObMaxType, /*ObSetInnerType=>ObCollectionSQLType*/ }, /*ObTimestampTZType*/ { @@ -2024,6 +2060,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObTimestampTZType=>ObGeometryType*/ ObMaxType, /*ObTimestampTZType=>ObUserDefinedSQLType*/ ObVarcharType, + ObMaxType, /*ObTimestampTZType=>ObCollectionSQLType*/ }, /*ObTimestampLTZType*/ { @@ -2078,6 +2115,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObTimestampLTZType=>ObGeometryType*/ ObMaxType, /*ObTimestampLTZType=>ObUserDefinedSQLType*/ ObVarcharType, + ObMaxType, /*ObTimestampLTZType=>ObCollectionSQLType*/ }, /*ObTimestampNanoType*/ { @@ -2132,6 +2170,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObTimestampNanoType=>ObGeometryType*/ ObMaxType, /*ObTimestampNanoType=>ObUserDefinedSQLType*/ ObVarcharType, + ObMaxType, /*ObTimestampNanoType=>ObCollectionSQLType*/ }, /*ObRawType*/ { @@ -2186,6 +2225,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObRawType=>ObGeometryType*/ ObMaxType, /*ObRawType=>ObUserDefinedSQLType*/ ObRawType, + ObMaxType, /*ObRawType=>ObCollectionSQLType*/ }, /*ObIntervalYMType*/ { @@ -2240,6 +2280,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObIntervalYMType=>ObGeometryType*/ ObMaxType, /*ObIntervalYMType=>ObUserDefinedSQLType*/ ObIntervalYMType, + ObMaxType, /*ObIntervalYMType=>ObCollectionSQLType*/ }, /*ObIntervalDSType*/ { @@ -2294,6 +2335,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObIntervalDSType=>ObGeometryType*/ ObMaxType, /*ObIntervalDSType=>ObUserDefinedSQLType*/ ObIntervalDSType, + ObMaxType, /*ObIntervalDSType=>ObCollectionSQLType*/ }, /*ObNumberFloatType*/ @@ -2349,6 +2391,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*NumberFloatType=>ObGeometryType*/ ObMaxType, /*NumberFloatType=>ObUserDefinedSQLType*/ ObNumberType, + ObMaxType, /*NumberFloatType=>ObCollectionSQLType*/ }, /*ObNVarchar2Type*/ { @@ -2403,6 +2446,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObNVarchar2Type=>ObGeometryType*/ ObMaxType, /*ObNVarchar2Type=>ObUserDefinedSQLType*/ ObNVarchar2Type, + ObMaxType, /*ObNVarchar2Type=>ObCollectionSQLType*/ }, /*ObNCharType*/ { @@ -2457,6 +2501,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObNCharType=>ObGeometryType*/ ObMaxType, /*ObNCharType=>ObUserDefinedSQLType*/ ObNCharType, + ObMaxType, /*ObNCharType=>ObCollectionSQLType*/ }, /*ObURowIDType*/ { @@ -2511,6 +2556,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObURowIDType=>ObGeometryType*/ ObMaxType, /*ObURowIDType=>ObUserDefinedSQLType*/ ObMaxType, + ObMaxType, /*ObURowIDType=>ObCollectionSQLType*/ }, /*ObLobType*/ { @@ -2565,6 +2611,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /* ObLobType=>ObGeometryType*/ ObMaxType, /* ObLobType=>ObUserDefinedSQLType*/ ObMaxType, + ObMaxType, /* ObLobType=>ObCollectionSQLType*/ }, /*ObJsonType*/ { @@ -2619,6 +2666,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /*ObJsonType=>ObGeometryType*/ ObMaxType, /*ObJsonType=>ObUserDefinedSQLType*/ ObJsonType, + ObMaxType, /*ObJsonType=>ObCollectionSQLType*/ }, /*ObGeometryType*/ { @@ -2673,6 +2721,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /* ObGeometryType=>ObGeometryType*/ ObMaxType, /* ObGeometryType=>ObUserDefinedSQLType*/ ObGeometryType, + ObMaxType, /* ObGeometryType=>ObCollectionSQLType*/ }, /*ObUserDefinedSQLType*/ { @@ -2727,6 +2776,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObMaxType, /* ObUserDefinedSQLType=>ObGeometryType*/ ObUserDefinedSQLType, /*ObUserDefinedSQLType*/ ObMaxType, + ObMaxType, /* ObUserDefinedSQLType=>ObCollectionSQLType*/ }, /*ObDecimalIntType*/ { @@ -2781,7 +2831,63 @@ static constexpr ObObjType MERGE_RESULT_TYPE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObDecimalIntType=>ObGeometryType*/ ObMaxType, /* ObDecimalIntType=>ObUserDefinedSqlType */ ObDecimalIntType, /*ObDecimalIntType=>ObDecimalIntType */ - } + ObMaxType, /* ObDecimalIntType=>ObCollectionSQLType */ + }, + /*ObCollectionSQLType*/ + { + ObCollectionSQLType, /* ObCollectionSQLType=>NullType */ + ObMaxType, /* ObCollectionSQLType=>TinyIntType */ + ObMaxType, /* ObCollectionSQLType=>SmallIntType */ + ObMaxType, /* ObCollectionSQLType=>MediumIntType */ + ObMaxType, /* ObCollectionSQLType=>Int32Type */ + ObMaxType, /* ObCollectionSQLType=>IntType */ + ObMaxType, /* ObCollectionSQLType=>UTinyIntType */ + ObMaxType, /* ObCollectionSQLType=>USmallIntType */ + ObMaxType, /* ObCollectionSQLType=>UMediumIntType */ + ObMaxType, /* ObCollectionSQLType=>UInt32Type */ + ObMaxType, /* ObCollectionSQLType=>UIntType */ + ObMaxType, /* ObCollectionSQLType=>FloatType */ + ObMaxType, /* ObCollectionSQLType=>DoubleType */ + ObMaxType, /* ObCollectionSQLType=>UFloatType */ + ObMaxType, /* ObCollectionSQLType=>UDoubleType */ + ObMaxType, /* ObCollectionSQLType=>NumberType */ + ObMaxType, /* ObCollectionSQLType=>UNumberType */ + ObMaxType, /* ObCollectionSQLType=>DateTimeType */ + ObMaxType, /* ObCollectionSQLType=>TimestampType */ + ObMaxType, /* ObCollectionSQLType=>DateType */ + ObMaxType, /* ObCollectionSQLType=>TimeType */ + ObMaxType, /* ObCollectionSQLType=>YearType */ + ObMaxType, /* ObCollectionSQLType=>VarcharType */ + ObMaxType, /* ObCollectionSQLType=>CharType */ + ObMaxType, /* ObCollectionSQLType=>HexStringType */ + ObCollectionSQLType, /* ObCollectionSQLType=>ExtendType */ + ObMaxType, /* ObCollectionSQLType=>UnknownType */ + ObMaxType, /* ObCollectionSQLType=>ObTinyTextType */ + ObMaxType, /* ObCollectionSQLType=>ObTextType */ + ObMaxType, /* ObCollectionSQLType=>ObMediumTextType */ + ObMaxType, /* ObCollectionSQLType=>ObLongTextType */ + ObMaxType, /* ObCollectionSQLType=>ObBitType */ + ObMaxType, /* ObCollectionSQLType=>ObEnumType */ + ObMaxType, /* ObCollectionSQLType=>ObSetType */ + ObMaxType, /* ObCollectionSQLType=>ObEnumInnerType */ + ObMaxType, /* ObCollectionSQLType=>ObSetInnerType */ + ObMaxType, /* ObCollectionSQLType=>ObTimestampTZType */ + ObMaxType, /* ObCollectionSQLType=>ObTimestampLTZType */ + ObMaxType, /* ObCollectionSQLType=>ObTimestampNanoType */ + ObMaxType, /* ObCollectionSQLType=>ObRawType */ + ObMaxType, /* ObCollectionSQLType=>ObIntervalYMType */ + ObMaxType, /* ObCollectionSQLType=>ObIntervalDSType */ + ObMaxType, /* ObCollectionSQLType=>ObNumberFloatType */ + ObMaxType, /* ObCollectionSQLType=>ObNVarchar2Type */ + ObMaxType, /* ObCollectionSQLType=>ObNCharType */ + ObMaxType, /* ObCollectionSQLType=>ObURowIDType*/ + ObLobType, /* ObCollectionSQLType=>ObLobType*/ + ObMaxType, /* ObCollectionSQLType=>ObJsonType*/ + ObMaxType, /* ObCollectionSQLType=>ObGeometryType*/ + ObMaxType, /* ObCollectionSQLType=>ObUserDefinedSQLType*/ + ObMaxType, /* ObCollectionSQLType=>ObDecimalIntType */ + ObCollectionSQLType, /* ObCollectionSQLType */ + }, }; static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { @@ -2838,6 +2944,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*NullType=>ObGeometryType*/ ObUserDefinedSQLType,/*NullType=>ObUserDefinedSQLType*/ ObNumberType, /*NullType=>ObDecimalIntType */ + ObCollectionSQLType, /* NullType=>ObCollectionSQLType*/ }, /*TinyIntType*/ @@ -2893,6 +3000,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*TinyInt=>ObGeometryType*/ ObMaxType, /*TinyInt=>ObUserDefinedSQLType*/ ObNumberType, /*TinyInt=>ObDecimalIntType */ + ObMaxType, /* TinyInt=>ObCollectionSQLType*/ }, /*SmallIntType*/ @@ -2948,6 +3056,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*SmallInt=>ObGeometryType*/ ObMaxType, /*SmallInt=>ObUserDefinedSQLType*/ ObNumberType, /*SmallIntType=>ObDecimalIntType */ + ObMaxType, /*SmallInt=>ObCollectionSQLType*/ }, /*MediumIntType*/ @@ -3003,6 +3112,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*MediumInt=>ObGeometryType*/ ObMaxType, /*MediumInt=>ObUserDefinedSQLType*/ ObNumberType, /*MediumIntType=>ObDecimalIntType */ + ObMaxType, /*MediumInt=>ObCollectionSQLType*/ }, /*Int32Type*/ @@ -3058,6 +3168,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*Int32Type=>ObGeometryType*/ ObMaxType, /*Int32Type=>ObUserDefinedSQLType*/ ObNumberType, /*Int32Type=>ObDecimalIntType */ + ObMaxType, }, /*IntType*/ @@ -3113,6 +3224,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*IntType=>ObGeometryType*/ ObMaxType, /*IntType=>ObUserDefinedSQLType*/ ObNumberType, /*IntType=>ObDecimalIntType */ + ObMaxType, /*IntType=>ObCollectionSQLType*/ }, /*UTinyIntType*/ @@ -3168,6 +3280,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*UTinyIntType=>ObGeometryType*/ ObMaxType, /*UTinyIntType=>ObUserDefinedSQLType*/ ObNumberType, /*IntType=>ObDecimalIntType */ + ObMaxType, }, /*USmallIntType*/ @@ -3223,6 +3336,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*USmallIntType=>ObGeometryType*/ ObMaxType, /*USmallIntType=>ObUserDefinedSQLType*/ ObNumberType, /*IntType=>ObDecimalIntType */ + ObMaxType, }, /*UMediumIntType*/ @@ -3278,6 +3392,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*UMediumIntType=>ObGeometryType*/ ObMaxType, /*UMediumIntType=>ObUserDefinedSQLType*/ ObNumberType, /*IntType=>ObDecimalIntType */ + ObMaxType, }, /*UInt32Type*/ @@ -3333,6 +3448,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*UInt32Type=>ObGeometryType*/ ObMaxType, /*UInt32Type=>ObUserDefinedSQLType*/ ObNumberType, /*IntType=>ObDecimalIntType */ + ObMaxType, }, /*UIntType*/ @@ -3388,6 +3504,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*UIntType=>ObGeometryType*/ ObMaxType, /*UIntType=>ObUserDefinedSQLType*/ ObNumberType, /*IntType=>ObDecimalIntType */ + ObMaxType, }, /*FloatType*/ @@ -3443,6 +3560,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*FloatType=>ObGeometryType*/ ObMaxType, /*FloatType=>ObUserDefinedSQLType*/ ObFloatType, /*FloatType=>ObDecimalIntType */ + ObMaxType, }, /*DoubleType*/ @@ -3498,6 +3616,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*DoubleTYpe=>ObGeometryType*/ ObMaxType, /*DoubleTYpe=>ObUserDefinedSQLType*/ ObDoubleType, /*DoubleType=>ObDecimalIntType */ + ObMaxType, }, /*UFloatType*/ @@ -3553,6 +3672,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*UFloatTYpe=>ObGeometryType*/ ObMaxType, /*UFloatTYpe=>ObUserDefinedSQLType*/ ObFloatType, /*FloatType=>ObDecimalIntType */ + ObMaxType, }, /*UDoubleType*/ @@ -3608,6 +3728,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*UDoubleTYpe=>ObGeometryType*/ ObMaxType, /*UDoubleTYpe=>ObUserDefinedSQLType*/ ObDoubleType, /*UDoubleType=>ObDecimalIntType */ + ObMaxType, }, /*NumberType*/ @@ -3663,6 +3784,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*NumberTYpe=>ObGeometryType*/ ObMaxType, /*NumberTYpe=>ObUserDefinedSQLType*/ ObNumberType, /*NumberType=>ObDecimalIntType */ + ObMaxType, }, /*UNumberType*/ @@ -3718,6 +3840,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*UNumberTYpe=>ObGeometryType*/ ObMaxType, /*UNumberTYpe=>ObUserDefinedSQLType*/ ObNumberType, /*NumberType=>ObDecimalIntType */ + ObMaxType, }, /*DateTimeType*/ @@ -3773,6 +3896,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*DateTimeTYpe=>ObGeometryType*/ ObMaxType, /*DateTimeTYpe=>ObUserDefinedSQLType*/ ObVarcharType, /*DateTimeType=>ObDecimalIntType */ + ObMaxType, }, /*TimestampType*/ @@ -3828,6 +3952,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*TimestampTYpe=>ObGeometryType*/ ObMaxType, /*TimestampTYpe=>ObUserDefinedSQLType*/ ObVarcharType, /*TimestampType=>ObDecimalIntType */ + ObMaxType, }, /*DateType*/ @@ -3883,6 +4008,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*DateTYpe=>ObGeometryType*/ ObMaxType, /*DateTYpe=>ObUserDefinedSQLType*/ ObVarcharType, /*TimestampType=>ObDecimalIntType */ + ObMaxType, }, /*TimeType*/ @@ -3938,6 +4064,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*TimeTYpe=>ObGeometryType*/ ObMaxType, /*TimeTYpe=>ObUserDefinedSQLType*/ ObVarcharType, /*TimestampType=>ObDecimalIntType */ + ObMaxType, }, /*YearType*/ @@ -3993,6 +4120,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*YearTYpe=>ObGeometryType*/ ObMaxType, /*YearTYpe=>ObUserDefinedSQLType*/ ObDecimalIntType, /*YearType=>ObDecimalIntType */ + ObMaxType, }, /*VarcharType*/ @@ -4048,6 +4176,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*VarcharTYpe=>ObGeometryType*/ ObMaxType, /*VarcharTYpe=>ObUserDefinedSQLType*/ ObVarcharType, /*VarcharType=>ObDecimalIntType */ + ObMaxType, }, /*CharType*/ @@ -4103,6 +4232,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*CharType=>ObGeometryType*/ ObMaxType, /*CharType=>ObUserDefinedSQLType*/ ObCharType, /*CharType=>ObDecimalIntType */ + ObMaxType, }, /*HexStringType*/ @@ -4158,6 +4288,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*HexStringType=>ObGeometryType*/ ObMaxType, /*HexStringType=>ObUserDefinedSQLType*/ ObVarcharType, /*HexStringType=>ObDecimalIntType */ + ObMaxType, }, /*ExtendType*/ @@ -4213,6 +4344,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*ExtendType=>ObGeometryType*/ ObUserDefinedSQLType, /*ExtendType=>ObUserDefinedSQLType*/ ObMaxType, /*ExtendType=>ObDecimalIntType */ + ObCollectionSQLType, /*ExtendType=>ObCollectionSQLType*/ }, /*UnknownType*/ @@ -4268,6 +4400,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*UnknownType=>ObGeometryType*/ ObMaxType, /*UnknownType=>ObUserDefinedSQLType*/ ObVarcharType, /*UnknownType=>ObDecimalIntType */ + ObMaxType, }, /*ObTinyTextType*/ { @@ -4322,6 +4455,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObTinyTextType=>ObGeometryType*/ ObMaxType, /*ObTinyTextType=>ObUserDefinedSQLType*/ ObTinyTextType, /*ObTinyTextType=>ObDecimalIntType */ + ObMaxType, }, /*ObTextType*/ { @@ -4376,6 +4510,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObTextType=>ObGeometryType*/ ObMaxType, /*ObTextType=>ObUserDefinedSQLType*/ ObTextType, /*ObTextType=>ObDecimalIntType */ + ObMaxType, }, /*ObMediumTextType*/ @@ -4431,6 +4566,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObMediumTextType=>ObGeometryType*/ ObMaxType, /*ObMediumTextType=>ObUserDefinedSQLType*/ ObMediumTextType, /*ObMediumTextType=>ObDecimalIntType */ + ObMaxType, }, /*ObLongTextType*/ @@ -4486,6 +4622,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObLongTextType=>ObGeometryType*/ ObMaxType, /*ObLongTextType=>ObUserDefinedSQLType*/ ObLongTextType, /*ObLongTextType=>ObDecimalIntType */ + ObMaxType, }, /*ObBitType*/ { @@ -4540,6 +4677,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObBitType=>ObGeometryType*/ ObMaxType, /*ObBitType=>ObUserDefinedSQLType*/ ObNumberType, /*ObBitType=>ObDecimalIntType */ + ObMaxType, }, /*ObEnumType*/ { @@ -4594,6 +4732,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObEnumType=>ObGeometryType*/ ObMaxType, /*ObEnumType=>ObUserDefinedSQLType*/ ObVarcharType, /*ObEnumType=>ObDecimalIntType */ + ObMaxType, }, /*ObSetType*/ { @@ -4648,6 +4787,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObSetType=>ObGeometryType*/ ObMaxType, /*ObSetType=>ObUserDefinedSQLType*/ ObVarcharType, /*ObSetType=>ObDecimalIntType */ + ObMaxType, }, /*ObEnumInnerType*/ { @@ -4702,6 +4842,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObEnumInnerType=>ObGeometryType*/ ObMaxType, /*ObEnumInnerType=>ObUserDefinedSQLType*/ ObVarcharType, /*ObEnumInnerType=>ObDecimalIntType */ + ObMaxType, }, /*ObSetInnerType*/ { @@ -4756,6 +4897,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObSetInnerType=>ObGeometryType*/ ObMaxType, /*ObSetInnerType=>ObUserDefinedSQLType*/ ObVarcharType, /*ObSetInnerType=>ObDecimalIntType */ + ObMaxType, }, /*ObTimestampTZType*/ { @@ -4810,6 +4952,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObTimestampTZType=>ObGeometryType*/ ObMaxType, /*ObTimestampTZType=>ObUserDefinedSQLType*/ ObVarcharType, /*ObTimestampTZType=>ObDecimalIntType */ + ObMaxType, }, /*ObTimestampLTZType*/ { @@ -4864,6 +5007,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObTimestampLTZType=>ObGeometryType*/ ObMaxType, /*ObTimestampLTZType=>ObUserDefinedSQLType*/ ObVarcharType, /*ObTimestampLTZType=>ObDecimalIntType */ + ObMaxType, }, /*ObTimestampNanoType*/ { @@ -4918,6 +5062,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObTimestampNanoType=>ObGeometryType*/ ObMaxType, /*ObTimestampNanoType=>ObUserDefinedSQLType*/ ObVarcharType, /*ObTimestampNanoType=>ObDecimalIntType */ + ObMaxType, }, /*ObRawType*/ { @@ -4972,6 +5117,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObRawType=>ObGeometryType*/ ObMaxType, /*ObRawType=>ObUserDefinedSQLType*/ ObRawType, /* ObRawType=>ObDecimalIntType */ + ObMaxType, }, /*ObIntervalYMType*/ { @@ -5026,6 +5172,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObIntervalYMType=>ObGeometryType*/ ObMaxType, /*ObIntervalYMType=>ObUserDefinedSQLType*/ ObIntervalYMType, /* ObIntervalYMType=>ObDecimalIntType */ + ObMaxType, }, /*ObIntervalDSType*/ { @@ -5080,6 +5227,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObIntervalDSType=>ObGeometryType*/ ObMaxType, /*ObIntervalDSType=>ObUserDefinedSQLType*/ ObIntervalDSType, /* ObIntervalDSType=>ObDecimalIntType */ + ObMaxType, }, /*ObNumberFloatType*/ @@ -5135,6 +5283,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*NumberFloatType=>ObGeometryType*/ ObMaxType, /*NumberFloatType=>ObUserDefinedSQLType*/ ObNumberType, /*NumberFloatType=>ObDecimalIntType */ + ObMaxType, }, /*ObNVarchar2Type*/ { @@ -5189,6 +5338,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObNVarchar2Type=>ObGeometryType*/ ObMaxType, /*ObNVarchar2Type=>ObUserDefinedSQLType*/ ObNVarchar2Type, /* ObNVarchar2Type=>ObDecimalIntType */ + ObMaxType, }, /*ObNCharType*/ { @@ -5243,6 +5393,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObNCharType=>ObGeometryType*/ ObMaxType, /*ObNCharType=>ObUserDefinedSQLType*/ ObNCharType, /* ObNCharType=>ObDecimalIntType */ + ObMaxType, }, /*ObURowIDType*/ { @@ -5297,6 +5448,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObURowIDType=>ObGeometryType*/ ObMaxType, /*ObURowIDType=>ObUserDefinedSQLType*/ ObMaxType, /* ObURowIDType=>ObDecimalIntType */ + ObMaxType, }, /*ObLobType*/ { @@ -5351,6 +5503,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /* ObLobType=>ObGeometryType*/ ObMaxType, /* ObLobType=>ObUserDefinedSQLType*/ ObMaxType, /* ObLobType=>ObDecimalIntType */ + ObMaxType, }, /*ObJsonType*/ { @@ -5405,6 +5558,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /*ObJsonType=>ObGeometryType*/ ObMaxType, /*ObJsonType=>ObUserDefinedSQLType*/ ObJsonType, /* ObJsonType=>ObDecimalIntType */ + ObMaxType, }, /*ObGeometryType*/ { @@ -5459,6 +5613,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /* ObGeometryType=>ObGeometryType*/ ObMaxType, /* ObGeometryType=>ObUserDefinedSQLType*/ ObGeometryType, /* ObGeometryType=>ObDecimalIntType */ + ObMaxType, }, /*ObUserDefinedSQLType*/ { @@ -5513,6 +5668,7 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObMaxType, /* ObUserDefinedSQLType=>ObGeometryType*/ ObUserDefinedSQLType, /*ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, }, /*ObDecimalIntType*/ { @@ -5567,6 +5723,62 @@ static constexpr ObObjType MERGE_RESULT_TYPE_ORACLE[ObMaxType][ObMaxType] = { ObGeometryType, /*ObDecimalIntType=>ObGeometryType*/ ObMaxType, /* ObDecimalIntType=>ObUserDefinedSqlType */ ObNumberType, /*ObDecimalIntType=>ObDecimalIntType */ + ObMaxType, /* ObDecimalIntType=>ObCollectionSQLType */ + }, + /*ObCollectionSQLType*/ + { + ObCollectionSQLType, /* ObCollectionSQLType=>NullType */ + ObMaxType, /* ObCollectionSQLType=>TinyIntType */ + ObMaxType, /* ObCollectionSQLType=>SmallIntType */ + ObMaxType, /* ObCollectionSQLType=>MediumIntType */ + ObMaxType, /* ObCollectionSQLType=>Int32Type */ + ObMaxType, /* ObCollectionSQLType=>IntType */ + ObMaxType, /* ObCollectionSQLType=>UTinyIntType */ + ObMaxType, /* ObCollectionSQLType=>USmallIntType */ + ObMaxType, /* ObCollectionSQLType=>UMediumIntType */ + ObMaxType, /* ObCollectionSQLType=>UInt32Type */ + ObMaxType, /* ObCollectionSQLType=>UIntType */ + ObMaxType, /* ObCollectionSQLType=>FloatType */ + ObMaxType, /* ObCollectionSQLType=>DoubleType */ + ObMaxType, /* ObCollectionSQLType=>UFloatType */ + ObMaxType, /* ObCollectionSQLType=>UDoubleType */ + ObMaxType, /* ObCollectionSQLType=>NumberType */ + ObMaxType, /* ObCollectionSQLType=>UNumberType */ + ObMaxType, /* ObCollectionSQLType=>DateTimeType */ + ObMaxType, /* ObCollectionSQLType=>TimestampType */ + ObMaxType, /* ObCollectionSQLType=>DateType */ + ObMaxType, /* ObCollectionSQLType=>TimeType */ + ObMaxType, /* ObCollectionSQLType=>YearType */ + ObMaxType, /* ObCollectionSQLType=>VarcharType */ + ObMaxType, /* ObCollectionSQLType=>CharType */ + ObMaxType, /* ObCollectionSQLType=>HexStringType */ + ObCollectionSQLType, /* ObCollectionSQLType=>ExtendType */ + ObMaxType, /* ObCollectionSQLType=>UnknownType */ + ObMaxType, /* ObCollectionSQLType=>ObTinyTextType */ + ObMaxType, /* ObCollectionSQLType=>ObTextType */ + ObMaxType, /* ObCollectionSQLType=>ObMediumTextType */ + ObMaxType, /* ObCollectionSQLType=>ObLongTextType */ + ObMaxType, /* ObCollectionSQLType=>ObBitType */ + ObMaxType, /* ObCollectionSQLType=>ObEnumType */ + ObMaxType, /* ObCollectionSQLType=>ObSetType */ + ObMaxType, /* ObCollectionSQLType=>ObEnumInnerType */ + ObMaxType, /* ObCollectionSQLType=>ObSetInnerType */ + ObMaxType, /* ObCollectionSQLType=>ObTimestampTZType */ + ObMaxType, /* ObCollectionSQLType=>ObTimestampLTZType */ + ObMaxType, /* ObCollectionSQLType=>ObTimestampNanoType */ + ObMaxType, /* ObCollectionSQLType=>ObRawType */ + ObMaxType, /* ObCollectionSQLType=>ObIntervalYMType */ + ObMaxType, /* ObCollectionSQLType=>ObIntervalDSType */ + ObMaxType, /* ObCollectionSQLType=>ObNumberFloatType */ + ObMaxType, /* ObCollectionSQLType=>ObNVarchar2Type */ + ObMaxType, /* ObCollectionSQLType=>ObNCharType */ + ObMaxType, /* ObCollectionSQLType=>ObURowIDType*/ + ObLobType, /* ObCollectionSQLType=>ObLobType*/ + ObMaxType, /* ObCollectionSQLType=>ObJsonType*/ + ObMaxType, /* ObCollectionSQLType=>ObGeometryType*/ + ObMaxType, /* ObCollectionSQLType=>ObUserDefinedSQLType*/ + ObMaxType, /* ObCollectionSQLType=>ObDecimalIntType */ + ObCollectionSQLType, /* ObCollectionSQLType */ }, }; diff --git a/src/sql/engine/expr/ob_expr_mod_result_type.map b/src/sql/engine/expr/ob_expr_mod_result_type.map index 48f2effd82..949830b738 100644 --- a/src/sql/engine/expr/ob_expr_mod_result_type.map +++ b/src/sql/engine/expr/ob_expr_mod_result_type.map @@ -53,6 +53,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TinyIntType*/ @@ -108,6 +109,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*SmallIntType*/ @@ -163,6 +165,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*MediumIntType*/ @@ -218,6 +221,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*Int32Type*/ @@ -273,6 +277,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*IntType*/ @@ -328,6 +333,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UTinyIntType*/ @@ -383,6 +389,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*USmallIntType*/ @@ -438,6 +445,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UMediumIntType*/ @@ -493,6 +501,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UInt32Type*/ @@ -548,6 +557,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UIntType*/ @@ -603,6 +613,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*FloatType*/ @@ -658,6 +669,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DoubleType*/ @@ -713,6 +725,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UFloatType*/ @@ -768,6 +781,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObUDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UDoubleType*/ @@ -823,6 +837,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObUDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*NumberType*/ @@ -878,6 +893,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UNumberType*/ @@ -933,6 +949,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObUNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DateTimeType*/ @@ -988,6 +1005,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TimestampType*/ @@ -1043,6 +1061,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DateType*/ @@ -1098,6 +1117,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TimeType*/ @@ -1153,6 +1173,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*YearType*/ @@ -1208,6 +1229,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObUNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*VarcharType*/ @@ -1263,6 +1285,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*CharType*/ @@ -1318,6 +1341,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*HexStringType*/ @@ -1372,7 +1396,8 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObUDoubleType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ - ObUDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ExtendType*/ @@ -1428,6 +1453,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /*ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UnknownType*/ @@ -1483,6 +1509,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TinyTextType*/ { @@ -1537,6 +1564,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TextType*/ { @@ -1591,6 +1619,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*MediumTextType*/ { @@ -1645,6 +1674,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*LongTextType*/ { @@ -1699,6 +1729,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*BitType*/ { @@ -1753,6 +1784,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObUNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObEnumType*/ { @@ -1807,6 +1839,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObSetType*/ { @@ -1861,6 +1894,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObEnumInnerType*/ { @@ -1915,6 +1949,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObSetInnerType*/ { @@ -1969,6 +2004,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObTimestampTZType*/ @@ -2024,6 +2060,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObTimestampLTZType*/ { @@ -2078,6 +2115,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObTimestampNanoType*/ { @@ -2132,6 +2170,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObRawType*/ { @@ -2186,6 +2225,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObIntervalYMType*/ { @@ -2240,6 +2280,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObIntervalDSType*/ { @@ -2294,6 +2335,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObNumberFloatType*/ { @@ -2348,6 +2390,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObNVarchar2Type*/ { @@ -2402,6 +2445,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObNCharType*/ { @@ -2456,6 +2500,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObURowIDType*/ { @@ -2510,6 +2555,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObLobType*/ { @@ -2564,6 +2610,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObJsonType*/ { @@ -2618,6 +2665,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObGeometryType*/ { @@ -2672,6 +2720,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /*ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /*ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObUserDefinedSQLType*/ { @@ -2726,6 +2775,7 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /*ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /*ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObDecimalIntType*/ @@ -2781,6 +2831,62 @@ static constexpr ObObjType MOD_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /*ObGeometryType */ ObMaxType, /*ObUserDefinedSQLType*/ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /*ObCollectionSQLType*/ + }, + /*ObCollectionSQLType*/ + { + ObMaxType, /* NullType */ + ObMaxType, /* TinyIntType */ + ObMaxType, /* SmallIntType */ + ObMaxType, /* MediumIntType */ + ObMaxType, /* Int32Type */ + ObMaxType, /* IntType */ + ObMaxType, /* UTinyIntType */ + ObMaxType, /* USmallIntType */ + ObMaxType, /* UMediumIntType */ + ObMaxType, /* UInt32Type */ + ObMaxType, /* UInt64Type */ + ObMaxType, /* FloatType */ + ObMaxType, /* DoubleType */ + ObMaxType, /* UFloatType */ + ObMaxType, /* UDoubleType */ + ObMaxType, /* NumberType */ + ObMaxType, /* UNumberType */ + ObMaxType, /* DateTimeType */ + ObMaxType, /* TimestampType */ + ObMaxType, /* DateType */ + ObMaxType, /* TimeType */ + ObMaxType, /* YearType */ + ObMaxType, /* VarcharType */ + ObMaxType, /* CharType */ + ObMaxType, /* HexStringType */ + ObMaxType, /* ExtendType */ + ObMaxType, /* UnknownType */ + ObMaxType, /* ObTinyTextType */ + ObMaxType, /* ObTextType */ + ObMaxType, /* ObMediumTextType */ + ObMaxType, /* ObLongTextType */ + ObMaxType, /* ObBitType */ + ObMaxType, /* ObEnumType */ + ObMaxType, /* ObSetType */ + ObMaxType, /* ObEnumInnerType */ + ObMaxType, /* ObSetInnerType */ + ObMaxType, /* ObTimestampTZType */ + ObMaxType, /* ObTimestampLTZType */ + ObMaxType, /* ObTimestampNanoType */ + ObMaxType, /* ObRawType */ + ObMaxType, /* ObIntervalYMType */ + ObMaxType, /* ObIntervalDSType */ + ObMaxType, /* ObNumberFloatType */ + ObMaxType, /* ObNVarchar2Type */ + ObMaxType, /* ObNCharType */ + ObMaxType, /* ObURowIDType */ + ObMaxType, /* ObLobType */ + ObMaxType, /* ObJsonType */ + ObMaxType, /* ObGeometryType */ + ObMaxType, /* ObUserDefinedSQLType */ + ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, }; diff --git a/src/sql/engine/expr/ob_expr_neg_result_type.map b/src/sql/engine/expr/ob_expr_neg_result_type.map index cc3228cbe7..b45b6d4106 100644 --- a/src/sql/engine/expr/ob_expr_neg_result_type.map +++ b/src/sql/engine/expr/ob_expr_neg_result_type.map @@ -51,6 +51,7 @@ static constexpr ObObjType NEG_RESULT_TYPE[ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }; static constexpr ObObjType NEG_RESULT_TYPE_ORACLE[ObMaxType] = @@ -106,6 +107,7 @@ static constexpr ObObjType NEG_RESULT_TYPE_ORACLE[ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }; static_assert(is_array_fully_initialized(NEG_RESULT_TYPE_ORACLE), "NEG_RESULT_TYPE_ORACLE is partially initlized"); diff --git a/src/sql/engine/expr/ob_expr_nvl.cpp b/src/sql/engine/expr/ob_expr_nvl.cpp index 8b765106eb..19e34258fc 100644 --- a/src/sql/engine/expr/ob_expr_nvl.cpp +++ b/src/sql/engine/expr/ob_expr_nvl.cpp @@ -64,6 +64,8 @@ int ObExprNvlUtil::calc_result_type(ObExprResType &type, type.set_collation_type(CS_TYPE_BINARY); } else if (ob_is_json(type.get_type())) { type.set_collation_level(CS_LEVEL_IMPLICIT); + } else if (ob_is_geometry(type.get_type())) { + type.set_geometry(); } if (OB_SUCC(ret)) { type.set_length(MAX(type1.get_length(), type2.get_length())); @@ -74,11 +76,17 @@ int ObExprNvlUtil::calc_result_type(ObExprResType &type, } if (OB_SUCC(ret) && ob_is_user_defined_sql_type(type.get_type())) { + bool is_one_type_null = ob_is_null(type1.get_type()) || ob_is_null(type2.get_type()); + ObExprResType &udt_type = !type1.is_null() ? type1 : type2; if (type1.is_xml_sql_type() || type2.is_xml_sql_type()) { type.set_subschema_id(ObXMLSqlType); + } else if ((is_one_type_null || type1.get_udt_id() == type2.get_udt_id()) + && udt_type.get_udt_id() != OB_INVALID_ID) { + type.set_subschema_id(udt_type.get_subschema_id()); + type.set_udt_id(udt_type.get_udt_id()); } else { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unsupported udt failed", K(ret), K(type1), K(type2)); + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("unsupported udt for nvl", K(ret), K(type1), K(type2)); } } return ret; @@ -294,6 +302,14 @@ int ObExprOracleNvl::calc_nvl_oralce_result_type(ObExprResType &type, OX (type.set_udt_id(type1.get_udt_id())); } else if (type.is_temporal_type()) { type.set_scale(0); + } else if (type.is_user_defined_sql_type()) { + // only two situations: + // 1. both type1 and type2 are UDT, and have same udt_id + // 2. one of type1 and type2 is null, need to set accuracy for udt_id_ + ObExprResType &null_type = type1.is_null() ? type1 : type2; + if (null_type.is_null()) { + null_type.set_calc_accuracy(type.get_accuracy()); + } } /* * diff --git a/src/sql/engine/expr/ob_expr_nvl_promotion.map b/src/sql/engine/expr/ob_expr_nvl_promotion.map index 41d29c9750..028326ea58 100644 --- a/src/sql/engine/expr/ob_expr_nvl_promotion.map +++ b/src/sql/engine/expr/ob_expr_nvl_promotion.map @@ -28,6 +28,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDecimalIntType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*int -> XXX*/ @@ -57,6 +58,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDecimalIntType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*uint -> XXX*/ @@ -86,6 +88,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDecimalIntType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*float -> XXX*/ @@ -115,6 +118,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDoubleType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*double -> XXX*/ @@ -144,6 +148,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDoubleType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*number -> XXX*/ @@ -173,6 +178,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDecimalIntType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*datetime -> XXX*/ @@ -202,6 +208,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObVarcharType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*date -> XXX*/ @@ -231,6 +238,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObVarcharType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*time -> XXX*/ @@ -260,6 +268,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObVarcharType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*year -> XXX*/ @@ -289,6 +298,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDecimalIntType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*string -> XXX*/ @@ -318,6 +328,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObVarcharType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*extend -> XXX*/ @@ -347,6 +358,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*unknown -> XXX*/ @@ -376,6 +388,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDecimalIntType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*text -> XXX*/ @@ -405,6 +418,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObLongTextType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*bit -> XXX*/ @@ -434,6 +448,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDecimalIntType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*EnumSet -> XXX*/ @@ -463,6 +478,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObVarcharType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*EnumSetInner -> XXX*/ @@ -492,6 +508,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*OTimestamp -> XXX*/ @@ -521,6 +538,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObVarcharType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*Raw -> XXX*/ @@ -550,6 +568,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*Interval -> XXX*/ @@ -579,6 +598,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*RowID -> XXX*/ @@ -608,6 +628,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*Lob -> XXX*/ @@ -637,6 +658,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*Json -> XXX*/ @@ -667,7 +689,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*UDT*/ ObJsonType, /*DecimalInt*/ }, -{ + { /*Geometry -> XXX*/ ObMaxType, /*null*/ ObMaxType, /*int*/ @@ -695,6 +717,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*UDT*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*UDT -> XXX*/ @@ -724,6 +747,7 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*UDT*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*DecimalInt -> XXX*/ @@ -753,6 +777,37 @@ static const ObObjType NVL_TYPE_PROMOTION[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*UDT*/ ObDecimalIntType,/*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ + }, + { + /*Collection Sql Type -> XXX*/ + ObMaxType, /*null*/ + ObMaxType, /*int*/ + ObMaxType, /*uint*/ + ObMaxType, /*float*/ + ObMaxType, /*double*/ + ObMaxType, /*number*/ + ObMaxType, /*datetime*/ + ObMaxType, /*date*/ + ObMaxType, /*time*/ + ObMaxType, /*year*/ + ObMaxType, /*string*/ + ObMaxType, /*extend*/ + ObMaxType, /*unknown*/ + ObMaxType, /*text*/ + ObMaxType, /*bit*/ + ObMaxType, /*EnumSet*/ + ObMaxType, /*EnumSetInner*/ + ObMaxType, /*OTimestamp*/ + ObMaxType, /*Raw*/ + ObMaxType, /*Interval*/ + ObMaxType, /*RowID*/ + ObMaxType, /*Lob*/ + ObMaxType, /*Json*/ + ObMaxType, /*Geometry*/ + ObMaxType, /*UDT*/ + ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, }; @@ -784,9 +839,10 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObURowIDType, /*Rowid*/ ObMaxType, /*Lob*/ ObMaxType, /*Json*/ - ObMaxType, /*Geometry*/ + ObGeometryType, /*Geometry*/ ObUserDefinedSQLType, /*User Defined Type*/ ObNumberType, /*DecimalInt*/ + ObCollectionSQLType, /*Collection Sql Type*/ }, { // treat int as number, because const 1 will be parsed to bigint 1, not number 1 now. @@ -817,6 +873,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObNumberType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*uint -> XXX*/ @@ -846,6 +903,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*float -> XXX*/ @@ -875,6 +933,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObFloatType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*double -> XXX*/ @@ -904,6 +963,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObDoubleType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*number -> XXX*/ @@ -933,6 +993,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObNumberType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*datetime -> XXX*/ @@ -962,6 +1023,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*date -> XXX*/ @@ -991,6 +1053,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*time -> XXX*/ @@ -1020,6 +1083,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*year -> XXX*/ @@ -1049,6 +1113,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*string -> XXX*/ @@ -1078,6 +1143,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObVarcharType, /*User Defined Type*/ ObVarcharType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*extend -> XXX*/ @@ -1107,6 +1173,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObUserDefinedSQLType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*unknown -> XXX*/ @@ -1136,6 +1203,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*text -> XXX*/ @@ -1165,6 +1233,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObLongTextType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*bit -> XXX*/ @@ -1194,6 +1263,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*EnumSet -> XXX*/ @@ -1223,6 +1293,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*EnumSetInner -> XXX*/ @@ -1252,6 +1323,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*otimestamp-> XXX*/ @@ -1281,6 +1353,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*Raw-> XXX*/ @@ -1310,6 +1383,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*Interval-> XXX*/ @@ -1339,6 +1413,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*RowID-> XXX*/ @@ -1368,6 +1443,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*Lob -> XXX*/ @@ -1397,6 +1473,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*Json -> XXX*/ @@ -1426,10 +1503,11 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*Geometry -> XXX*/ - ObMaxType, /*null*/ + ObGeometryType, /*null*/ ObMaxType, /*int*/ ObMaxType, /*uint*/ ObMaxType, /*float*/ @@ -1452,9 +1530,10 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*RowID*/ ObMaxType, /*Lob*/ ObMaxType, /*Json*/ - ObMaxType, /*Geometry*/ + ObGeometryType, /*Geometry*/ ObMaxType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*User Defined Type -> XXX*/ @@ -1484,6 +1563,7 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObUserDefinedSQLType, /*User Defined Type*/ ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, { /*DecimalInt -> XXX*/ @@ -1513,5 +1593,36 @@ static const ObObjType NVL_TYPE_PROMOTION_ORACLE[ObMaxTC][ObMaxTC] = ObMaxType, /*Geometry*/ ObMaxType, /*UDT*/ ObNumberType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ + }, + { + /*User Defined Type -> XXX*/ + ObUserDefinedSQLType, /*null*/ + ObMaxType, /*int*/ + ObMaxType, /*uint*/ + ObMaxType, /*float*/ + ObMaxType, /*double*/ + ObMaxType, /*number*/ + ObMaxType, /*datetime*/ + ObMaxType, /*date*/ + ObMaxType, /*time*/ + ObMaxType, /*year*/ + ObUserDefinedSQLType, /*string*/ + ObUserDefinedSQLType, /*extend*/ + ObMaxType, /*unknown*/ + ObMaxType, /*text*/ + ObMaxType, /*bit*/ + ObMaxType, /*EnumSet*/ + ObMaxType, /*EnumSetInner*/ + ObMaxType, /*OTimestamp*/ + ObMaxType, /*Raw*/ + ObMaxType, /*Interval*/ + ObMaxType, /*RowID*/ + ObMaxType, /*Lob*/ + ObMaxType, /*Json*/ + ObMaxType, /*Geometry*/ + ObMaxType, /*User Defined Type*/ + ObMaxType, /*DecimalInt*/ + ObMaxType, /*Collection Sql Type*/ }, }; diff --git a/src/sql/engine/expr/ob_expr_object_construct.cpp b/src/sql/engine/expr/ob_expr_object_construct.cpp index f6fc20f316..2aedf40024 100644 --- a/src/sql/engine/expr/ob_expr_object_construct.cpp +++ b/src/sql/engine/expr/ob_expr_object_construct.cpp @@ -62,6 +62,7 @@ int ObExprObjectConstruct::calc_result_typeN(ObExprResType &type, } } OX (type.set_type(ObExtendType)); + OX (type.set_extend_type(pl::PL_RECORD_TYPE)); OX (type.set_udt_id(udt_id_)); return ret; } @@ -121,9 +122,16 @@ int ObExprObjectConstruct::newx(ObEvalCtx &ctx, ObObj &result, uint64_t udt_id) ObExecContext &exec_ctx = ctx.exec_ctx_; ObIAllocator &alloc = ctx.exec_ctx_.get_allocator(); pl::ObPLPackageGuard package_guard(session->get_effective_tenant_id()); + ObSchemaGetterGuard *schema_guard = NULL; + // if called by check_default_value in ddl resolver, no sql ctx, get guard from session cache + if (OB_ISNULL(exec_ctx.get_sql_ctx()) || OB_ISNULL(exec_ctx.get_sql_ctx()->schema_guard_)) { + schema_guard = &session->get_cached_schema_guard_info().get_schema_guard(); + } else { + schema_guard = exec_ctx.get_sql_ctx()->schema_guard_; + } pl::ObPLResolveCtx resolve_ctx(alloc, *session, - *(exec_ctx.get_sql_ctx()->schema_guard_), + *(schema_guard), package_guard, *(exec_ctx.get_sql_proxy()), false); @@ -188,6 +196,14 @@ int ObExprObjectConstruct::eval_object_construct(const ObExpr &expr, ObEvalCtx & for (int64_t i = 0; OB_SUCC(ret) && i < expr.arg_cnt_; ++i) { if (objs[i].is_null() && info->elem_types_.at(i).is_ext()) { OZ (newx(ctx, record->get_element()[i], info->elem_types_.at(i).get_udt_id())); + if (OB_SUCC(ret)) { + // use _is_null to distinguish the following two situations: + // SDO_GEOMETRY(2003, 4000, SDO_POINT_TYPE(NULL,NULL,NULL), NULL, NULL) + // SDO_GEOMETRY(2003, 4000, NULL, NULL, NULL) + pl::ObPLRecord *child_null_record = + reinterpret_cast(record->get_element()[i].get_ext()); + child_null_record->set_null(); + } } else { // param ObObj may have different accuracy with the argument, need conversion OZ (ObSPIService::spi_convert(*session, diff --git a/src/sql/engine/expr/ob_expr_operator.cpp b/src/sql/engine/expr/ob_expr_operator.cpp index e6470100d7..6c0e107a29 100644 --- a/src/sql/engine/expr/ob_expr_operator.cpp +++ b/src/sql/engine/expr/ob_expr_operator.cpp @@ -1026,6 +1026,10 @@ int ObExprOperator::is_same_kind_type_for_case(const ObExprResType &type1, const match = ob_is_json(type2.get_type()); } else if (type1.is_xml_sql_type() || (type1.is_ext() && type1.get_udt_id() == T_OBJ_XML)) { match = type2.is_xml_sql_type() || (type2.is_ext() && type2.get_udt_id() == T_OBJ_XML); + } else if (type1.is_geometry()) { + match = type2.is_geometry(); + } else if (type1.is_user_defined_sql_type()) { + match = type2.is_user_defined_sql_type() && type1.get_udt_id() == type2.get_udt_id(); } } return ret; @@ -1510,6 +1514,7 @@ int ObExprOperator::aggregate_user_defined_sql_type( if (ob_is_user_defined_sql_type(types[i].get_type())) { found = true; type.set_subschema_id(types[i].get_subschema_id()); + type.set_udt_id(types[i].get_udt_id()); } } } @@ -1570,9 +1575,10 @@ ObObjType ObExprOperator::enumset_calc_types_[ObMaxTC] = ObVarcharType, /*ObRowIDTC*/ ObMaxType, /*ObLobTC*/ ObVarcharType, /*ObJsonTC*/ - ObMaxType, /*ObGeometryTC*/ + ObVarcharType, /*ObGeometryTC*/ ObNullType, /*UDT*/ ObUInt64Type, /*ObDecimalIntTC*/ + ObNullType, /*COLLECTION*/ }; //////////////////////////////////////////////////////////////// @@ -2060,6 +2066,14 @@ int ObExprOperator::calc_cmp_type2(ObExprResType &type, && type_ != T_OP_IS && type_ != T_OP_IS_NOT) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, ob_obj_type_str(type1.get_type()), ob_obj_type_str(type2.get_type())); + } else if (is_oracle_mode() && (type1.is_geometry() || type2.is_geometry())) { + // oracle error code compability + if (type1.get_type() != type2.get_type()) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + } else { + ret = OB_ERR_COMPARE_VARRAY_LOB_ATTR; + } + LOG_WARN("Incorrect cmp type with geometry arguments", K(type1), K(type2), K(type_), K(ret)); } else if ((type1.is_geometry() || type2.is_geometry()) && !(type_ == T_OP_EQ || type_ == T_OP_NE @@ -2068,7 +2082,9 @@ int ObExprOperator::calc_cmp_type2(ObExprResType &type, || type_ == T_OP_SQ_NE || type_ == T_OP_SQ_NSEQ || type_ == T_OP_IS - || type_ == T_OP_IS_NOT)) { + || type_ == T_OP_IS_NOT + || type_ == T_OP_IN + || type_ == T_OP_NOT_IN)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Incorrect cmp type with geometry arguments", K(type1), K(type2), K(type_), K(ret)); } else if (is_oracle_mode() @@ -2315,11 +2331,13 @@ int ObRelationalExprOperator::calc_result_type2(ObExprResType &type, } if (support && type1.is_ext()) { support = (type1.get_obj_meta().get_extend_type() == pl::PL_NESTED_TABLE_TYPE || - ob_is_xml_pl_type(type1.get_type(), type1.get_udt_id())); + ob_is_xml_pl_type(type1.get_type(), type1.get_udt_id()) || + ObObjUDTUtil::ob_is_supported_sql_udt(type1.get_udt_id())); } if (support && type2.is_ext()) { support = (type2.get_obj_meta().get_extend_type() == pl::PL_NESTED_TABLE_TYPE || - ob_is_xml_pl_type(type2.get_type(), type2.get_udt_id())); + ob_is_xml_pl_type(type2.get_type(), type2.get_udt_id()) || + ObObjUDTUtil::ob_is_supported_sql_udt(type2.get_udt_id())); } if (!support) { ret = OB_ERR_CALL_WRONG_ARG; diff --git a/src/sql/engine/expr/ob_expr_operator_factory.cpp b/src/sql/engine/expr/ob_expr_operator_factory.cpp index 079df2d68c..a7eb87220e 100644 --- a/src/sql/engine/expr/ob_expr_operator_factory.cpp +++ b/src/sql/engine/expr/ob_expr_operator_factory.cpp @@ -401,11 +401,31 @@ #include "sql/engine/expr/ob_expr_xml_serialize.h" #include "sql/engine/expr/ob_expr_xmlcast.h" #include "sql/engine/expr/ob_expr_update_xml.h" +#include "sql/engine/expr/ob_expr_sql_udt_construct.h" +#include "sql/engine/expr/ob_expr_priv_attribute_access.h" #include "sql/engine/expr/ob_expr_temp_table_ssid.h" +#include "sql/engine/expr/ob_expr_priv_st_numinteriorrings.h" +#include "sql/engine/expr/ob_expr_priv_st_iscollection.h" +#include "sql/engine/expr/ob_expr_priv_st_equals.h" +#include "sql/engine/expr/ob_expr_priv_st_touches.h" #include "sql/engine/expr/ob_expr_align_date4cmp.h" #include "sql/engine/expr/ob_expr_extract_cert_expired_time.h" #include "sql/engine/expr/ob_expr_transaction_id.h" #include "sql/engine/expr/ob_expr_inner_row_cmp_val.h" +#include "sql/engine/expr/ob_expr_priv_st_makeenvelope.h" +#include "sql/engine/expr/ob_expr_priv_st_clipbybox2d.h" +#include "sql/engine/expr/ob_expr_priv_st_pointonsurface.h" +#include "sql/engine/expr/ob_expr_priv_st_geometrytype.h" +#include "sql/engine/expr/ob_expr_st_crosses.h" +#include "sql/engine/expr/ob_expr_st_overlaps.h" +#include "sql/engine/expr/ob_expr_st_union.h" +#include "sql/engine/expr/ob_expr_st_length.h" +#include "sql/engine/expr/ob_expr_st_difference.h" +#include "sql/engine/expr/ob_expr_st_asgeojson.h" +#include "sql/engine/expr/ob_expr_st_centroid.h" +#include "sql/engine/expr/ob_expr_st_symdifference.h" +#include "sql/engine/expr/ob_expr_priv_st_asmvtgeom.h" +#include "sql/engine/expr/ob_expr_priv_st_makevalid.h" using namespace oceanbase::common; namespace oceanbase @@ -1001,11 +1021,29 @@ void ObExprOperatorFactory::register_expr_operators() REG_OP(ObExprRandom); REG_OP(ObExprRandstr); REG_OP(ObExprPrefixPattern); + REG_OP(ObExprPrivSTNumInteriorRings); + REG_OP(ObExprPrivSTIsCollection); + REG_OP(ObExprPrivSTEquals); + REG_OP(ObExprPrivSTTouches); REG_OP(ObExprAlignDate4Cmp); REG_OP(ObExprExtractExpiredTime); REG_OP(ObExprTransactionId); REG_OP(ObExprInnerRowCmpVal); // REG_OP(ObExprTopNFilter); + REG_OP(ObExprPrivSTMakeEnvelope); + REG_OP(ObExprPrivSTClipByBox2D); + REG_OP(ObExprPrivSTPointOnSurface); + REG_OP(ObExprPrivSTGeometryType); + REG_OP(ObExprSTCrosses); + REG_OP(ObExprSTOverlaps); + REG_OP(ObExprSTUnion); + REG_OP(ObExprSTLength); + REG_OP(ObExprSTDifference); + REG_OP(ObExprSTAsGeoJson); + REG_OP(ObExprSTCentroid); + REG_OP(ObExprSTSymDifference); + REG_OP(ObExprPrivSTAsMVTGeom); + REG_OP(ObExprPrivSTMakeValid); }(); // 注册oracle系统函数 REG_OP_ORCL(ObExprSysConnectByPath); @@ -1315,6 +1353,8 @@ void ObExprOperatorFactory::register_expr_operators() REG_OP_ORCL(ObExprXmlSerialize); REG_OP_ORCL(ObExprXmlcast); REG_OP_ORCL(ObExprUpdateXml); + REG_OP_ORCL(ObExprUdtConstruct); + REG_OP_ORCL(ObExprUDTAttributeAccess); REG_OP_ORCL(ObExprTempTableSSID); REG_OP_ORCL(ObExprJsonObjectStar); REG_OP_ORCL(ObExprTransactionId); @@ -1450,6 +1490,9 @@ void ObExprOperatorFactory::get_function_alias_name(const ObString &origin_name, } else if (0 == origin_name.case_compare("area")) { // area is synonym for st_area alias_name = ObString::make_string(N_ST_AREA); + } else if (0 == origin_name.case_compare("centroid")) { + // centroid is synonym for st_centroid + alias_name = ObString::make_string(N_ST_CENTROID); } else { //do nothing } diff --git a/src/sql/engine/expr/ob_expr_oracle_decode.cpp b/src/sql/engine/expr/ob_expr_oracle_decode.cpp index fc4396cfa5..6f67094cab 100644 --- a/src/sql/engine/expr/ob_expr_oracle_decode.cpp +++ b/src/sql/engine/expr/ob_expr_oracle_decode.cpp @@ -65,6 +65,15 @@ int ObExprOracleDecode::calc_result_typeN(ObExprResType &type, } else if (lib::is_oracle_mode() && types_stack[CALC_TYPE_INDEX].get_type() == ObUserDefinedSQLType) { ret = OB_ERR_NO_ORDER_MAP_SQL; LOG_WARN("cannot ORDER objects without MAP or ORDER method", K(ret)); + } else if (lib::is_oracle_mode() + && (types_stack[CALC_TYPE_INDEX].get_type() == ObGeometryType || types_stack[0].get_type() == ObGeometryType)) { + if (types_stack[CALC_TYPE_INDEX].get_type() == types_stack[0].get_type()) { + ret = OB_ERR_COMPARE_VARRAY_LOB_ATTR; + LOG_WARN("Incorrect cmp type with geometry arguments", K(ret)); + } else { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("invalid type of parameter", K(ret), K(types_stack[0]), K(types_stack[1])); + } } for (int64_t i = 1; OB_SUCC(ret) && i < param_num; i += 2) { if (has_default && i == param_num - 1) { diff --git a/src/sql/engine/expr/ob_expr_output_pack.cpp b/src/sql/engine/expr/ob_expr_output_pack.cpp index 4f6eeff2b5..b597b3ba95 100644 --- a/src/sql/engine/expr/ob_expr_output_pack.cpp +++ b/src/sql/engine/expr/ob_expr_output_pack.cpp @@ -17,9 +17,7 @@ #include "io/easy_io.h" #include "lib/oblog/ob_log.h" #include "share/ob_lob_access_utils.h" -#ifdef OB_BUILD_ORACLE_XML #include "sql/engine/expr/ob_expr_xml_func_helper.h" -#endif namespace oceanbase{ using namespace common; @@ -525,7 +523,7 @@ int ObExprOutputPack::process_lob_locator_results(common::ObObj& value, // 3. if client does not support use_lob_locator ,,return full lob data without locator header bool is_use_lob_locator = my_session.is_client_use_lob_locator(); bool is_support_outrow_locator_v2 = my_session.is_client_support_lob_locatorv2(); - if (!(value.is_lob() || value.is_json() || value.is_lob_locator())) { + if (!(value.is_lob() || value.is_json() || value.is_geometry() ||value.is_lob_locator())) { // not lob types, do nothing } else if (is_use_lob_locator && value.is_lob() && lib::is_oracle_mode()) { // if does not have extern header, mock one @@ -589,6 +587,11 @@ int ObExprOutputPack::process_lob_locator_results(common::ObObj& value, LOG_WARN("Lob: init lob str iter failed ", K(value)); } else { ObObjType dst_type = value.is_json() ? ObJsonType : ObLongTextType; + if (value.is_json()) { + dst_type = ObJsonType; + } else if (value.is_geometry()) { + dst_type = ObGeometryType; + } // remove has lob header flag value.set_lob_value(dst_type, data.ptr(), static_cast(data.length())); } @@ -678,13 +681,14 @@ int ObExprOutputPack::try_encode_row(const ObExpr &expr, ObEvalCtx &ctx, LOG_WARN("convert text obj charset failed", K(ret)); } if (OB_FAIL(ret)) { - } else if ((obj.is_lob() || obj.is_lob_locator() || obj.is_json()) + } else if ((obj.is_lob() || obj.is_lob_locator() || obj.is_json() || obj.is_geometry()) && OB_FAIL(process_lob_locator_results(obj, alloc, *session))) { LOG_WARN("convert lob locator to longtext failed", K(ret)); -#ifdef OB_BUILD_ORACLE_XML - } else if (obj.is_user_defined_sql_type() && OB_FAIL(ObXMLExprHelper::process_sql_udt_results(obj, &alloc, session))) { + } else if ((obj.is_user_defined_sql_type() || obj.is_collection_sql_type() || obj.is_geometry()) + && OB_FAIL(ObXMLExprHelper::process_sql_udt_results(obj, &alloc, session, + &ctx.exec_ctx_, + session->is_ps_protocol()))) { LOG_WARN("convert udt to client format failed", K(ret), K(obj.get_udt_subschema_id())); -#endif } } } diff --git a/src/sql/engine/expr/ob_expr_point.cpp b/src/sql/engine/expr/ob_expr_point.cpp index 89eee502ac..e756bc11b8 100644 --- a/src/sql/engine/expr/ob_expr_point.cpp +++ b/src/sql/engine/expr/ob_expr_point.cpp @@ -59,9 +59,8 @@ int ObExprPoint::calc_result_type2(ObExprResType &type, if (!ob_is_double_tc(type_y)) { type2.set_calc_type(ObDoubleType); } - type.set_type(ObGeometryType); - type.set_collation_level(common::CS_LEVEL_COERCIBLE); - type.set_collation_type(CS_TYPE_BINARY); + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); } return ret; diff --git a/src/sql/engine/expr/ob_expr_priv_attribute_access.cpp b/src/sql/engine/expr/ob_expr_priv_attribute_access.cpp new file mode 100644 index 0000000000..e5b0eac4cb --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_attribute_access.cpp @@ -0,0 +1,312 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "ob_expr_priv_attribute_access.h" +#include "sql/session/ob_sql_session_info.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "lib/json_type/ob_json_base.h" +#include "lib/geo/ob_sdo_geo_object.h" +#include "lib/geo/ob_geo_utils.h" + +namespace oceanbase +{ +using namespace common; +namespace sql +{ + +OB_SERIALIZE_MEMBER((ObExprUDTAttributeAccess, ObFuncExprOperator), udt_id_, attr_type_); + +ObExprUDTAttributeAccess::ObExprUDTAttributeAccess(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS, N_PRIV_UDT_ATTR_ACCESS, MORE_THAN_ONE, NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION, + false, INTERNAL_IN_ORACLE_MODE), + udt_id_(OB_INVALID_ID), + attr_type_(OB_INVALID_ID) {} + +ObExprUDTAttributeAccess::~ObExprUDTAttributeAccess() {} + +int ObExprUDTAttributeAccess::calc_result_typeN(ObExprResType &type, + ObExprResType *types, + int64_t param_num, + ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + uint16_t subschema_id; + // need const cast to modify subschema ctx, in physcial plan ctx belong to cur exec_ctx; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + if (param_num != 2) { + ret = OB_ERR_CALL_WRONG_ARG; + LOG_WARN("wrong number or types of arguments in call", K(ret)); + } else if (OB_ISNULL(exec_ctx) && udt_id_ != T_OBJ_XML) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("need context to search subschema mapping", K(ret), K(udt_id_)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_udt_id(udt_id_, subschema_id))) { + LOG_WARN("failed to get sub schema id", K(ret), K(udt_id_)); + } else if (types[0].is_geometry()) { + if (udt_id_ != T_OBJ_SDO_GEOMETRY) { + ret = OB_ERR_CALL_WRONG_ARG; + LOG_WARN("wrong types of arguments in call", K(ret), K(udt_id_), K(types[0])); + } else { + types[1].set_calc_type(ObIntType); + type.set_type(ObNumberType); + const ObAccuracy &acc = + ObAccuracy::DDL_DEFAULT_ACCURACY2[common::ORACLE_MODE][common::ObNumberType]; + type.set_scale(acc.get_scale()); + type.set_precision(acc.get_precision()); + } + } else if (!types[0].is_null() + && !types[0].is_expectd_udt_type(subschema_id) // subschema id of types[0] is already deduced + && types[0].get_udt_id() != udt_id_) { + ret = OB_ERR_CALL_WRONG_ARG; + LOG_WARN("wrong types of arguments in call", K(ret), K(udt_id_), K(types[0]), K(subschema_id)); + } else { + types[1].set_calc_type(ObIntType); + type.set_type(static_cast(attr_type_)); + } + return ret; +} + +int ObExprUDTAttributeAccess::cg_expr(ObExprCGCtx &op_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + ObIAllocator &alloc = *op_cg_ctx.allocator_; + const ObUDTAttributeAccessRawExpr &fun_sys + = static_cast(raw_expr); + ObExprUdtAttrAccessInfo *info + = OB_NEWx(ObExprUdtAttrAccessInfo, (&alloc), alloc, T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS); + if (NULL == info) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret)); + } else { + OZ(info->from_raw_expr(fun_sys)); + rt_expr.extra_info_ = info; + } + rt_expr.eval_func_ = eval_attr_access; + + return ret; +} + +int ObExprUDTAttributeAccess::get_udt_meta_by_udt_id(uint64_t udt_id, ObSqlUDTMeta &udt_meta) +{ + int ret = OB_SUCCESS; + // mock sdo_geometry + udt_meta.attribute_cnt_ = 7; + return ret; +} + +int ObExprUDTAttributeAccess::eval_attr_access(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObDatum *udt_datum = NULL; + ObDatum *attr_datum = NULL; + int32_t attr_idx = 0; + int num_args = expr.arg_cnt_; + if (num_args != 2) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected params number", K(ret), K(num_args)); + } else if (OB_FAIL(expr.args_[0]->eval(ctx, udt_datum))) { + LOG_WARN("failed to eval first argument", K(ret)); + } else if (udt_datum->is_null()) { + res.set_null(); + } else if (OB_FAIL(expr.args_[1]->eval(ctx, attr_datum))) { + LOG_WARN("failed to eval first argument", K(ret)); + } else if (attr_datum->is_null()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid attribute idx", K(ret)); + } else { + attr_idx = attr_datum->get_int(); + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + const ObExprUdtAttrAccessInfo *info + = static_cast(expr.extra_info_); + ObSqlUDT sql_udt; + ObSqlUDTMeta sql_udt_meta; + ObString raw_data = udt_datum->get_string(); + ObString attr_data; + if (OB_ISNULL(info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("extra info is null", K(ret)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(&temp_allocator, ObLongTextType, + CS_TYPE_BINARY, true, + raw_data))) { + LOG_WARN("failed to get udt raw data", K(ret), K(info->udt_id_)); + } else if (expr.args_[0]->datum_meta_.type_ == ObGeometryType) { + if (OB_FAIL(eval_sdo_geom_attr_access(temp_allocator, raw_data, attr_idx, res))) { + LOG_WARN("failed to eval sdo_geometry attribute", K(ret), K(attr_idx)); + } + } else if (OB_FAIL(get_udt_meta_by_udt_id(info->udt_id_, sql_udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(info->udt_id_)); + } else if (FALSE_IT(sql_udt.set_data(raw_data))) { + } else if (FALSE_IT(sql_udt.set_udt_meta(sql_udt_meta))) { + } else if (OB_FAIL(sql_udt.access_attribute(attr_idx, attr_data))) { + LOG_WARN("failed to get udt attribute data", K(ret), K(info->udt_id_), K(attr_idx), K(sql_udt_meta.attribute_cnt_)); + } + if (OB_SUCC(ret) && expr.args_[0]->datum_meta_.type_ != ObGeometryType) { + if (attr_data.empty()) { + res.set_null(); + } else { + char *res_ptr = NULL; + if (OB_ISNULL(res_ptr = expr.get_str_res_mem(ctx, attr_data.length()))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("Failed to allocate memory for lob locator", K(ret), K(attr_data.length())); + } else { + ObString res_str(attr_data.length(), 0, res_ptr); + res_str.write(attr_data.ptr(), attr_data.length()); + if (expr.datum_meta_.type_ == ObNumberType) { + ObObj obj; + obj.set_meta_type(expr.obj_meta_); + int64_t pos = 0; + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj, res_str.ptr(), res_str.length(), pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(res_str)); + } else { + const number::ObNumber val = obj.get_number(); + res.set_number(val); + } + } else { + res.set_string(res_str); + } + } + } + } + } + + return ret; +} + +int ObExprUDTAttributeAccess::eval_sdo_geom_attr_access(ObIAllocator &allocator, const ObString &swkb, const int32_t attr_idx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObSdoGeoObject sdo_geo; + if (OB_FAIL(ObGeoTypeUtil::wkb_to_sdo_geo(swkb, sdo_geo, true))) { + LOG_WARN("fail to wkb_to_sdo_geo", K(ret), K(swkb)); + } else { + switch (static_cast(attr_idx)) { + case ObSdoGeoAttrIdx::ObGtype : { + uint64_t gtype_num; + number::ObNumber gtype; + if (OB_FAIL(ObGeoTypeUtil::get_num_by_gtype(sdo_geo.get_gtype(), gtype_num))) { + LOG_WARN("fail to get_num_by_gtype", K(ret), K(sdo_geo.get_gtype()), K(gtype_num)); + } else if (OB_FAIL(gtype.from(gtype_num, allocator))) { + LOG_WARN("fail to alloc memory for gtype", K(ret), K(gtype_num)); + } else { + res.set_number(gtype); + } + break; + } + case ObSdoGeoAttrIdx::ObSrid : { + number::ObNumber srid; + if (sdo_geo.get_srid() == UINT32_MAX) { + res.set_null(); + } else if (OB_FAIL(srid.from(sdo_geo.get_srid(), allocator))) { + LOG_WARN("fail to alloc memory for gtype", K(ret), K(sdo_geo.get_srid())); + } else { + res.set_number(srid); + } + break; + } + case ObSdoGeoAttrIdx::ObPointX : { + number::ObNumber x_num; + if (sdo_geo.get_point().is_null()) { + res.set_null(); + } else if (OB_FAIL(ObJsonBaseUtil::double_to_number(sdo_geo.get_point().get_x(), allocator, x_num))) { + LOG_WARN("fail to alloc memory for x_num", K(ret), K(sdo_geo.get_point().get_x())); + } else { + res.set_number(x_num); + } + break; + } + case ObSdoGeoAttrIdx::ObPointY : { + number::ObNumber y_num; + if (sdo_geo.get_point().is_null()) { + res.set_null(); + } else if (OB_FAIL(ObJsonBaseUtil::double_to_number(sdo_geo.get_point().get_y(), allocator, y_num))) { + LOG_WARN("fail to alloc memory for y_num", K(ret), K(sdo_geo.get_point().get_y())); + } else { + res.set_number(y_num); + } + break; + } + case ObSdoGeoAttrIdx::ObPointZ : { + number::ObNumber z_num; + if (sdo_geo.get_point().is_null() || !sdo_geo.get_point().has_z()) { + res.set_null(); + } else if (OB_FAIL(ObJsonBaseUtil::double_to_number(sdo_geo.get_point().get_z(), allocator, z_num))) { + LOG_WARN("fail to alloc memory for z_num", K(ret), K(sdo_geo.get_point().get_z())); + } else { + res.set_number(z_num); + } + break; + } + default: + ret = OB_ERR_UNEXPECTED; + } + } + return ret; +} + +OB_DEF_SERIALIZE(ObExprUdtAttrAccessInfo) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_ENCODE, + udt_id_, + attr_type_); + return ret; +} + +OB_DEF_DESERIALIZE(ObExprUdtAttrAccessInfo) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_DECODE, + udt_id_, + attr_type_); + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObExprUdtAttrAccessInfo) +{ + int64_t len = 0; + LST_DO_CODE(OB_UNIS_ADD_LEN, + udt_id_, + attr_type_); + return len; +} + +int ObExprUdtAttrAccessInfo::deep_copy(common::ObIAllocator &allocator, + const ObExprOperatorType type, + ObIExprExtraInfo *&copied_info) const +{ + int ret = common::OB_SUCCESS; + OZ(ObExprExtraInfoFactory::alloc(allocator, type, copied_info)); + ObExprUdtAttrAccessInfo &other = *static_cast(copied_info); + other.udt_id_ = udt_id_; + other.attr_type_ = attr_type_; + return ret; +} + +template +int ObExprUdtAttrAccessInfo::from_raw_expr(RE &raw_expr) +{ + int ret = OB_SUCCESS; + ObUDTAttributeAccessRawExpr &udt_raw_expr + = const_cast + (static_cast(raw_expr)); + udt_id_ = udt_raw_expr.get_udt_id(); + attr_type_ = udt_raw_expr.get_attribute_type(); + return ret; +} + +} /* sql */ +} /* oceanbase */ diff --git a/src/sql/engine/expr/ob_expr_priv_attribute_access.h b/src/sql/engine/expr/ob_expr_priv_attribute_access.h new file mode 100644 index 0000000000..a43c6988f0 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_attribute_access.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_UDT_ATTR_ACCESS_H_ +#define OCEANBASE_SQL_OB_EXPR_UDT_ATTR_ACCESS_H_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "sql/engine/expr/ob_i_expr_extra_info.h" +#include "deps/oblib/src/lib/udt/ob_udt_type.h" + + +namespace oceanbase +{ +namespace sql +{ + +struct ObExprUdtAttrAccessInfo : public ObIExprExtraInfo +{ + OB_UNIS_VERSION(1); +public: + ObExprUdtAttrAccessInfo(common::ObIAllocator &alloc, ObExprOperatorType type) + : ObIExprExtraInfo(alloc, type), + udt_id_(OB_INVALID_ID), attr_type_(OB_INVALID_ID) + { + } + + virtual int deep_copy(common::ObIAllocator &allocator, + const ObExprOperatorType type, + ObIExprExtraInfo *&copied_info) const override; + + template + int from_raw_expr(RE &expr); + + uint64_t udt_id_; + uint64_t attr_type_; // attribute type +}; + +class ObExprUDTAttributeAccess : public ObFuncExprOperator +{ + OB_UNIS_VERSION(1); +public: + explicit ObExprUDTAttributeAccess(common::ObIAllocator &alloc); + virtual ~ObExprUDTAttributeAccess(); + + virtual int calc_result_typeN(ObExprResType &type, + ObExprResType *types_stack, + int64_t param_num, + common::ObExprTypeCtx &type_ctx) const; + + virtual int cg_expr(ObExprCGCtx &op_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; + static int eval_attr_access(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int get_udt_meta_by_udt_id(uint64_t udt_id, ObSqlUDTMeta &udt_meta); + static int eval_sdo_geom_attr_access(ObIAllocator &allocator, const ObString &swkb, const int32_t attr_idx, ObDatum &res); + inline void set_udt_id(uint64_t udt_id) { udt_id_ = udt_id; } + uint64_t get_udt_id() { return udt_id_; } + inline void set_attribute_type(uint64_t attr_type) { attr_type_ = attr_type; } + uint64_t get_attribute_type() { return attr_type_; } + +private: + uint64_t udt_id_; + uint64_t attr_type_; // attribute type + +private: + DISALLOW_COPY_AND_ASSIGN(ObExprUDTAttributeAccess); +}; + +} //sql +} //oceanbase +#endif //OCEANBASE_SQL_OB_EXPR_UDT_ATTR_ACCESS_H_ diff --git a/src/sql/engine/expr/ob_expr_priv_st_asewkb.cpp b/src/sql/engine/expr/ob_expr_priv_st_asewkb.cpp index 970b24710c..85c74ab2f8 100644 --- a/src/sql/engine/expr/ob_expr_priv_st_asewkb.cpp +++ b/src/sql/engine/expr/ob_expr_priv_st_asewkb.cpp @@ -91,14 +91,14 @@ int ObExprStPrivAsEwkb::eval_priv_st_as_ewkb(const ObExpr &expr, LOG_WARN("fail to get real data.", K(ret), K(wkb_str)); } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb_str, srs))) { LOG_WARN("fail to get srs item", K(ret), K(wkb_str)); - } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_wkb(tmp_allocator, wkb_str, srs, geo, true))) { + } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_wkb(tmp_allocator, wkb_str, srs, geo, true, true, true))) { LOG_WARN("fail to create geo by wkb", K(ret), K(wkb_str)); if (ret != OB_ERR_SRS_NOT_FOUND && ret != OB_ERR_INVALID_GEOMETRY_TYPE) { ret = OB_ERR_GIS_INVALID_DATA; LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_ASEWKB); } } else if (OB_NOT_NULL(srs)) { - is_geog = srs->is_geographical_srs(); + is_geog = srs->is_geographical_srs(); } if (OB_SUCC(ret)) { @@ -123,15 +123,18 @@ int ObExprStPrivAsEwkb::eval_priv_st_as_ewkb(const ObExpr &expr, int64_t pos = WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE; int64_t data_offset = WKB_OFFSET + WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE; int64_t remove_len = WKB_VERSION_SIZE; + uint32_t geo_type = static_cast(header.type_); + bool is_3d_geo = ObGeoTypeUtil::is_3d_geo_type(geo->type()); + //transform to EWKB format + geo_type = is_3d_geo ? ((geo_type - ObGeoTypeUtil::WKB_3D_TYPE_OFFSET) | ObGeoTypeUtil::EWKB_Z_FLAG) : geo_type; if (0 != header.srid_) { ObGeoWkbByteOrderUtil::write(res_wkb.ptr() + WKB_GEO_BO_SIZE, - static_cast(header.type_) | ObGeoTypeUtil::EWKB_SRID_FLAG, header.bo_); // 2. write [type] + geo_type | ObGeoTypeUtil::EWKB_SRID_FLAG, header.bo_); // 2. write [type] ObGeoWkbByteOrderUtil::write(res_wkb.ptr() + WKB_GEO_BO_SIZE + WKB_GEO_TYPE_SIZE, header.srid_, header.bo_); // write [srid] pos += WKB_GEO_SRID_SIZE; } else { // 当srid为0时,ewkb中不输出srid字段 - ObGeoWkbByteOrderUtil::write(res_wkb.ptr() + WKB_GEO_BO_SIZE, - static_cast(header.type_), header.bo_); // 2. write [type] + ObGeoWkbByteOrderUtil::write(res_wkb.ptr() + WKB_GEO_BO_SIZE, geo_type, header.bo_); // 2. write [type] remove_len += WKB_GEO_SRID_SIZE; } MEMMOVE(res_wkb.ptr() + pos, res_wkb.ptr() + data_offset, res_wkb.length() - data_offset);// write [data] diff --git a/src/sql/engine/expr/ob_expr_priv_st_asmvtgeom.cpp b/src/sql/engine/expr/ob_expr_priv_st_asmvtgeom.cpp new file mode 100644 index 0000000000..351961e7d9 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_asmvtgeom.cpp @@ -0,0 +1,538 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_asmvtgeom. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_priv_st_asmvtgeom.h" +#include "sql/session/ob_sql_session_info.h" +#include "observer/omt/ob_tenant_srs.h" +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_utils.h" +#include "share/object/ob_obj_cast_util.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "lib/geo/ob_geo_func_utils.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +ObExprPrivSTAsMVTGeom::ObExprPrivSTAsMVTGeom(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_ASMVTGEOM, N_PRIV_ST_ASMVTGEOM, MORE_THAN_ONE, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprPrivSTAsMVTGeom::~ObExprPrivSTAsMVTGeom() +{} + +int ObExprPrivSTAsMVTGeom::calc_result_typeN(ObExprResType &type, ObExprResType *types_stack, + int64_t param_num, ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObObjType obj_type1 = types_stack[0].get_type(); // geometry + ObObjType obj_type2 = types_stack[1].get_type(); // geometry + if (ObHexStringType != obj_type1 && !ob_is_geometry(obj_type1) && !ob_is_null(obj_type1)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_ASMVTGEOM); + LOG_WARN("invalid type", K(ret), K(obj_type1)); + } else if (ObHexStringType != obj_type1 && !ob_is_geometry(obj_type2)) { + if (ob_is_null(obj_type2)) { + ret = OB_ERR_NULL_INPUT; + LOG_WARN("_ST_AsMVTGeom: Geometric bounds cannot be null", K(ret), K(obj_type2)); + } else { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid input type extent", K(ret), K(obj_type2)); + } + } + // integer extent + if (OB_SUCC(ret) && param_num >= 3) { + ObObjType extent_type = types_stack[2].get_type(); + if (extent_type == ObTinyIntType + || (!ob_is_integer_type(extent_type) && extent_type != ObVarcharType && !ob_is_null(extent_type))) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid input type extent", K(ret), K(extent_type)); + } else if (ob_is_string_type(extent_type)) { + types_stack[2].set_calc_type(ObIntType); + } + } + // integer buffer + if (OB_SUCC(ret) && param_num >= 4) { + ObObjType extent_type = types_stack[3].get_type(); + if (extent_type == ObTinyIntType + || (!ob_is_integer_type(extent_type) && extent_type != ObVarcharType && !ob_is_null(extent_type))) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid input type extent", K(ret), K(extent_type)); + } else if (ob_is_string_type(extent_type)) { + types_stack[3].set_calc_type(ObIntType); + } + } + // boolean clip_geom + if (OB_SUCC(ret) && param_num >= 5) { + ObObjType extent_type = types_stack[4].get_type(); + if (extent_type != ObTinyIntType && extent_type != ObVarcharType + && !ob_is_null(extent_type)) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid input type extent", K(ret), K(extent_type)); + } else if (ob_is_string_type(extent_type)) { + types_stack[4].set_calc_type(ObTinyIntType); + } + } + + if (OB_SUCC(ret)) { + ObCastMode cast_mode = type_ctx.get_cast_mode(); + cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail + cast_mode |= CM_STRING_INTEGER_TRUNC; // make cast check range when string to int + type_ctx.set_cast_mode(cast_mode); // cast mode only do work in new sql engine cast frame. + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); + } + return ret; +} + +int ObExprPrivSTAsMVTGeom::process_input_geometry(const ObExpr &expr, ObEvalCtx &ctx, + bool &is_null_res, ObGeometry *&geo1, ObGeogBox *&bounds, int32_t &extent, int32_t &buffer, + bool &clip_geom) +{ + int ret = OB_SUCCESS; + ObDatum *datum1 = nullptr; + ObDatum *datum2 = nullptr; + ObExpr *arg1 = expr.args_[0]; + ObExpr *arg2 = expr.args_[1]; + ObObjType type1 = arg1->datum_meta_.type_; + ObObjType type2 = arg2->datum_meta_.type_; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs1 = nullptr; + const ObSrsItem *srs2 = nullptr; + ObEvalCtx::TempAllocGuard ctx_alloc_g(ctx); + common::ObArenaAllocator &ctx_allocator = ctx_alloc_g.get_allocator(); + // ObArenaAllocator tmp_allocator; + ObGeometry *geo2 = nullptr; + + // process two geometry + if (ob_is_null(type1)) { + is_null_res = true; + } else if (ob_is_null(type2)) { + ret = OB_ERR_NULL_INPUT; + LOG_WARN("_ST_AsMVTGeom: Geometric bounds cannot be null", K(ret)); + } else if (OB_FAIL(arg1->eval(ctx, datum1)) || OB_FAIL(arg2->eval(ctx, datum2))) { + LOG_WARN("fail to eval args", K(ret)); + } else if (datum1->is_null()) { + is_null_res = true; + } else if (datum2->is_null()) { + ret = OB_ERR_NULL_INPUT; + LOG_WARN("_ST_AsMVTGeom: Geometric bounds cannot be null", K(ret)); + } else { + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &ctx_allocator = tmp_alloc_g.get_allocator(); + ObString wkb1 = datum1->get_string(); + ObString wkb2 = datum2->get_string(); + ObGeoEvalCtx box_ctx(&ctx_allocator); + box_ctx.set_is_called_in_pg_expr(true); + + if (OB_FAIL(ObTextStringHelper::read_real_string_data( + ctx_allocator, *datum1, arg1->datum_meta_, arg1->obj_meta_.has_lob_header(), wkb1))) { + LOG_WARN( + "fail to read real string data", K(ret), K(arg1->obj_meta_.has_lob_header()), K(wkb1)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(ctx_allocator, + *datum2, + arg2->datum_meta_, + arg2->obj_meta_.has_lob_header(), + wkb2))) { + LOG_WARN( + "fail to read real string data", K(ret), K(arg2->obj_meta_.has_lob_header()), K(wkb2)); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb1, srs1, true, N_PRIV_ST_ASMVTGEOM)) + || OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb2, srs2, true, N_PRIV_ST_ASMVTGEOM))) { + if (ret == OB_ERR_SRS_NOT_FOUND) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_ASMVTGEOM); + } + LOG_WARN("fail to get srs item", K(ret), K(wkb1), K(wkb2)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(ctx_allocator, + wkb1, + geo1, + srs1, + N_PRIV_ST_ASMVTGEOM, + ObGeoBuildFlag::GEO_NORMALIZE | ObGeoBuildFlag::GEO_CHECK_RING))) { + LOG_WARN("get first geo by wkb failed", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(ctx_allocator, + wkb2, + geo2, + srs2, + N_PRIV_ST_ASMVTGEOM, + ObGeoBuildFlag::GEO_DEFAULT | ObGeoBuildFlag::GEO_CHECK_RING))) { + LOG_WARN("get second geo by wkb failed", K(ret)); + } else if (OB_NOT_NULL(srs1) && srs1->is_geographical_srs()) { + ret = OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS; + LOG_USER_ERROR(OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS, N_PRIV_ST_ASMVTGEOM, + ObGeoTypeUtil::get_geo_name_by_type(geo1->type())); + LOG_WARN("Geometry in geographical srs can not be input", K(ret), K(srs1)); + } else if (OB_NOT_NULL(srs2) && srs2->is_geographical_srs()) { + ret = OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS; + LOG_USER_ERROR(OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS, N_PRIV_ST_ASMVTGEOM, + ObGeoTypeUtil::get_geo_name_by_type(geo2->type())); + LOG_WARN("Geometry in geographical srs can not be input", K(ret), K(srs2)); + } else if (OB_FAIL(box_ctx.append_geo_arg(geo2))) { + LOG_WARN("build gis context failed", K(ret), K(box_ctx.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(box_ctx, bounds))) { + LOG_WARN("failed to do box functor failed", K(ret)); + } else if ((bounds->xmax - bounds->xmin) <= 0 || ((bounds->ymax - bounds->ymin) <= 0)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_ASMVTGEOM); + LOG_WARN("_ST_AsMVTGeom: Geometric bounds are too small", + K(ret), + K(bounds->xmin), + K(bounds->ymin), + K(bounds->ymax), + K(bounds->xmax)); + } + } + // process extent + uint32_t num_args = expr.arg_cnt_; + extent = 4096; // default + if (OB_SUCC(ret) && num_args >= 3) { + ObDatum *datum = nullptr; + if (OB_FAIL(expr.args_[2]->eval(ctx, datum))) { + LOG_WARN("fail to eval second argument", K(ret)); + } else if (datum->is_null()) { + // use default value + } else if (datum->get_int() <= 0 || datum->get_int() > INT_MAX32) { + ret = OB_OPERATE_OVERFLOW; + LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "extent", N_PRIV_ST_ASMVTGEOM); + LOG_WARN("_ST_AsMVTGeom: Extent must be greater than 0", K(ret), K(datum->get_int())); + } else { + extent = datum->get_int32(); + } + } + // process buffer + buffer = 256; // default + if (OB_SUCC(ret) && num_args >= 4) { + ObDatum *datum = nullptr; + if (OB_FAIL(expr.args_[3]->eval(ctx, datum))) { + LOG_WARN("fail to eval second argument", K(ret)); + } else if (datum->is_null()) { + // use default value + } else if (datum->get_int() < 0 || datum->get_int() > INT_MAX32) { + ret = OB_OPERATE_OVERFLOW; + LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "buffer", N_PRIV_ST_ASMVTGEOM); + LOG_WARN("value is out of range", K(ret), K(datum->get_int())); + } else { + buffer = datum->get_int32(); + } + } + // process clip_geom + clip_geom = true; // default + int8_t clip_num = 0; + if (OB_SUCC(ret) && num_args >= 5) { + ObDatum *datum = nullptr; + if (OB_FAIL(expr.args_[4]->eval(ctx, datum))) { + LOG_WARN("fail to eval second argument", K(ret)); + } else if (datum->is_null()) { + // use default value + } else if (FALSE_IT(clip_num = datum->get_tinyint())) { + } else { + clip_geom = datum->get_tinyint(); + } + } + return ret; +} + +int ObExprPrivSTAsMVTGeom::get_basic_type(ObGeometry *geo, ObGeoType &basic_type) +{ + int ret = OB_SUCCESS; + switch (geo->type()) { + case ObGeoType::POINT: + case ObGeoType::MULTIPOINT: { + basic_type = ObGeoType::POINT; + break; + } + case ObGeoType::LINESTRING: + case ObGeoType::MULTILINESTRING: { + basic_type = ObGeoType::LINESTRING; + break; + } + case ObGeoType::POLYGON: + case ObGeoType::MULTIPOLYGON: { + basic_type = ObGeoType::POLYGON; + break; + } + case ObGeoType::GEOMETRYCOLLECTION: { + int8_t dimension = 0; + ObIWkbGeomCollection *coll = reinterpret_cast(geo); + if (OB_FAIL(ObGeoTypeUtil::get_coll_dimension(coll, dimension))) { + LOG_WARN("fail to get collection dimension", K(ret)); + } else { + basic_type = static_cast(dimension + 1); + } + break; + } + default: { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid geo type", K(ret), K(geo->type())); + break; + } + } + return ret; +} + +int ObExprPrivSTAsMVTGeom::affine_to_tile_space( + ObGeometry *&geo, const ObGeogBox *bounds, int32_t extent) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(geo) || OB_ISNULL(bounds)) { + ret = OB_ERR_NULL_INPUT; + LOG_WARN("geometry and bounds cannot be null", K(ret), K(geo), K(bounds)); + } else { + double x_fac = extent / (bounds->xmax - bounds->xmin); + double y_fac = -(extent / (bounds->ymax - bounds->ymin)); + ObAffineMatrix affine = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + affine.x_fac1 = x_fac; + affine.y_fac2 = y_fac; + affine.z_fac3 = 1; + affine.x_off = -bounds->xmin * x_fac; + affine.y_off = -bounds->ymax * y_fac; + if (OB_FAIL(ObGeoMVTUtil::affine_transformation(geo, affine))) { + LOG_WARN("fail to do affine transformation", + K(ret), + K(x_fac), + K(y_fac), + K(affine.x_off), + K(affine.y_off)); + } + } + return ret; +} + +int ObExprPrivSTAsMVTGeom::split_geo_to_basic_type( + ObGeometry *&geo, ObIAllocator &allocator, ObGeoType basic_type, ObGeometry *&split_geo) +{ + int ret = OB_SUCCESS; + if (geo->type() == ObGeoType::GEOMETRYCOLLECTION) { + ObCartesianMultipoint *mpt = NULL; + ObCartesianMultilinestring *mls = NULL; + ObCartesianMultipolygon *mpy = NULL; + if (OB_FAIL(ObGeoFuncUtils::ob_geo_gc_split( + allocator, *static_cast(geo), mpt, mls, mpy))) { + LOG_WARN("failed to do gc split", K(ret)); + } else if (OB_ISNULL(mpt) || OB_ISNULL(mls) || OB_ISNULL(mpt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geometry collection split", K(ret)); + } else { + if (basic_type == ObGeoType::POLYGON) { + split_geo = mpy; + } else if (basic_type == ObGeoType::LINESTRING) { + split_geo = mls; + } else { + split_geo = mpt; + } + } + } else { + split_geo = geo; + } + if (OB_SUCC(ret) + && OB_FAIL((ObGeoFuncUtils::simplify_multi_geo( + split_geo, allocator)))) { + LOG_WARN("fail to simplify multi geometry", K(ret)); + } + return ret; +} + +int ObExprPrivSTAsMVTGeom::snap_geometry_to_grid( + ObGeometry *&geo, ObIAllocator &allocator, bool use_floor) +{ + int ret = OB_SUCCESS; + ObGeoGrid grid = {0, 0, 0, 1, 1, 0}; + if (OB_FAIL(ObGeoMVTUtil::snap_to_grid(geo, grid, use_floor))) { + LOG_WARN("fail to do snap to grid", K(ret)); + } else if (OB_FAIL((ObGeoFuncUtils::simplify_multi_geo( + geo, allocator)))) { + LOG_WARN("fail to simplify multi geometry", K(ret)); + } + return ret; +} + +int ObExprPrivSTAsMVTGeom::clip_geometry(ObGeometry *geo, ObIAllocator &allocator, + ObGeoType basic_type, int32_t extent, int32_t buffer, bool clip_geom, bool &is_null_res, + ObGeometry *&res_geo) +{ + int ret = OB_SUCCESS; + ObGeometry *basic_geo = nullptr; + ObGeogBox *clip_box = nullptr; + bool is_geo_empty = false; + if (OB_FAIL(split_geo_to_basic_type(geo, allocator, ObGeoType::POLYGON, basic_geo))) { + LOG_WARN("fail to split geo to basic type", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(basic_geo, is_geo_empty))) { + LOG_WARN("fail to check empty", K(ret)); + } else if (is_geo_empty) { + is_null_res = true; + } else if (basic_geo->type() != ObGeoType::POLYGON && basic_geo->type() != ObGeoType::MULTIPOLYGON + && !clip_geom) { + res_geo = basic_geo; + } else { + if (clip_geom) { + if (OB_ISNULL(clip_box = OB_NEWx(ObGeogBox, &allocator))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } else { + clip_box->xmax = clip_box->ymax = extent + static_cast(buffer); + clip_box->xmin = clip_box->ymin = -static_cast(buffer); + if (OB_FAIL(ObGeoBoxUtil::clip_by_box(*basic_geo, allocator, *clip_box, res_geo, true))) { + LOG_WARN("fail to do clip by box", K(ret)); + } else if (OB_ISNULL(res_geo)) { + is_null_res = true; + } else if (OB_FAIL(ObGeoExprUtils::check_empty(res_geo, is_geo_empty))) { + LOG_WARN("fail to check empty", K(ret)); + } else if (is_geo_empty) { + is_null_res = true; + } + } + } else { + res_geo = basic_geo; + } + if (OB_FAIL(ret) || is_null_res) { + } else if (basic_geo->type() == ObGeoType::POLYGON + || basic_geo->type() == ObGeoType::MULTIPOLYGON) { + ObGeometry *valid_poly = nullptr; + if (OB_FAIL(ObGeoExprUtils::make_valid_polygon(res_geo, allocator, valid_poly))) { + LOG_WARN("fail to make polygon valid", K(ret)); + } else { + res_geo = valid_poly; + if (OB_FAIL(snap_geometry_to_grid(res_geo, allocator, true))) { + LOG_WARN("fail to snap geometry to grid", K(ret)); + } + } + } else if (OB_FAIL(snap_geometry_to_grid(res_geo, allocator, false))) { + LOG_WARN("fail to snap geometry to grid", K(ret)); + } + } + return ret; +} + +int ObExprPrivSTAsMVTGeom::eval_priv_st_asmvtgeom(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_null_res = false; + ObGeometry *geo1 = nullptr; + bool is_geo_empty = false; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObGeogBox *bounds = nullptr; + int32_t extent = 4096; + int32_t buffer = 256; + bool clip_geom = true; + ObGeometry *res_geo = nullptr; + ObString res_wkb; + + if (OB_FAIL(process_input_geometry( + expr, ctx, is_null_res, geo1, bounds, extent, buffer, clip_geom))) { + LOG_WARN("fail to process input geometry", K(ret), K(geo1), K(is_null_res)); + } else if (is_null_res) { + // do nothing + } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo1, is_geo_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_geo_empty) { + is_null_res = true; + } else if (geo1->type() == ObGeoType::LINESTRING || geo1->type() == ObGeoType::MULTILINESTRING) { + // pre-check + ObGeogBox fast_box; + bool has_fast_box = false; + if (OB_FAIL(ObGeoBoxUtil::fast_box(geo1, fast_box, has_fast_box))) { + LOG_WARN("fail to calculate fast box", K(ret), K(geo1->type())); + } else if (has_fast_box) { + double fast_box_width = fast_box.xmax - fast_box.xmin; + double fast_box_height = fast_box.ymax - fast_box.ymin; + double bounds_width = (bounds->xmax - bounds->xmin) / extent / 2.0; + double bounds_height = (bounds->ymax - bounds->ymin) / extent / 2.0; + if (fast_box_width < bounds_width && fast_box_height < bounds_height) { + is_null_res = true; + } + } + } + + ObGeoType basic_type = ObGeoType::GEOTYPEMAX; // POINT/LINE/POLYGON + ObGeometry *split_geo = nullptr; + ObGeometry *geo_tree = nullptr; + ObGeoToTreeVisitor tree_visitor(&temp_allocator); + if (OB_FAIL(ret) || is_null_res) { + // do nothing + } else if (OB_FAIL(get_basic_type(geo1, basic_type))) { + LOG_WARN("fail to get basic type", K(ret)); + } else if (OB_FAIL(geo1->do_visit(tree_visitor))) { + LOG_WARN("failed to transform gc to tree", K(ret)); + } else if (FALSE_IT(geo_tree = tree_visitor.get_geometry())) { + } else if (OB_FAIL(split_geo_to_basic_type( + geo_tree, temp_allocator, basic_type, split_geo))) { // split_geo: ObCartesian* + LOG_WARN("fail to split geometry to basic type", K(ret), K(basic_type)); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(split_geo, is_geo_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_geo_empty) { + is_null_res = true; + } else if (OB_FAIL(affine_to_tile_space(split_geo, bounds, extent))) { + LOG_WARN("fail to affine geometry", K(ret), K(extent)); + } else if (OB_FAIL(snap_geometry_to_grid(split_geo, temp_allocator, false))) { + LOG_WARN("fail to do snap geometry", K(ret)); + } else if (OB_FAIL(ObGeoMVTUtil::simplify_geometry(split_geo))) { + LOG_WARN("fail to simplify geometry", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(split_geo, is_geo_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_geo_empty) { + is_null_res = true; + } else if (OB_FAIL(clip_geometry(split_geo, + temp_allocator, + basic_type, + extent, + buffer, + clip_geom, + is_null_res, + res_geo))) { + LOG_WARN("fail to clip geometry", K(ret)); + } else if (OB_FAIL((ObGeoFuncUtils::simplify_multi_geo( + res_geo, temp_allocator)))) { + LOG_WARN("fail to simplify multi geometry", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(res_geo, is_geo_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_geo_empty) { + is_null_res = true; + } + + if (OB_SUCC(ret)) { + if (is_null_res) { + res.set_null(); + } else { + ObGeometry *res_bin = nullptr; + if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(temp_allocator, res_geo, res_bin, nullptr))) { + LOG_WARN("fail to convert tree to bin", K(ret)); + } else if (FALSE_IT(res_bin->set_srid(geo1->get_srid()))) { + } else if (OB_FAIL(ObGeoExprUtils::geo_to_wkb( + *res_bin, expr, ctx, nullptr, res_wkb, geo1->get_srid()))) { + LOG_WARN("fail to get wkb from geometry", K(ret)); + } else { + res.set_string(res_wkb); + } + } + } + return ret; +} + +int ObExprPrivSTAsMVTGeom::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_asmvtgeom; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_asmvtgeom.h b/src/sql/engine/expr/ob_expr_priv_st_asmvtgeom.h new file mode 100644 index 0000000000..5358cf3b3e --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_asmvtgeom.h @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_asmvtgeom. + */ +#ifndef OCEANBASE_SQL_OB_EXPR_ST_ASMVTGEOM_ +#define OCEANBASE_SQL_OB_EXPR_ST_ASMVTGEOM_ +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_func_box.h" + +namespace oceanbase +{ +namespace common +{ +class ObGeometry; +} +namespace sql +{ +class ObExprPrivSTAsMVTGeom : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTAsMVTGeom(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTAsMVTGeom(); + virtual int calc_result_typeN(ObExprResType &type, ObExprResType *types, int64_t param_num, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_priv_st_asmvtgeom(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int clip_geometry(ObGeometry *geo, ObIAllocator &allocator, ObGeoType basic_type, + int32_t extent, int32_t buffer, bool clip_geom, bool &is_null_res, ObGeometry *&res_geo); + static int get_basic_type(ObGeometry *geo, ObGeoType &basic_type); + static int snap_geometry_to_grid(ObGeometry *&geo, ObIAllocator &allocator, bool use_floor); + static int split_geo_to_basic_type( + ObGeometry *&geo, ObIAllocator &allocator, ObGeoType basic_type, ObGeometry *&split_geo); + static int affine_to_tile_space(ObGeometry *&geo, const ObGeogBox *bounds, int32_t extent); + static int process_input_geometry(const ObExpr &expr, ObEvalCtx &ctx, bool &is_null_res, + ObGeometry *&geo1, ObGeogBox *&bounds, int32_t &extent, int32_t &buffer, bool &clip_geom); + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTAsMVTGeom); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_ASMVTGEOM_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_clipbybox2d.cpp b/src/sql/engine/expr/ob_expr_priv_st_clipbybox2d.cpp new file mode 100644 index 0000000000..1289ddb10f --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_clipbybox2d.cpp @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_clipbybox2d. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_priv_st_clipbybox2d.h" +#include "sql/session/ob_sql_session_info.h" +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_utils.h" +#include "share/object/ob_obj_cast_util.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +ObExprPrivSTClipByBox2D::ObExprPrivSTClipByBox2D(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_CLIPBYBOX2D, N_PRIV_ST_CLIPBYBOX2D, 2, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprPrivSTClipByBox2D::~ObExprPrivSTClipByBox2D() +{} + +int ObExprPrivSTClipByBox2D::calc_result_type2(ObExprResType &type, ObExprResType &type1, + ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObObjType obj_type1 = type1.get_type(); + ObObjType obj_type2 = type2.get_type(); + + if (!ob_is_string_type(obj_type1) && !ob_is_geometry(obj_type1) && !ob_is_null(obj_type1)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_CLIPBYBOX2D); + LOG_WARN("invalid type", K(ret), K(obj_type1)); + } else if (!ob_is_string_type(obj_type2) && !ob_is_geometry(obj_type2) + && !ob_is_null(obj_type2)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_CLIPBYBOX2D); + LOG_WARN("invalid type", K(ret), K(obj_type2)); + } else { + ObCastMode cast_mode = type_ctx.get_cast_mode(); + cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail + type_ctx.set_cast_mode(cast_mode); // cast mode only do work in new sql engine cast frame. + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); + } + + return ret; +} + +int ObExprPrivSTClipByBox2D::process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, + bool &is_null_res, ObGeometry *&geo1, ObGeometry *&geo2, const ObSrsItem *&srs1, + const ObSrsItem *&srs2) +{ + int ret = OB_SUCCESS; + ObDatum *datum1 = nullptr; + ObDatum *datum2 = nullptr; + ObExpr *arg1 = expr.args_[0]; + ObExpr *arg2 = expr.args_[1]; + ObObjType type1 = arg1->datum_meta_.type_; + ObObjType type2 = arg2->datum_meta_.type_; + + if (ob_is_null(type1) || ob_is_null(type2)) { + is_null_res = true; + } else if (OB_FAIL(arg1->eval(ctx, datum1)) || OB_FAIL(arg2->eval(ctx, datum2))) { + LOG_WARN("fail to eval args", K(ret)); + } else if (datum1->is_null() || datum2->is_null()) { + is_null_res = true; + } else { + ObString wkb1 = datum1->get_string(); + ObString wkb2 = datum2->get_string(); + + if (OB_FAIL(ObTextStringHelper::read_real_string_data( + allocator, *datum1, arg1->datum_meta_, arg1->obj_meta_.has_lob_header(), wkb1))) { + LOG_WARN( + "fail to read real string data", K(ret), K(arg1->obj_meta_.has_lob_header()), K(wkb1)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *datum2, + arg2->datum_meta_, + arg2->obj_meta_.has_lob_header(), + wkb2))) { + LOG_WARN( + "fail to read real string data", K(ret), K(arg2->obj_meta_.has_lob_header()), K(wkb2)); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb1, srs1, true, N_PRIV_ST_CLIPBYBOX2D))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb1)); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb2, srs2, true, N_PRIV_ST_CLIPBYBOX2D))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb2)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry( + allocator, wkb1, geo1, nullptr, N_PRIV_ST_CLIPBYBOX2D))) { // ObIWkbGeom + LOG_WARN("fail to build geometry from wkb", K(ret), K(wkb1)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry( + allocator, wkb2, geo2, nullptr, N_PRIV_ST_CLIPBYBOX2D))) { // ObIWkbGeom + LOG_WARN("fail to build geometry from wkb", K(ret), K(wkb2)); + } else if (OB_NOT_NULL(srs1) && srs1->is_geographical_srs()) { + ret = OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS; + LOG_USER_ERROR(OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS, N_PRIV_ST_ASMVTGEOM, + ObGeoTypeUtil::get_geo_name_by_type(geo1->type())); + LOG_WARN("Geometry in geographical srs can not be input", K(ret), K(srs1)); + } else if (OB_NOT_NULL(srs2) && srs2->is_geographical_srs()) { + ret = OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS; + LOG_USER_ERROR(OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS, N_PRIV_ST_ASMVTGEOM, + ObGeoTypeUtil::get_geo_name_by_type(geo2->type())); + LOG_WARN("Geometry in geographical srs can not be input", K(ret), K(srs2)); + } + } + return ret; +} + +int ObExprPrivSTClipByBox2D::eval_priv_st_clipbybox2d( + const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_null_res = false; + ObGeometry *geo1 = nullptr; + ObGeometry *geo2 = nullptr; + ObGeometry *res_geo = NULL; + bool is_geo1_empty = false; + bool is_geo2_empty = false; + const ObSrsItem *srs1 = nullptr; + const ObSrsItem *srs2 = nullptr; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObString res_wkb; + omt::ObSrsCacheGuard srs_guard; + + if (OB_FAIL(process_input_geometry(srs_guard, expr, ctx, temp_allocator, is_null_res, geo1, geo2, srs1, srs2))) { + LOG_WARN("fail to process input geometry", K(ret), K(geo1), K(geo2), K(is_null_res)); + } else if (is_null_res) { + // do nothing + } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo1, is_geo1_empty)) + || OB_FAIL(ObGeoExprUtils::check_empty(geo2, is_geo2_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_geo2_empty) { + is_null_res = true; + } else if (is_geo1_empty) { + // return empty when first geo argument is empty + res_geo = geo1; + } else { + ObGeoEvalCtx box_ctx(&temp_allocator); + box_ctx.set_is_called_in_pg_expr(true); + ObGeogBox *gbox = nullptr; + // calculate 2d box of geo2, then convert the box to a rectangle geo + if (OB_FAIL(box_ctx.append_geo_arg(geo2))) { + LOG_WARN("build gis context failed", K(ret), K(box_ctx.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(box_ctx, gbox))) { + LOG_WARN("failed to do box functor failed", K(ret)); + } else if (OB_FAIL(ObGeoBoxUtil::clip_by_box(*geo1, temp_allocator, *gbox, res_geo, true))) { + LOG_WARN("fail to do clip by box", K(ret)); + } else if (OB_ISNULL(res_geo)) { + is_null_res = true; + } + } + + if (OB_SUCC(ret)) { + if (is_null_res) { + res.set_null(); + } else { + if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*res_geo, expr, ctx, srs1, res_wkb))) { + LOG_WARN("fail to get wkb from geometry", K(ret)); + } else { + res.set_string(res_wkb); + } + } + } + return ret; +} + +int ObExprPrivSTClipByBox2D::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_clipbybox2d; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_clipbybox2d.h b/src/sql/engine/expr/ob_expr_priv_st_clipbybox2d.h new file mode 100644 index 0000000000..7816d7268c --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_clipbybox2d.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_clipbybox2d. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_CLIPBYBOX2D_ +#define OCEANBASE_SQL_OB_EXPR_ST_CLIPBYBOX2D_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "observer/omt/ob_tenant_srs.h" + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace sql +{ +class ObExprPrivSTClipByBox2D : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTClipByBox2D(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTClipByBox2D(); + virtual int calc_result_type2( + ObExprResType &type, ObExprResType &type1, ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const override; + static int eval_priv_st_clipbybox2d(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, bool &is_null_res, ObGeometry *&geo1, + ObGeometry *&geo2, const ObSrsItem *&srs1, const ObSrsItem *&srs2); + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTClipByBox2D); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_CLIPBYBOX2D_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_equals.cpp b/src/sql/engine/expr/ob_expr_priv_st_equals.cpp new file mode 100644 index 0000000000..ae67320a6a --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_equals.cpp @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_priv_st_equals. + */ + +#define USING_LOG_PREFIX SQL_ENG + +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_ibin.h" +#include "sql/engine/ob_exec_context.h" +#include "ob_expr_priv_st_equals.h" +#include "lib/geo/ob_geo_utils.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ + +ObExprPrivSTEquals::ObExprPrivSTEquals(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_EQUALS, N_PRIV_ST_EQUALS, 2, + VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprPrivSTEquals::~ObExprPrivSTEquals() +{} + +int ObExprPrivSTEquals::calc_result_type2(ObExprResType &type, ObExprResType &type1, + ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + INIT_SUCC(ret); + if (type1.get_type() == ObNullType) { + } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { + type1.set_calc_type(ObVarcharType); + type1.set_calc_collation_type(CS_TYPE_BINARY); + } + if (type2.get_type() == ObNullType) { + } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { + type2.set_calc_type(ObVarcharType); + type2.set_calc_collation_type(CS_TYPE_BINARY); + } + type.set_int(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + return ret; +} + +int ObExprPrivSTEquals::get_input_geometry(omt::ObSrsCacheGuard &srs_guard, ObDatum *gis_datum, ObEvalCtx &ctx, ObExpr *gis_arg, bool &is_null_geo, + const ObSrsItem *&srs, ObGeometry *&geo, bool &is_geo_empty) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard ctx_alloc_g(ctx); + common::ObArenaAllocator &allocator = ctx_alloc_g.get_allocator(); + if (OB_FAIL(gis_arg->eval(ctx, gis_datum))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum->is_null()) { + is_null_geo = true; + } else { + ObString wkb = gis_datum->get_string(); + ObGeoType type = ObGeoType::GEOTYPEMAX; + uint32_t srid = -1; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum, + gis_arg->datum_meta_, + gis_arg->obj_meta_.has_lob_header(), + wkb))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb, type, srid))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_EQUALS); + } + LOG_WARN("get type and srid from wkb failed", K(wkb), K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb, srs, true, N_PRIV_ST_EQUALS))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(allocator, + wkb, + geo, + srs, + N_PRIV_ST_EQUALS, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { + LOG_WARN("get first geo by wkb failed", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo, is_geo_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } + } + return ret; +} + +int ObExprPrivSTEquals::eval_priv_st_equals(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObExpr *gis_arg1 = expr.args_[0]; + ObExpr *gis_arg2 = expr.args_[1]; + bool is_geo1_empty = false; + bool is_geo2_empty = false; + bool is_geo1_null = false; + bool is_geo2_null = false; + ObGeometry *geo1 = nullptr; + ObGeometry *geo2 = nullptr; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs1 = nullptr; + const ObSrsItem *srs2 = nullptr; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObDatum *gis_datum1 = nullptr; + ObDatum *gis_datum2 = nullptr; + if (OB_FAIL(gis_arg1->eval(ctx, gis_datum1)) || OB_FAIL(gis_arg2->eval(ctx, gis_datum2))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum1->is_null() || gis_datum2->is_null()) { + res.set_null(); + } else if (OB_FAIL(get_input_geometry(srs_guard, gis_datum1, ctx, gis_arg1, is_geo1_null, srs1, geo1, is_geo1_empty))) { + LOG_WARN("fail to get input geometry", K(ret)); + } else if (OB_FAIL(get_input_geometry(srs_guard, gis_datum2, ctx, gis_arg2, is_geo2_null, srs2, geo2, is_geo2_empty))) { + LOG_WARN("fail to get input geometry", K(ret)); + } else { + uint32_t srid1 = srs1 == nullptr ? 0 : srs1->get_srid(); + uint32_t srid2 = srs2 == nullptr ? 0 : srs2->get_srid(); + if (srid1 != srid2) { + ret = OB_ERR_GIS_DIFFERENT_SRIDS; + LOG_WARN("srid not the same", K(ret), K(srid1), K(srid2)); + LOG_USER_ERROR(OB_ERR_GIS_DIFFERENT_SRIDS, N_PRIV_ST_EQUALS, srid1, srid2); + } else if (is_geo1_empty || is_geo2_empty) { + res.set_bool(is_geo1_empty && is_geo2_empty); + } else if (OB_FAIL(ObGeoExprUtils::zoom_in_geos_for_relation(*geo1, *geo2))) { + LOG_WARN("zoom in geos failed", K(ret)); + } else { + bool result = false; + ObGeoEvalCtx gis_context(&temp_allocator, srs1); + if (OB_FAIL(gis_context.append_geo_arg(geo1)) || OB_FAIL(gis_context.append_geo_arg(geo2))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, result))) { + LOG_WARN("eval st intersection failed", K(ret)); + ObGeoExprUtils::geo_func_error_handle(ret, N_PRIV_ST_EQUALS); + } else { + res.set_bool(result); + } + } + } + return ret; +} + +int ObExprPrivSTEquals::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_equals; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_priv_st_equals.h b/src/sql/engine/expr/ob_expr_priv_st_equals.h new file mode 100644 index 0000000000..81d18e4a3f --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_equals.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_priv_st_equals. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_PRIV_ST_EQUALS_H_ +#define OCEANBASE_SQL_OB_EXPR_PRIV_ST_EQUALS_H_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "observer/omt/ob_tenant_srs.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprPrivSTEquals : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTEquals(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTEquals(); + virtual int calc_result_type2(ObExprResType &type, ObExprResType &type1, ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_priv_st_equals(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int get_input_geometry(omt::ObSrsCacheGuard &srs_guard, ObDatum *gis_datum, ObEvalCtx &ctx, ObExpr *gis_arg, + bool &is_null_geo, const ObSrsItem *&srs, ObGeometry *&geo, bool &is_geo_empty); + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTEquals); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_PRIV_ST_EQUALS_H_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_geogfromtext.cpp b/src/sql/engine/expr/ob_expr_priv_st_geogfromtext.cpp index 2050bc2a9f..6faff3aa7e 100644 --- a/src/sql/engine/expr/ob_expr_priv_st_geogfromtext.cpp +++ b/src/sql/engine/expr/ob_expr_priv_st_geogfromtext.cpp @@ -131,7 +131,9 @@ int ObExprPrivSTGeogFromText::eval_priv_st_geogfromtext_common(const ObExpr &exp LOG_WARN("unexpected null geo after parse_wkt", K(ret), K(wkt)); } else if (OB_FAIL(ObGeoExprUtils::correct_coordinate_range(srs_item, geo, func_name))) { LOG_WARN("check geo coordinate range failed", K(ret)); - } else { + } + + if (OB_SUCC(ret)) { ObString res_wkb; if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*geo, expr, ctx, srs_item, res_wkb))) { LOG_WARN("failed to write geometry to wkb", K(ret)); diff --git a/src/sql/engine/expr/ob_expr_priv_st_geometrytype.cpp b/src/sql/engine/expr/ob_expr_priv_st_geometrytype.cpp new file mode 100644 index 0000000000..dff378fc29 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_geometrytype.cpp @@ -0,0 +1,110 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_geometrytype. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_priv_st_geometrytype.h" +#include "share/object/ob_obj_cast_util.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/json_type/ob_json_base.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +ObExprPrivSTGeometryType::ObExprPrivSTGeometryType(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_GEOMETRYTYPE, N_PRIV_ST_GEOMETRYTYPE, 1, NOT_VALID_FOR_GENERATED_COL, + NOT_ROW_DIMENSION) +{} + +ObExprPrivSTGeometryType::~ObExprPrivSTGeometryType() +{} + +int ObExprPrivSTGeometryType::calc_result_type1( + ObExprResType &type, ObExprResType &type1, common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObObjType obj_type1 = type1.get_type(); + + if (!ob_is_string_type(obj_type1) && !ob_is_geometry(obj_type1) && !ob_is_null(obj_type1)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_GEOMETRYTYPE); + LOG_WARN("invalid type", K(ret), K(obj_type1)); + } else { + ObCastMode cast_mode = type_ctx.get_cast_mode(); + cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail + type_ctx.set_cast_mode(cast_mode); // cast mode only do work in new sql engine cast frame. + type.set_varchar(); + type.set_collation_type(type_ctx.get_coll_type()); + type.set_collation_level(CS_LEVEL_IMPLICIT); + type.set_length(MAX_TYPE_LEN); + } + + return ret; +} + +int ObExprPrivSTGeometryType::eval_priv_st_geometrytype(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_null_res = false; + ObDatum *datum1 = nullptr; + ObExpr *arg1 = expr.args_[0]; + ObObjType type1 = arg1->datum_meta_.type_; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObString res_type; + + if (ob_is_null(type1)) { + is_null_res = true; + } else if (OB_FAIL(arg1->eval(ctx, datum1))) { + LOG_WARN("fail to eval args", K(ret)); + } else if (datum1->is_null()) { + is_null_res = true; + } else { + ObString wkb = datum1->get_string(); + ObGeoType gtype = ObGeoType::GEOTYPEMAX; + + if (OB_FAIL(ObTextStringHelper::read_real_string_data( + temp_allocator, *datum1, arg1->datum_meta_, arg1->obj_meta_.has_lob_header(), wkb))) { + LOG_WARN("fail to read real string data", K(ret), K(arg1->obj_meta_.has_lob_header())); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_from_wkb(wkb, gtype))) { + LOG_WARN("fail to get geo type from wkb", K(ret), K(gtype)); + } else if (OB_FAIL(ObGeoTypeUtil::get_st_geo_name_by_type(gtype, res_type))) { + LOG_WARN("fail to get geo type name", K(ret), K(gtype)); + } + } + + if (OB_SUCC(ret)) { + if (is_null_res) { + res.set_null(); + } else { + res.set_string(res_type); + } + } + + return ret; +} + +int ObExprPrivSTGeometryType::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_geometrytype; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_geometrytype.h b/src/sql/engine/expr/ob_expr_priv_st_geometrytype.h new file mode 100644 index 0000000000..f65631b6d0 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_geometrytype.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_geometrytype. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_GEOMETRYTYPE_ +#define OCEANBASE_SQL_OB_EXPR_ST_GEOMETRYTYPE_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace sql +{ +class ObExprPrivSTGeometryType : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTGeometryType(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTGeometryType(); + virtual int calc_result_type1(ObExprResType &type, ObExprResType &type1, common::ObExprTypeCtx &type_ctx) const; + static int eval_priv_st_geometrytype(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; +private: + static const int32_t MAX_TYPE_LEN = 22; // ST_GeometryCollection + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTGeometryType); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_GEOMETRYTYPE_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_iscollection.cpp b/src/sql/engine/expr/ob_expr_priv_st_iscollection.cpp new file mode 100644 index 0000000000..bb8b306f77 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_iscollection.cpp @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_iscollection. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_priv_st_iscollection.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "share/object/ob_obj_cast_util.h" +#include "lib/geo/ob_geo_utils.h" +#include "observer/omt/ob_tenant_srs.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +ObExprPrivSTIsCollection::ObExprPrivSTIsCollection(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_ISCOLLECTION, N_PRIV_ST_ISCOLLECTION, 1, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprPrivSTIsCollection::~ObExprPrivSTIsCollection() +{} + +int ObExprPrivSTIsCollection::calc_result_type1( + ObExprResType &type, ObExprResType &type1, common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObObjType obj_type1 = type1.get_type(); + + if (!ob_is_string_type(obj_type1) && !ob_is_geometry(obj_type1) && !ob_is_null(obj_type1)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_ISCOLLECTION); + LOG_WARN("invalid type", K(ret), K(obj_type1)); + } else { + ObCastMode cast_mode = type_ctx.get_cast_mode(); + cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail + type_ctx.set_cast_mode(cast_mode); // cast mode only do work in new sql engine cast frame. + type.set_int(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + } + + return ret; +} + +int ObExprPrivSTIsCollection::eval_priv_st_iscollection( + const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_null_res = false; + ObDatum *datum1 = nullptr; + ObExpr *arg1 = expr.args_[0]; + ObObjType type1 = arg1->datum_meta_.type_; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + bool bres = true; + + if (ob_is_null(type1)) { + is_null_res = true; + } else if (OB_FAIL(arg1->eval(ctx, datum1))) { + LOG_WARN("fail to eval args", K(ret)); + } else if (datum1->is_null()) { + is_null_res = true; + } else { + ObString wkb = datum1->get_string(); + ObGeoType gtype = ObGeoType::GEOTYPEMAX; + ObGeometry *geo = nullptr; + + if (OB_FAIL(ObTextStringHelper::read_real_string_data( + temp_allocator, *datum1, arg1->datum_meta_, arg1->obj_meta_.has_lob_header(), wkb))) { + LOG_WARN("fail to read real string data", K(ret), K(arg1->obj_meta_.has_lob_header())); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, + wkb, + geo, + nullptr, + N_PRIV_ST_ISCOLLECTION, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { // ObIWkbGeom + LOG_WARN("fail to build geometry from wkb", K(ret), K(wkb)); + } else if ((geo->type() <= ObGeoType::GEOMETRY) || (geo->type() >= ObGeoType::GEOTYPEMAX)) { + ret = OB_ERR_INVALID_GEOMETRY_TYPE; + LOG_WARN("unknown geometry type", K(ret), K(geo->type())); + } else if (geo->type() <= ObGeoType::POLYGON) { + bres = false; + } + } + + if (OB_SUCC(ret)) { + if (is_null_res) { + res.set_null(); + } else { + res.set_bool(bres); + } + } + + return ret; +} + +int ObExprPrivSTIsCollection::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_iscollection; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_iscollection.h b/src/sql/engine/expr/ob_expr_priv_st_iscollection.h new file mode 100644 index 0000000000..a9d451f37b --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_iscollection.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_iscollection. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_ISCOLLECTION_ +#define OCEANBASE_SQL_OB_EXPR_ST_ISCOLLECTION_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace sql +{ +class ObExprPrivSTIsCollection : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTIsCollection(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTIsCollection(); + virtual int calc_result_type1( + ObExprResType &type, ObExprResType &type1, common::ObExprTypeCtx &type_ctx) const; + static int eval_priv_st_iscollection(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTIsCollection); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_ISCOLLECTION_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_makeenvelope.cpp b/src/sql/engine/expr/ob_expr_priv_st_makeenvelope.cpp new file mode 100644 index 0000000000..a23e60174f --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_makeenvelope.cpp @@ -0,0 +1,210 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_makeenvelope. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_priv_st_makeenvelope.h" +#include "sql/session/ob_sql_session_info.h" +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_utils.h" +#include "share/object/ob_obj_cast_util.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +ObExprPrivSTMakeEnvelope::ObExprPrivSTMakeEnvelope(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_MAKEENVELOPE, N_PRIV_ST_MAKEENVELOPE, MORE_THAN_TWO, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprPrivSTMakeEnvelope::~ObExprPrivSTMakeEnvelope() +{} + +int ObExprPrivSTMakeEnvelope::calc_result_typeN( + ObExprResType &type, ObExprResType *types_stack, int64_t param_num, ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + + if (param_num != 4 && param_num != 5) { + ret = OB_ERR_PARAM_SIZE; + LOG_WARN("invalid param number, should be four or five", K(ret), K(param_num)); + } else { + ObObjType cur_type = ObObjType::ObMaxType; + for (int i = 0; OB_SUCC(ret) && i < 4; ++i) { + cur_type = types_stack[i].get_type(); + if (!ob_is_numeric_type(cur_type) && !ob_is_string_type(cur_type) && !ob_is_null(cur_type)) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid input type x", K(ret), K(i), K(cur_type)); + } else if ((ob_is_numeric_type(cur_type) && !ob_is_double_type(cur_type) + && ObTinyIntType != cur_type)) { // pass string type and boolean type + types_stack[i].set_calc_type(ObDoubleType); + } + } + + if (OB_SUCC(ret) && param_num == 5) { + cur_type = types_stack[4].get_type(); + if (!ob_is_integer_type(cur_type) && !ob_is_string_type(cur_type) && !ob_is_null(cur_type)) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid input type srid", K(ret), K(cur_type)); + } else if (ob_is_string_type(cur_type)) { + types_stack[4].set_calc_type(ObIntType); + } + } + + if (OB_SUCC(ret)) { + ObCastMode cast_mode = type_ctx.get_cast_mode(); + cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail + cast_mode |= CM_STRING_INTEGER_TRUNC; // make cast check range when string to int + type_ctx.set_cast_mode(cast_mode); // cast mode only do work in new sql engine cast frame. + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); + } + } + + return ret; +} + +// ob_obj_cast.cpp string_double does not return error +// when empty string is converted to double in mysql mode +int ObExprPrivSTMakeEnvelope::string_to_double(const common::ObString &in_str, ObCollationType cs_type, double &res) +{ + int ret = OB_SUCCESS; + + if (in_str.empty()) { + ret = OB_ERR_DOUBLE_TRUNCATED; + LOG_WARN("input string is empty", K(ret), K(in_str)); + } else { + int err = 0; + char *endptr = NULL; + double out_val = ObCharset::strntodv2(in_str.ptr(), in_str.length(), &endptr, &err); + if (EOVERFLOW == err && (-DBL_MAX == out_val || DBL_MAX == out_val)) { + ret = OB_DATA_OUT_OF_RANGE; + LOG_WARN("value is out of range", K(ret), K(out_val)); + } else { + if (OB_FAIL(check_convert_str_err(in_str.ptr(), endptr, in_str.length(), err, cs_type))) { + LOG_WARN("fail to check convert str err", K(ret), K(in_str), K(out_val), K(err)); + ret = OB_ERR_DOUBLE_TRUNCATED; + } else { + res = out_val; + } + } + } + + return ret; +} + +int ObExprPrivSTMakeEnvelope::read_args(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, ObSEArray &coords, + ObGeoSrid &srid, bool &is_null_result, const ObSrsItem *&srs_item) +{ + int ret = OB_SUCCESS; + ObExpr *arg = nullptr; + ObObjType type = ObObjType::ObMaxType; + ObDatum *datum = nullptr; + double coord = 0.0; + + // read args + for (int i = 0; OB_SUCC(ret) && !is_null_result && i < 4; ++i) { + arg = expr.args_[i]; + type = arg->datum_meta_.type_; + if (arg->is_boolean_) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid type", K(ret), K(arg->is_boolean_)); + } else if (ob_is_null(type)) { + is_null_result = true; + } else if (OB_FAIL(arg->eval(ctx, datum))) { + LOG_WARN("fail to eval arg", K(ret), K(i), K(type)); + } else if (datum->is_null()) { + is_null_result = true; + } else if (!ob_is_string_type(type)) { + coord = type == ObTinyIntType ? datum->get_tinyint() : datum->get_double(); + } else if (OB_FAIL(string_to_double(datum->get_string(), arg->datum_meta_.cs_type_, coord))) { + LOG_WARN("fail to get x", K(ret), K(datum->get_string()), K(arg->datum_meta_.cs_type_)); + } + + if (OB_SUCC(ret) && !is_null_result) { + if (OB_FAIL(coords.push_back(coord))) { + LOG_WARN("failed to read point params", K(ret), K(i), K(coord)); + } + } + } + + bool is_geog = false; + if (expr.arg_cnt_ == 5 && !is_null_result && OB_SUCC(ret)) { + if (expr.args_[4]->is_boolean_) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid type", K(ret)); + } else if (OB_FAIL(expr.args_[4]->eval(ctx, datum))) { + LOG_WARN("fail to eval second argument", K(ret)); + } else if (datum->is_null()) { + is_null_result = true; + } else if (datum->get_int() < 0 || datum->get_int() > INT_MAX32) { + ret = OB_OPERATE_OVERFLOW; + LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "SRID", N_PRIV_ST_MAKEENVELOPE); + LOG_WARN("srid input value out of range", K(ret), K(srid)); + } else if (0 != (srid = datum->get_uint32())) { + if (OB_FAIL(OTSRS_MGR->get_tenant_srs_guard(srs_guard))) { + LOG_WARN("fail to get srs guard", K(ret)); + } else if (OB_FAIL(srs_guard.get_srs_item(srid, srs_item))) { + LOG_WARN("fail to get srs item", K(ret)); + } else if (OB_ISNULL(srs_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null srs item", K(ret)); + } + } + } + return ret; +} + +int ObExprPrivSTMakeEnvelope::eval_priv_st_makeenvelope(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObGeoSrid srid = 0; + ObSEArray coords; // rectangle point: xmin, ymin, xmax, ymax + bool is_null_result = false; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + ObWkbBuffer wkb_buf(tmp_allocator); + ObWkbBuffer res_wkb_buf(tmp_allocator); + ObGeometry *geo = NULL; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs_item = NULL; + // rectangle point -> polygon ewkb + if (OB_FAIL(read_args(srs_guard, expr, ctx, coords, srid, is_null_result, srs_item))) { + LOG_WARN("fail to read args", K(ret)); + } else if (is_null_result) { + res.set_null(); + } else { + if (OB_FAIL(ObGeoTypeUtil::rectangle_to_swkb(coords[0], coords[1], coords[2], coords[3], srid, true, res_wkb_buf))) { + LOG_WARN("fail to transform rectangle point to ewkb", K(ret), K(srid)); + } else if (OB_FAIL(ObGeoExprUtils::pack_geo_res(expr, ctx, res, res_wkb_buf.string()))) { + LOG_WARN("fail to pack geo res", K(ret)); + } + } + + return ret; +} + +int ObExprPrivSTMakeEnvelope::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_makeenvelope; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_makeenvelope.h b/src/sql/engine/expr/ob_expr_priv_st_makeenvelope.h new file mode 100644 index 0000000000..c1c0edff38 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_makeenvelope.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_makeenvelope. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_MAKEENVELOPE_ +#define OCEANBASE_SQL_OB_EXPR_ST_MAKEENVELOPE_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "observer/omt/ob_tenant_srs.h" + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace sql +{ +class ObExprPrivSTMakeEnvelope : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTMakeEnvelope(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTMakeEnvelope(); + virtual int calc_result_typeN(ObExprResType &type, ObExprResType *types, int64_t param_num, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_priv_st_makeenvelope(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int string_to_double(const common::ObString &in_str, ObCollationType cs_type, double &res); + static int read_args(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, ObSEArray &coords, + ObGeoSrid &srid, bool &is_null_result, const ObSrsItem *&srs_item); + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTMakeEnvelope); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_MAKEENVELOPE_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_makevalid.cpp b/src/sql/engine/expr/ob_expr_priv_st_makevalid.cpp new file mode 100644 index 0000000000..50a4ab18cd --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_makevalid.cpp @@ -0,0 +1,138 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_makevalid. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_priv_st_makevalid.h" +#include "sql/session/ob_sql_session_info.h" +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +ObExprPrivSTMakeValid::ObExprPrivSTMakeValid(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_MAKE_VALID, N_PRIV_ST_MAKEVALID, ZERO_OR_ONE, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprPrivSTMakeValid::~ObExprPrivSTMakeValid() +{} + +int ObExprPrivSTMakeValid::calc_result_typeN( + ObExprResType &type, ObExprResType *types_stack, int64_t param_num, ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + + if (param_num != 1) { + ret = OB_ERR_PARAM_SIZE; + LOG_WARN("invalid param number, should be four or five", K(ret), K(param_num)); + } else if (!ob_is_geometry(types_stack[0].get_type()) + && !ob_is_string_type(types_stack[0].get_type()) + && types_stack[0].get_type() != ObNullType) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid type", K(ret), K(types_stack[0].get_type())); + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_MAKEVALID); + } else { + ObCastMode cast_mode = type_ctx.get_cast_mode(); + cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); + } + + return ret; +} + +int ObExprPrivSTMakeValid::eval_priv_st_makevalid(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_null_result = false; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + ObDatum *gis_datum1 = nullptr; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs = nullptr; + ObGeometry *geo = NULL; + if (OB_FAIL(expr.args_[0]->eval(ctx, gis_datum1))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum1->is_null()) { + res.set_null(); + } else if (OB_FAIL(ObGeoExprUtils::get_input_geometry(tmp_allocator, gis_datum1, ctx, + expr.args_[0], srs_guard, N_PRIV_ST_MAKEVALID, srs, geo))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (geo->crs() != ObGeoCRS::Cartesian) { + ret = OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS; + LOG_USER_ERROR(OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS, N_PRIV_ST_MAKEVALID, + ObGeoTypeUtil::get_geo_name_by_type(geo->type())); + } else { + bool isvalid_res = false; + int correct_result; + ObGeoNormalVal reason; + ObGeoEvalCtx gis_context(&tmp_allocator, srs); + if (OB_FAIL(gis_context.append_geo_arg(geo))) { + LOG_WARN("build geo gis context failed", K(ret)); + } else if (OB_FAIL(gis_context.append_val_arg(reason))) { + LOG_WARN("add reason val to context failed", K(ret)); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, isvalid_res))) { + LOG_WARN("eval geo func isvalid failed", K(ret)); + } else if (!isvalid_res) { + if (geo->type() == ObGeoType::POLYGON || geo->type() == ObGeoType::MULTIPOLYGON) { + ObGeoToTreeVisitor to_tree(&tmp_allocator); + ObGeometry *valid_geo = nullptr; + if (OB_FAIL(geo->do_visit(to_tree))) { + LOG_WARN("fail to transfer geo1 to tree", K(ret)); + } else { + if (OB_FAIL(ObGeoExprUtils::make_valid_polygon(to_tree.get_geometry(), tmp_allocator, valid_geo))) { + LOG_WARN("make polygon valid failed", K(ret)); + } else if (OB_NOT_NULL(valid_geo) && !valid_geo->is_empty()) { + geo = valid_geo; + } + } + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, correct_result))) { + LOG_WARN("eval boost correct failed", K(ret)); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, isvalid_res))) { + LOG_WARN("eval geo func isvalid failed", K(ret)); + } else if (!isvalid_res) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid result geo", K(ret), K(reason.int64_)); + } + } + if (OB_SUCC(ret)) { + ObString res_wkb; + if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*geo, expr, ctx, srs, res_wkb))){ + LOG_WARN("failed to write geometry to wkb", K(ret)); + } else { + res.set_string(res_wkb); + } + } + } + + return ret; +} + +int ObExprPrivSTMakeValid::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_makevalid; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_makevalid.h b/src/sql/engine/expr/ob_expr_priv_st_makevalid.h new file mode 100644 index 0000000000..64a98974fd --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_makevalid.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_makevalid. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_MAKEVALID_ +#define OCEANBASE_SQL_OB_EXPR_ST_MAKEVALID_ + +#include "sql/engine/expr/ob_expr_operator.h" + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace sql +{ +class ObExprPrivSTMakeValid : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTMakeValid(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTMakeValid(); + virtual int calc_result_typeN(ObExprResType &type, ObExprResType *types, int64_t param_num, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_priv_st_makevalid(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTMakeValid); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_MAKEVALID_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_numinteriorrings.cpp b/src/sql/engine/expr/ob_expr_priv_st_numinteriorrings.cpp new file mode 100644 index 0000000000..a2d68613a7 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_numinteriorrings.cpp @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_numinteriorrings. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_priv_st_numinteriorrings.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "share/object/ob_obj_cast_util.h" +#include "lib/geo/ob_geo_utils.h" +#include "observer/omt/ob_tenant_srs.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +ObExprPrivSTNumInteriorRings::ObExprPrivSTNumInteriorRings(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_NUMINTERIORRINGS, N_PRIV_ST_NUMINTERIORRINGS, 1, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprPrivSTNumInteriorRings::~ObExprPrivSTNumInteriorRings() +{} + +int ObExprPrivSTNumInteriorRings::calc_result_type1( + ObExprResType &type, ObExprResType &type1, common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObObjType obj_type1 = type1.get_type(); + + if (!ob_is_string_type(obj_type1) && !ob_is_geometry(obj_type1) && !ob_is_null(obj_type1)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_NUMINTERIORRINGS); + LOG_WARN("invalid type", K(ret), K(obj_type1)); + } else { + ObCastMode cast_mode = type_ctx.get_cast_mode(); + cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail + type_ctx.set_cast_mode(cast_mode); // cast mode only do work in new sql engine cast frame. + type.set_int32(); + } + + return ret; +} + +int ObExprPrivSTNumInteriorRings::eval_priv_st_numinteriorrings( + const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_null_res = false; + ObDatum *datum1 = nullptr; + ObExpr *arg1 = expr.args_[0]; + ObObjType type1 = arg1->datum_meta_.type_; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + uint32_t res_num = 0; + + if (ob_is_null(type1)) { + is_null_res = true; + } else if (OB_FAIL(arg1->eval(ctx, datum1))) { + LOG_WARN("fail to eval args", K(ret)); + } else if (datum1->is_null()) { + is_null_res = true; + } else { + ObString wkb = datum1->get_string(); + ObGeoType gtype = ObGeoType::GEOTYPEMAX; + ObGeometry *geo = nullptr; + + if (OB_FAIL(ObTextStringHelper::read_real_string_data( + temp_allocator, *datum1, arg1->datum_meta_, arg1->obj_meta_.has_lob_header(), wkb))) { + LOG_WARN("fail to read real string data", K(ret), K(arg1->obj_meta_.has_lob_header())); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, + wkb, + geo, + nullptr, + N_PRIV_ST_NUMINTERIORRINGS, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { // ObIWkbGeom + LOG_WARN("fail to build geometry from wkb", K(ret), K(wkb)); + } else if (geo->type() != ObGeoType::POLYGON) { + is_null_res = true; + } else { + const ObWkbGeomPolygon *poly = reinterpret_cast(geo->val()); + if ((res_num = poly->size()) > 0) { + --res_num; + } + } + } + + if (OB_SUCC(ret)) { + if (is_null_res) { + res.set_null(); + } else { + res.set_int32(res_num); + } + } + + return ret; +} + +int ObExprPrivSTNumInteriorRings::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_numinteriorrings; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_numinteriorrings.h b/src/sql/engine/expr/ob_expr_priv_st_numinteriorrings.h new file mode 100644 index 0000000000..431089455f --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_numinteriorrings.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_numinteriorrings. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_NUMINTERIORRINGS_ +#define OCEANBASE_SQL_OB_EXPR_ST_NUMINTERIORRINGS_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace sql +{ +class ObExprPrivSTNumInteriorRings : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTNumInteriorRings(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTNumInteriorRings(); + virtual int calc_result_type1( + ObExprResType &type, ObExprResType &type1, common::ObExprTypeCtx &type_ctx) const; + static int eval_priv_st_numinteriorrings(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTNumInteriorRings); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_NUMINTERIORRINGS_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_point.cpp b/src/sql/engine/expr/ob_expr_priv_st_point.cpp index 88b3aa45b0..8f2ff9419e 100644 --- a/src/sql/engine/expr/ob_expr_priv_st_point.cpp +++ b/src/sql/engine/expr/ob_expr_priv_st_point.cpp @@ -93,9 +93,7 @@ int ObExprPrivSTPoint::calc_result_typeN(ObExprResType& type, cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail cast_mode |= CM_STRING_INTEGER_TRUNC; // make cast check range when string to int type_ctx.set_cast_mode(cast_mode); // cast mode only do work in new sql engine cast frame. - type.set_type(ObGeometryType); - type.set_collation_level(common::CS_LEVEL_COERCIBLE); - type.set_collation_type(CS_TYPE_BINARY); + type.set_geometry(); type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); } } diff --git a/src/sql/engine/expr/ob_expr_priv_st_pointonsurface.cpp b/src/sql/engine/expr/ob_expr_priv_st_pointonsurface.cpp new file mode 100644 index 0000000000..42ead9d45d --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_pointonsurface.cpp @@ -0,0 +1,145 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_pointonsurface. + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_priv_st_pointonsurface.h" +#include "sql/session/ob_sql_session_info.h" +#include "observer/omt/ob_tenant_srs.h" +#include "lib/geo/ob_geo_func_register.h" +#include "share/object/ob_obj_cast_util.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "lib/geo/ob_geo_interior_point_visitor.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +ObExprPrivSTPointOnSurface::ObExprPrivSTPointOnSurface(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_POINTONSURFACE, N_PRIV_ST_POINTONSURFACE, 1, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprPrivSTPointOnSurface::~ObExprPrivSTPointOnSurface() +{} + +int ObExprPrivSTPointOnSurface::calc_result_type1( + ObExprResType &type, ObExprResType &type1, common::ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + ObObjType obj_type1 = type1.get_type(); + + if (!ob_is_string_type(obj_type1) && !ob_is_geometry(obj_type1) && !ob_is_null(obj_type1)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_POINTONSURFACE); + LOG_WARN("invalid type", K(ret), K(obj_type1)); + } else { + ObCastMode cast_mode = type_ctx.get_cast_mode(); + cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail + type_ctx.set_cast_mode(cast_mode); // cast mode only do work in new sql engine cast frame. + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); + } + + return ret; +} + +int ObExprPrivSTPointOnSurface::process_input_geometry( + const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, bool &is_null_res, ObGeometry *&geo1) +{ + int ret = OB_SUCCESS; + ObDatum *datum1 = nullptr; + ObExpr *arg1 = expr.args_[0]; + ObObjType type1 = arg1->datum_meta_.type_; + + if (ob_is_null(type1)) { + is_null_res = true; + } else if (OB_FAIL(arg1->eval(ctx, datum1))) { + LOG_WARN("fail to eval args", K(ret)); + } else if (datum1->is_null()) { + is_null_res = true; + } else { + ObString wkb1 = datum1->get_string(); + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs1 = nullptr; + + if (OB_FAIL(ObTextStringHelper::read_real_string_data( + allocator, *datum1, arg1->datum_meta_, arg1->obj_meta_.has_lob_header(), wkb1))) { + LOG_WARN("fail to read real string data", K(ret), K(arg1->obj_meta_.has_lob_header()), K(wkb1)); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb1, srs1, true, N_PRIV_ST_POINTONSURFACE))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb1)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry( + allocator, wkb1, geo1, nullptr, N_PRIV_ST_POINTONSURFACE))) { // ObIWkbGeom + LOG_WARN("fail to build geometry from wkb", K(ret), K(wkb1)); + } else if (OB_NOT_NULL(srs1) && srs1->is_geographical_srs()) { + ret = OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS; + LOG_USER_ERROR(OB_ERR_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS, N_PRIV_ST_ASMVTGEOM, + ObGeoTypeUtil::get_geo_name_by_type(geo1->type())); + LOG_WARN("Geometry in geographical srs can not be input", K(ret), K(srs1)); + } + } + + return ret; +} + +int ObExprPrivSTPointOnSurface::eval_priv_st_pointonsurface(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_null_res = false; + ObGeometry *geo1 = nullptr; + ObGeometry *res_geo = NULL; + ObGeometry *interior_point = nullptr; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObString res_wkb; + + if (OB_FAIL(process_input_geometry(expr, ctx, temp_allocator, is_null_res, geo1))) { + LOG_WARN("fail to process input geometry", K(ret), K(geo1), K(is_null_res)); + } else if (is_null_res) { + // do nothing + } else { + ObGeoInteriorPointVisitor inter_point_visitor(&temp_allocator); + if (OB_FAIL(geo1->do_visit(inter_point_visitor))) { + LOG_WARN("fail to do interior point visitor", K(ret)); + } else if (OB_FAIL(inter_point_visitor.get_interior_point(interior_point))) { + LOG_WARN("fail to get interior point", K(ret)); + } + } + + if (OB_SUCC(ret)) { + if (is_null_res) { + res.set_null(); + } else { + if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*interior_point, expr, ctx, nullptr, res_wkb, geo1->get_srid()))) { + LOG_WARN("fail to get wkb from geometry", K(ret)); + } else { + res.set_string(res_wkb); + } + } + } + + return ret; +} + +int ObExprPrivSTPointOnSurface::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_pointonsurface; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_pointonsurface.h b/src/sql/engine/expr/ob_expr_priv_st_pointonsurface.h new file mode 100644 index 0000000000..919cbcb83a --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_pointonsurface.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_pointonsurface. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_POINTONSURFACE_ +#define OCEANBASE_SQL_OB_EXPR_ST_POINTONSURFACE_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace sql +{ +class ObExprPrivSTPointOnSurface : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTPointOnSurface(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTPointOnSurface(); + virtual int calc_result_type1(ObExprResType &type, ObExprResType &type1, common::ObExprTypeCtx &type_ctx) const; + static int eval_priv_st_pointonsurface(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int process_input_geometry( + const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, bool &is_null_res, ObGeometry *&geo1); + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTPointOnSurface); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_POINTONSURFACE_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_setsrid.cpp b/src/sql/engine/expr/ob_expr_priv_st_setsrid.cpp index 0ddd97cff3..4edf1fe6a5 100644 --- a/src/sql/engine/expr/ob_expr_priv_st_setsrid.cpp +++ b/src/sql/engine/expr/ob_expr_priv_st_setsrid.cpp @@ -72,9 +72,7 @@ int ObExprPrivSTSetSRID::calc_result_type2(ObExprResType &type, cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail cast_mode |= CM_STRING_INTEGER_TRUNC; // make cast check range when string to int type_ctx.set_cast_mode(cast_mode); // cast mode only do work in new sql engine cast frame. - type.set_type(ObGeometryType); - type.set_collation_level(common::CS_LEVEL_COERCIBLE); - type.set_collation_type(CS_TYPE_BINARY); + type.set_geometry(); type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); } diff --git a/src/sql/engine/expr/ob_expr_priv_st_touches.cpp b/src/sql/engine/expr/ob_expr_priv_st_touches.cpp new file mode 100644 index 0000000000..255045c2dc --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_touches.cpp @@ -0,0 +1,181 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_priv_st_touches. + */ + +#define USING_LOG_PREFIX SQL_ENG + +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_ibin.h" +#include "sql/engine/ob_exec_context.h" +#include "ob_expr_priv_st_touches.h" +#include "lib/geo/ob_geo_utils.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ + +ObExprPrivSTTouches::ObExprPrivSTTouches(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_ST_TOUCHES, N_PRIV_ST_TOUCHES, 2, + VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprPrivSTTouches::~ObExprPrivSTTouches() +{} + +int ObExprPrivSTTouches::calc_result_type2(ObExprResType &type, ObExprResType &type1, + ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + INIT_SUCC(ret); + int unexpected_types = 0; + int null_types = 0; + + if (type1.get_type() == ObNullType) { + null_types++; + } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { + unexpected_types++; + LOG_WARN("invalid type", K(type1.get_type())); + } + if (type2.get_type() == ObNullType) { + null_types++; + } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { + unexpected_types++; + LOG_WARN("invalid type", K(type2.get_type())); + } + // an invalid type and a nullptr type will return nullptr + // an invalid type and a valid type return error + if (null_types == 0 && unexpected_types > 0) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_TOUCHES); + LOG_WARN("invalid type", K(ret)); + } + if (OB_SUCC(ret)) { + type.set_int(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + } + return ret; +} + +int ObExprPrivSTTouches::get_input_geometry(omt::ObSrsCacheGuard &srs_guard, ObDatum *gis_datum, ObEvalCtx &ctx, ObExpr *gis_arg, + bool &is_null_geo, const ObSrsItem *&srs, ObGeometry *&geo, bool &is_geo_empty) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard ctx_alloc_g(ctx); + common::ObArenaAllocator &allocator = ctx_alloc_g.get_allocator(); + if (OB_FAIL(gis_arg->eval(ctx, gis_datum))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum->is_null()) { + is_null_geo = true; + } else { + ObString wkb = gis_datum->get_string(); + ObGeoType type = ObGeoType::GEOTYPEMAX; + uint32_t srid = -1; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum, + gis_arg->datum_meta_, + gis_arg->obj_meta_.has_lob_header(), + wkb))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb, type, srid))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_TOUCHES); + } + LOG_WARN("get type and srid from wkb failed", K(wkb), K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb, srs, true, N_PRIV_ST_TOUCHES))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(allocator, + wkb, + geo, + srs, + N_PRIV_ST_TOUCHES, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { + LOG_WARN("get first geo by wkb failed", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo, is_geo_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } + } + return ret; +} + +int ObExprPrivSTTouches::eval_priv_st_touches(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObExpr *gis_arg1 = expr.args_[0]; + ObExpr *gis_arg2 = expr.args_[1]; + bool is_geo1_empty = false; + bool is_geo2_empty = false; + bool is_geo1_null = false; + bool is_geo2_null = false; + ObGeometry *geo1 = nullptr; + ObGeometry *geo2 = nullptr; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs1 = nullptr; + const ObSrsItem *srs2 = nullptr; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObDatum *gis_datum1 = nullptr; + ObDatum *gis_datum2 = nullptr; + if (OB_FAIL(gis_arg1->eval(ctx, gis_datum1)) || OB_FAIL(gis_arg2->eval(ctx, gis_datum2))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum1->is_null() || gis_datum2->is_null()) { + res.set_null(); + } else if (OB_FAIL(get_input_geometry( + srs_guard, gis_datum1, ctx, gis_arg1, is_geo1_null, srs1, geo1, is_geo1_empty))) { + LOG_WARN("fail to get input geometry", K(ret)); + } else if (OB_FAIL(get_input_geometry( + srs_guard, gis_datum2, ctx, gis_arg2, is_geo2_null, srs2, geo2, is_geo2_empty))) { + LOG_WARN("fail to get input geometry", K(ret)); + } else { + uint32_t srid1 = srs1 == nullptr ? 0 : srs1->get_srid(); + uint32_t srid2 = srs2 == nullptr ? 0 : srs2->get_srid(); + if (srid1 != srid2) { + ret = OB_ERR_GIS_DIFFERENT_SRIDS; + LOG_WARN("srid not the same", K(ret), K(srid1), K(srid2)); + LOG_USER_ERROR(OB_ERR_GIS_DIFFERENT_SRIDS, N_PRIV_ST_TOUCHES, srid1, srid2); + } else if (is_geo1_empty || is_geo2_empty) { + res.set_bool(false); + } else if (OB_FAIL(ObGeoExprUtils::zoom_in_geos_for_relation(*geo1, *geo2))) { + LOG_WARN("zoom in geos failed", K(ret)); + } else { + bool result = false; + ObGeoEvalCtx gis_context(&temp_allocator, srs1); + if (OB_FAIL(gis_context.append_geo_arg(geo1)) || OB_FAIL(gis_context.append_geo_arg(geo2))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, result))) { + LOG_WARN("eval st intersection failed", K(ret)); + ObGeoExprUtils::geo_func_error_handle(ret, N_PRIV_ST_TOUCHES); + } else { + res.set_bool(result); + } + } + } + return ret; +} + +int ObExprPrivSTTouches::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_priv_st_touches; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_priv_st_touches.h b/src/sql/engine/expr/ob_expr_priv_st_touches.h new file mode 100644 index 0000000000..55e494525d --- /dev/null +++ b/src/sql/engine/expr/ob_expr_priv_st_touches.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_priv_st_touches. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_PRIV_ST_TOUCHES_H_ +#define OCEANBASE_SQL_OB_EXPR_PRIV_ST_TOUCHES_H_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "observer/omt/ob_tenant_srs.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprPrivSTTouches : public ObFuncExprOperator +{ +public: + explicit ObExprPrivSTTouches(common::ObIAllocator &alloc); + virtual ~ObExprPrivSTTouches(); + virtual int calc_result_type2(ObExprResType &type, ObExprResType &type1, ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_priv_st_touches(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int get_input_geometry(omt::ObSrsCacheGuard &srs_guard, ObDatum *gis_datum, ObEvalCtx &ctx, ObExpr *gis_arg, + bool &is_null_geo, const ObSrsItem *&srs, ObGeometry *&geo, bool &is_geo_empty); + DISALLOW_COPY_AND_ASSIGN(ObExprPrivSTTouches); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_PRIV_ST_TOUCHES_H_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_priv_st_transform.cpp b/src/sql/engine/expr/ob_expr_priv_st_transform.cpp index 7f38466268..656662f179 100644 --- a/src/sql/engine/expr/ob_expr_priv_st_transform.cpp +++ b/src/sql/engine/expr/ob_expr_priv_st_transform.cpp @@ -67,9 +67,7 @@ int ObExprPrivSTTransform::calc_result_typeN(ObExprResType& type, if (OB_SUCC(ret)) { ObCastMode cast_mode = type_ctx.get_cast_mode(); cast_mode &= ~CM_WARN_ON_FAIL; // make cast return error when fail - type.set_type(ObGeometryType); - type.set_collation_level(common::CS_LEVEL_COERCIBLE); - type.set_collation_type(CS_TYPE_BINARY); + type.set_geometry(); type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); } } @@ -119,7 +117,8 @@ int ObExprPrivSTTransform::eval_priv_st_transform(const ObExpr &expr, ObEvalCtx LOG_WARN("get tenant srs guard failed", K(session->get_effective_tenant_id()), K(src_srid), K(ret)); } else if (src_srid != 0 && OB_FAIL(srs_guard.get_srs_item(src_srid, src_srs_item))) { LOG_WARN("failed to get srs item", K(ret), K(src_srid)); - } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_wkb(temp_allocator, wkb, src_srs_item, src_geo))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb, src_geo, src_srs_item, N_PRIV_ST_TRANSFORM, + ObGeoBuildFlag::GEO_ALLOW_3D))) { LOG_WARN("get geo by wkb failed", K(ret), K(wkb)); if (ret != OB_ERR_SRS_NOT_FOUND) { ret = OB_ERR_GIS_INVALID_DATA; diff --git a/src/sql/engine/expr/ob_expr_relational_cmp_type.map b/src/sql/engine/expr/ob_expr_relational_cmp_type.map index 47e9b71978..aa84d1d645 100644 --- a/src/sql/engine/expr/ob_expr_relational_cmp_type.map +++ b/src/sql/engine/expr/ob_expr_relational_cmp_type.map @@ -71,6 +71,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObHexStringType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*TinyIntType*/ @@ -126,6 +127,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*SmallIntType*/ @@ -181,6 +183,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*MediumIntType*/ @@ -236,6 +239,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*Int32Type*/ @@ -290,7 +294,8 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*IntType*/ @@ -345,7 +350,8 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, // for all uint cmp int, we must set cmp type to unsigned, @@ -402,7 +408,8 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*USmallIntType*/ @@ -457,7 +464,8 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UMediumIntType*/ @@ -512,7 +520,8 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UInt32Type*/ @@ -567,7 +576,8 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UInt64Type*/ @@ -622,7 +632,8 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*FloatType*/ @@ -678,6 +689,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*DoubleType*/ @@ -733,6 +745,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UFloatType*/ @@ -788,6 +801,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UDoubleType*/ @@ -843,6 +857,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*NumberType*/ @@ -898,6 +913,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObNumberType, /* ObGeometryType */ ObMaxType, /* UDT */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UNumberType*/ @@ -953,6 +969,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObNumberType, /* ObGeometryType */ ObMaxType, /* UDT */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*DateTimeType*/ @@ -1008,6 +1025,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDateTimeType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*TimestampType*/ @@ -1063,6 +1081,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimestampType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*DateType*/ @@ -1118,6 +1137,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDateType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*TimeType*/ @@ -1173,6 +1193,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObHexStringType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimeType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*YearType*/ @@ -1228,6 +1249,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*VarcharType*/ @@ -1281,8 +1303,9 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObNullType, /* ObLobType */ ObJsonType, /* ObJsonType */ ObHexStringType, /* ObGeometryType */ - ObNullType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* UDT */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*CharType*/ @@ -1336,8 +1359,9 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObNullType, /* ObLobType */ ObJsonType, /* ObJsonType */ ObHexStringType, /* ObGeometryType */ - ObNullType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* UDT */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*HexStringType*/ @@ -1392,7 +1416,8 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObHexStringType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ExtendType*/ @@ -1448,6 +1473,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UnknownType*/ @@ -1503,6 +1529,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*TinyTextType*/ { @@ -1557,6 +1584,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*TextType*/ { @@ -1611,6 +1639,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*MediumTextType*/ { @@ -1665,6 +1694,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*LongTextType*/ { @@ -1718,7 +1748,8 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*BitType*/ { @@ -1773,6 +1804,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*EnumType*/ @@ -1828,6 +1860,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*SetType*/ { @@ -1882,6 +1915,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*EnumInnerType*/ { @@ -1936,6 +1970,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*SetInnerType*/ { @@ -1990,6 +2025,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObTimestampTZType*/ { @@ -2044,6 +2080,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimestampTZType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObTimestampLTZType*/ { @@ -2098,6 +2135,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimestampLTZType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObTimestampNanoType*/ { @@ -2152,6 +2190,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimestampNanoType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObRawType*/ { @@ -2206,6 +2245,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObRawType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObIntervalYMType*/ { @@ -2260,6 +2300,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObIntervalYMType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObIntervalDSType*/ { @@ -2314,6 +2355,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObIntervalDSType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*NumberFloatType*/ @@ -2369,6 +2411,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* UDT */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObNVarchar2Type*/ { @@ -2421,8 +2464,9 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObNullType, /* ObLobType */ ObMaxType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ - ObNullType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* UDT */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*CharType*/ @@ -2476,8 +2520,9 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObNullType, /* ObLobType */ ObMaxType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ - ObNullType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* UDT */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObURowIDType*/ { @@ -2532,6 +2577,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObLobType*/ { @@ -2586,6 +2632,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObJsonType*/ { @@ -2640,6 +2687,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObGeometryType*/ ObMaxType, /* UDT */ ObJsonType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObGeometryType*/ { @@ -2693,9 +2741,10 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObHexStringType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType, /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, - /*User Defined Sql Type*/ + /*User Defined Sql Type*/ { ObMaxType, /* NullType */ ObMaxType, /* TinyIntType */ @@ -2748,6 +2797,7 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObDecimalIntType*/ { @@ -2802,6 +2852,62 @@ static constexpr ObObjType RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObGeometryType*/ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ + }, + /*ObCollectionSQLType*/ + { + ObMaxType, /* NullType */ + ObMaxType, /* TinyIntType */ + ObMaxType, /* SmallIntType */ + ObMaxType, /* MediumIntType */ + ObMaxType, /* Int32Type */ + ObMaxType, /* IntType */ + ObMaxType, /* UTinyIntType */ + ObMaxType, /* USmallIntType */ + ObMaxType, /* UMediumIntType */ + ObMaxType, /* UInt32Type */ + ObMaxType, /* UIntType */ + ObMaxType, /* FloatType */ + ObMaxType, /* DoubleType */ + ObMaxType, /* UFloatType */ + ObMaxType, /* UDoubleType */ + ObMaxType, /* NumberType */ + ObMaxType, /* UNumberType */ + ObMaxType, /* DateTimeType */ + ObMaxType, /* TimestampType */ + ObMaxType, /* DateType */ + ObMaxType, /* TimeType */ + ObMaxType, /* YearType */ + ObMaxType, /* VarcharType */ + ObMaxType, /* CharType */ + ObMaxType, /* HexStringType */ + ObMaxType, /* ExtendType */ + ObMaxType, /* UnknownType */ + ObMaxType, /*TinyTextType*/ + ObMaxType, /*TextType*/ + ObMaxType, /*MediumTextType*/ + ObMaxType, /*LongTextType*/ + ObMaxType, /*BitType*/ + ObMaxType, /* EnumType */ + ObMaxType, /* SetType */ + ObMaxType, /* EnumInnerType */ + ObMaxType, /* SetInnerType */ + ObMaxType, /* ObTimestampTZType */ + ObMaxType, /* ObTimestampLTZType */ + ObMaxType, /* ObTimestampNanoType */ + ObMaxType, /* ObRawType */ + ObMaxType, /* ObIntervalYMType */ + ObMaxType, /* ObIntervalDSType */ + ObMaxType, /* ObNumberFloatType */ + ObNullType, /* ObNVarchar2Type */ + ObNullType, /* ObNCharType */ + ObMaxType, /* ObURowIDType */ + ObMaxType, /* ObLobType */ + ObMaxType, /* ObJsonType */ + ObMaxType, /* ObGeometryType */ + ObMaxType, /* UDT */ + ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, }; @@ -2862,6 +2968,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalintType */ + ObMaxType, /* UDT */ }, /*TinyIntType*/ @@ -2917,6 +3024,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*SmallIntType*/ @@ -2972,6 +3080,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*MediumIntType*/ @@ -3027,6 +3136,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*Int32Type*/ @@ -3082,6 +3192,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*IntType*/ @@ -3137,6 +3248,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, // for all uint cmp int, we must set cmp type to unsigned, @@ -3194,6 +3306,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*USmallIntType*/ @@ -3249,6 +3362,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UMediumIntType*/ @@ -3304,6 +3418,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UInt32Type*/ @@ -3359,6 +3474,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UInt64Type*/ @@ -3414,6 +3530,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*FloatType*/ @@ -3469,6 +3586,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObFloatType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*DoubleType*/ @@ -3524,6 +3642,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UFloatType*/ @@ -3579,6 +3698,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObFloatType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UDoubleType*/ @@ -3634,6 +3754,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*NumberType*/ @@ -3689,6 +3810,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UNumberType*/ @@ -3744,6 +3866,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*DateTimeType*/ @@ -3799,6 +3922,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDateTimeType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*TimestampType*/ @@ -3854,6 +3978,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimestampType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*DateType*/ @@ -3909,6 +4034,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDateTimeType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*TimeType*/ @@ -3964,6 +4090,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimeType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*YearType*/ @@ -4019,6 +4146,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*VarcharType*/ @@ -4074,6 +4202,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObNullType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*CharType*/ @@ -4129,6 +4258,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObNullType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*HexStringType*/ @@ -4184,6 +4314,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ExtendType*/ @@ -4239,6 +4370,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*UnknownType*/ @@ -4294,6 +4426,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObIntType, /* ObGeometryType */ ObMaxType, /* UDT */ ObIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*TinyTextType*/ { @@ -4348,6 +4481,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*TextType*/ { @@ -4402,6 +4536,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*MediumTextType*/ { @@ -4456,6 +4591,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*LongTextType*/ { @@ -4510,6 +4646,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*BitType*/ { @@ -4564,6 +4701,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*EnumType*/ @@ -4619,6 +4757,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*SetType*/ { @@ -4673,6 +4812,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*EnumInnerType*/ { @@ -4727,6 +4867,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*SetInnerType*/ { @@ -4781,6 +4922,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObTimestampTZType*/ { @@ -4835,6 +4977,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimestampTZType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObTimestampLTZType*/ { @@ -4889,6 +5032,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimestampLTZType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObTimestampNanoType*/ { @@ -4943,6 +5087,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObTimestampNanoType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObRawType*/ { @@ -4997,6 +5142,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObRawType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObIntervalYMType*/ { @@ -5051,6 +5197,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObIntervalYMType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObIntervalDSType*/ { @@ -5105,6 +5252,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObIntervalDSType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*NumberFloatType*/ @@ -5160,6 +5308,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*ObNVarchar2Type*/ { @@ -5214,6 +5363,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObNullType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /*NCharType*/ @@ -5269,6 +5419,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObNullType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /* ObURowIDType */ @@ -5324,6 +5475,7 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObGeometryType, /* ObGeometryType */ ObMaxType, /* UDT */ ObURowIDType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /* ObLobType */ { @@ -5377,7 +5529,8 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObDecimalIntType /* ObDecimalIntType */ + ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /* ObJsonType */ { @@ -5431,7 +5584,8 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObJsonType /* ObDecimalIntType */ + ObJsonType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /* ObGeometryType */ { @@ -5485,7 +5639,8 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ - ObMaxType /* ObDecimalIntType */ + ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /* UDT */ { @@ -5539,7 +5694,8 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ ObNullType, /* UDT */ - ObMaxType /* ObDecimalIntType */ + ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ }, /* ObDecimalIntType */ { @@ -5594,6 +5750,62 @@ static constexpr ObObjType ORACLE_RELATIONAL_CMP_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* COLLECTION */ + }, + /* COLLECTION */ + { + ObMaxType, /* NullType */ + ObMaxType, /* TinyIntType */ + ObMaxType, /* SmallIntType */ + ObMaxType, /* MediumIntType */ + ObMaxType, /* Int32Type */ + ObMaxType, /* IntType */ + ObMaxType, /* UTinyIntType */ + ObMaxType, /* USmallIntType */ + ObMaxType, /* UMediumIntType */ + ObMaxType, /* UInt32Type */ + ObMaxType, /* UIntType */ + ObMaxType, /* FloatType */ + ObMaxType, /* DoubleType */ + ObMaxType, /* UFloatType */ + ObMaxType, /* UDoubleType */ + ObMaxType, /* NumberType */ + ObMaxType, /* UNumberType */ + ObMaxType, /* DateTimeType */ + ObMaxType, /* TimestampType */ + ObMaxType, /* DateType */ + ObMaxType, /* TimeType */ + ObMaxType, /* YearType */ + ObNullType, /* VarcharType */ + ObNullType, /* CharType */ + ObMaxType, /* HexStringType */ + ObMaxType, /* ExtendType */ + ObMaxType, /* UnknownType */ + ObMaxType, /*TinyTextType*/ + ObMaxType, /*TextType*/ + ObMaxType, /*MediumTextType*/ + ObMaxType, /*LongTextType*/ + ObMaxType, /*BitType*/ + ObMaxType, /* EnumType */ + ObMaxType, /* SetType */ + ObMaxType, /* EnumInnerType */ + ObMaxType, /* SetInnerType */ + ObMaxType, /* ObTimestampTZType */ + ObMaxType, /* ObTimestampLTZType */ + ObMaxType, /* ObTimestampNanoType */ + ObMaxType, /* ObRawType */ + ObMaxType, /* ObIntervalYMType */ + ObMaxType, /* ObIntervalDSType */ + ObMaxType, /* ObNumberFloatType */ + ObNullType, /* ObNVarchar2Type */ + ObNullType, /* ObNCharType */ + ObMaxType, /* ObURowIDType */ + ObMaxType, /* ObLobType */ + ObMaxType, /* ObJsonType */ + ObMaxType, /* ObGeometryType */ + ObNullType, /* UDT */ + ObMaxType, /* ObDecimalintType */ + ObMaxType, /* COLLECTION */ }, }; diff --git a/src/sql/engine/expr/ob_expr_relational_equal_type.map b/src/sql/engine/expr/ob_expr_relational_equal_type.map index d4ed0c2e2f..ff0908b11d 100644 --- a/src/sql/engine/expr/ob_expr_relational_equal_type.map +++ b/src/sql/engine/expr/ob_expr_relational_equal_type.map @@ -53,6 +53,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TinyIntType*/ @@ -108,6 +109,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*SmallIntType*/ @@ -163,6 +165,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*MediumIntType*/ @@ -218,6 +221,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*Int32Type*/ @@ -273,6 +277,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*IntType*/ @@ -328,6 +333,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UTinyIntType*/ { @@ -382,6 +388,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*USmallIntType*/ @@ -437,6 +444,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UMediumIntType*/ @@ -492,6 +500,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UInt32Type*/ @@ -547,6 +556,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UInt64Type*/ @@ -602,6 +612,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*FloatType*/ @@ -657,6 +668,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DoubleType*/ @@ -712,6 +724,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UFloatType*/ @@ -767,6 +780,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UDoubleType*/ @@ -822,6 +836,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*NumberType*/ @@ -877,6 +892,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObNumberType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UNumberType*/ @@ -932,6 +948,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObNumberType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DateTimeType*/ @@ -987,6 +1004,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDateTimeType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TimestampType*/ @@ -1042,6 +1060,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObTimestampType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DateType*/ @@ -1097,6 +1116,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDateType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TimeType*/ @@ -1152,6 +1172,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObHexStringType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObTimeType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*YearType*/ @@ -1207,6 +1228,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType*/ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*VarcharType*/ @@ -1262,6 +1284,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObHexStringType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*CharType*/ @@ -1317,6 +1340,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObHexStringType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*HexStringType*/ @@ -1372,6 +1396,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObHexStringType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ExtendType*/ @@ -1427,6 +1452,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*UnknownType*/ @@ -1480,8 +1506,9 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObLobType */ ObMaxType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ - ObMaxType, /* ObUserDefinedSQLType */ + ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TinyTextType*/ { @@ -1536,6 +1563,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*TextType*/ { @@ -1590,6 +1618,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*MediumTextType*/ { @@ -1644,6 +1673,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*LongTextType*/ { @@ -1698,6 +1728,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*BitType*/ { @@ -1752,6 +1783,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*EnumType*/ { @@ -1806,6 +1838,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*SetType*/ { @@ -1860,6 +1893,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*EnumInnerType*/ { @@ -1912,8 +1946,9 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObLobType */ ObNumberType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ - ObMaxType, /* ObUserDefinedSQLType */ + ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*SetInnerType*/ { @@ -1966,8 +2001,9 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObLobType */ ObNumberType, /* ObJsonType */ ObMaxType, /* ObGeometryType */ - ObMaxType, /* ObUserDefinedSQLType */ + ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObTimestampTZType*/ { @@ -2022,6 +2058,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObTimestampTZType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObTimestampLTZType*/ { @@ -2076,6 +2113,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObTimestampLTZType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObTimestampNanoType*/ { @@ -2130,6 +2168,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObTimestampNanoType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObRawType*/ { @@ -2184,6 +2223,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObRawType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObIntervalYMType*/ { @@ -2238,6 +2278,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObIntervalYMType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObIntervalDSType*/ { @@ -2292,6 +2333,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObIntervalDSType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*NumberFloatType*/ @@ -2347,6 +2389,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObDoubleType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNumberType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*NVarchar2Type*/ @@ -2402,6 +2445,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*NCharType*/ @@ -2457,6 +2501,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObURowIDType*/ { @@ -2511,6 +2556,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObLobType*/ { @@ -2565,6 +2611,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObJsonType*/ { @@ -2619,6 +2666,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObJsonType, /* ObGeometryType*/ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObGeometryType*/ { @@ -2673,6 +2721,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObHexStringType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*ObUserDefinedSQLType*/ { @@ -2727,6 +2776,7 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, /*DecimalIntType*/ { @@ -2781,7 +2831,63 @@ static constexpr ObObjType RELATIONAL_EQUAL_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }, + /*ObCollectionSQLType*/ + { + ObMaxType, /* NullType */ + ObMaxType, /* TinyIntType */ + ObMaxType, /* SmallIntType */ + ObMaxType, /* MediumIntType */ + ObMaxType, /* Int32Type */ + ObMaxType, /* IntType */ + ObMaxType, /* UTinyIntType */ + ObMaxType, /* USmallIntType */ + ObMaxType, /* UMediumIntType */ + ObMaxType, /* UInt32Type */ + ObMaxType, /* UIntType */ + ObMaxType, /* FloatType */ + ObMaxType, /* DoubleType */ + ObMaxType, /* UFloatType */ + ObMaxType, /* UDoubleType */ + ObMaxType, /* NumberType */ + ObMaxType, /* UNumberType */ + ObMaxType, /* DateTimeType */ + ObMaxType, /* TimestampType */ + ObMaxType, /* DateType */ + ObMaxType, /* TimeType */ + ObMaxType, /* YearType */ + ObMaxType, /* VarcharType */ + ObMaxType, /* CharType */ + ObMaxType, /* HexStringType */ + ObMaxType, /* ExtendType */ + ObMaxType, /* UnknownType */ + ObMaxType, /*TinyTextType*/ + ObMaxType, /*TextType*/ + ObMaxType, /*MediumTextType*/ + ObMaxType, /*LongTextType*/ + ObMaxType, /*BitType*/ + ObMaxType, /*EnumType*/ + ObMaxType, /*SetType*/ + ObMaxType, /*EnumInnerType*/ + ObMaxType, /*SetInnerType*/ + ObMaxType, /* ObTimestampTZType */ + ObMaxType, /* ObTimestampLTZType */ + ObMaxType, /* ObTimestampNanoType */ + ObMaxType, /* ObRawType */ + ObMaxType, /* ObIntervalYMType */ + ObMaxType, /* ObIntervalDSType */ + ObMaxType, /* ObNumberFloatType */ + ObMaxType, /* ObNVarchar2Type */ + ObMaxType, /* ObNCharType */ + ObMaxType, /* ObURowIDType */ + ObMaxType, /* ObLobType */ + ObMaxType, /* ObJsonType */ + ObMaxType, /* ObGeometryType */ + ObMaxType, /* ObUserDefinedSQLType */ + ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ + } }; static_assert(is_array_fully_initialized(RELATIONAL_EQUAL_TYPE, ObMaxType), "RELATIONAL_EQUAL_TYPE is partially initlized"); diff --git a/src/sql/engine/expr/ob_expr_relational_result_type.map b/src/sql/engine/expr/ob_expr_relational_result_type.map index 2835534b07..932ddb7a28 100644 --- a/src/sql/engine/expr/ob_expr_relational_result_type.map +++ b/src/sql/engine/expr/ob_expr_relational_result_type.map @@ -53,6 +53,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*TinyIntType*/ { @@ -107,6 +108,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*SmallIntType*/ @@ -162,6 +164,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*MediumIntType*/ @@ -217,6 +220,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*Int32Type*/ @@ -272,6 +276,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*IntType*/ @@ -327,6 +332,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UTinyIntType*/ @@ -382,6 +388,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*USmallIntType*/ @@ -437,6 +444,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UMediumIntType*/ @@ -492,6 +500,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UInt32Type*/ @@ -547,6 +556,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UIntType*/ @@ -602,6 +612,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*FloatType*/ @@ -657,6 +668,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*DoubleType*/ @@ -712,6 +724,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UFloatType*/ @@ -767,6 +780,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UDoubleType*/ @@ -822,6 +836,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*NumberType*/ @@ -877,6 +892,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UNumberType*/ @@ -932,6 +948,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*DateTimeType*/ @@ -987,6 +1004,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*TimestampType*/ @@ -1042,6 +1060,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*DateType*/ @@ -1097,6 +1116,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*TimeType*/ @@ -1152,6 +1172,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*YearType*/ @@ -1207,6 +1228,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*VarcharType*/ @@ -1262,6 +1284,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*CharType*/ @@ -1317,6 +1340,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*HexStringType*/ @@ -1372,6 +1396,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ExtendType*/ @@ -1427,6 +1452,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*UnknownType*/ @@ -1482,6 +1508,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObVarcharType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTinyTextType*/ { @@ -1536,6 +1563,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTextType*/ { @@ -1590,6 +1618,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObMediumTextType*/ { @@ -1644,6 +1673,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObLongTextType*/ { @@ -1698,6 +1728,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*BitType*/ { @@ -1752,6 +1783,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObEnumType*/ { @@ -1806,6 +1838,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObSetType*/ { @@ -1860,6 +1893,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObEnumInnerType*/ { @@ -1914,6 +1948,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObSetInnerType*/ { @@ -1968,6 +2003,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTimestampTZType*/ { @@ -2022,6 +2058,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObVarcharType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTimestampLTZType*/ { @@ -2076,6 +2113,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObVarcharType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObTimestampNanoType*/ { @@ -2130,6 +2168,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObVarcharType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObRawType*/ { @@ -2184,6 +2223,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObIntervalYMType*/ { @@ -2238,6 +2278,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObIntervalDSType*/ { @@ -2292,6 +2333,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*NumberFloatType*/ @@ -2347,6 +2389,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*NVarchar2Type*/ { @@ -2401,6 +2444,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNVarchar2Type, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*NCharType*/ @@ -2456,6 +2500,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObNCharType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObURowIDType*/ { @@ -2510,6 +2555,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObLobType*/ { @@ -2564,6 +2610,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObJsonType*/ { @@ -2618,6 +2665,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDoubleType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObGeometryType*/ { @@ -2672,6 +2720,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObUserDefinedSQLType*/ { @@ -2726,6 +2775,7 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType*/ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, /*ObDecimalIntType*/ { @@ -2780,6 +2830,62 @@ static constexpr ObObjType RELATIONAL_RESULT_TYPE[ObMaxType][ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* UDT */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ + }, + /*ObCollectionSQLType*/ + { + ObMaxType, /* NullType */ + ObMaxType, /* TinyIntType */ + ObMaxType, /* SmallIntType */ + ObMaxType, /* MediumIntType */ + ObMaxType, /* Int32Type */ + ObMaxType, /* IntType */ + ObMaxType, /* UTinyIntType */ + ObMaxType, /* USmallIntType */ + ObMaxType, /* UMediumIntType */ + ObMaxType, /* UInt32Type */ + ObMaxType, /* UInt64Type */ + ObMaxType, /* FloatType */ + ObMaxType, /* DoubleType */ + ObMaxType, /* UFloatType */ + ObMaxType, /* UDoubleType */ + ObMaxType, /* NumberType */ + ObMaxType, /* UNumberType */ + ObMaxType, /* DateTimeType */ + ObMaxType, /* TimestampType */ + ObMaxType, /* DateType */ + ObMaxType, /* TimeType */ + ObMaxType, /* YearType */ + ObMaxType, /* VarcharType */ + ObMaxType, /* CharType */ + ObMaxType, /* HexStringType */ + ObMaxType, /* ExtendType */ + ObMaxType, /* UnknownType */ + ObMaxType, /* ObTinyTextType */ + ObMaxType, /* ObTextType */ + ObMaxType, /* ObMediumTextType */ + ObMaxType, /* ObLongTextType */ + ObMaxType, /* ObBitType */ + ObMaxType, /* ObEnumType */ + ObMaxType, /* ObSetType */ + ObMaxType, /* ObEnumInnerType */ + ObMaxType, /* ObSetInnerType */ + ObMaxType, /* ObTimestampTZType */ + ObMaxType, /* ObTimestampLTZType */ + ObMaxType, /* ObTimestampNanoType */ + ObMaxType, /* ObRawType */ + ObMaxType, /* ObIntervalYMType */ + ObMaxType, /* ObIntervalDSType */ + ObMaxType, /* ObNumberFloatType */ + ObMaxType, /* ObNVarchar2Type */ + ObMaxType, /* ObNCharType */ + ObMaxType, /* ObURowIDType */ + ObMaxType, /* ObLobType */ + ObMaxType, /* ObJsonType */ + ObMaxType, /* ObGeometryType */ + ObMaxType, /* ObUserDefinedSQLType*/ + ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType*/ }, }; diff --git a/src/sql/engine/expr/ob_expr_res_type.h b/src/sql/engine/expr/ob_expr_res_type.h index a457d1c43e..45c235cbbd 100644 --- a/src/sql/engine/expr/ob_expr_res_type.h +++ b/src/sql/engine/expr/ob_expr_res_type.h @@ -155,7 +155,8 @@ public: int ret = common::OB_SUCCESS; common::ObLength length = accuracy_.get_length(); if (!is_string_type() && !is_enum_or_set() && !is_enumset_inner_type() - && !is_ext() && !is_lob_locator() && !is_user_defined_sql_type()) { + && !is_ext() && !is_lob_locator() && !is_user_defined_sql_type() + && !is_collection_sql_type()) { if (OB_FAIL(common::ObField::get_field_mb_length(get_type(), get_accuracy(), common::CS_TYPE_INVALID, diff --git a/src/sql/engine/expr/ob_expr_round_result_type.map b/src/sql/engine/expr/ob_expr_round_result_type.map index 74f0fe397a..d2845e8d1f 100644 --- a/src/sql/engine/expr/ob_expr_round_result_type.map +++ b/src/sql/engine/expr/ob_expr_round_result_type.map @@ -51,6 +51,7 @@ static constexpr ObObjType ROUND_RESULT_TYPE[ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObDecimalIntType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }; static_assert(is_array_fully_initialized(ROUND_RESULT_TYPE), "ROUND_RESULT_TYPE is partially initlized"); \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_spatial_collection.cpp b/src/sql/engine/expr/ob_expr_spatial_collection.cpp index 2685a3a308..c950c3b19f 100644 --- a/src/sql/engine/expr/ob_expr_spatial_collection.cpp +++ b/src/sql/engine/expr/ob_expr_spatial_collection.cpp @@ -48,9 +48,8 @@ int ObExprSpatialCollection::calc_result_typeN(ObExprResType &type, { UNUSED(type_ctx); int ret = OB_SUCCESS; - type.set_type(ObGeometryType); - type.set_collation_level(common::CS_LEVEL_COERCIBLE); - type.set_collation_type(CS_TYPE_BINARY); + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); for (uint32_t i = 0; i < param_num && OB_SUCC(ret); i++) { ObObjType in_type = types_stack[i].get_type(); if (ob_is_null(in_type)) { @@ -253,6 +252,7 @@ int ObExprSpatialCollection::eval_spatial_collection(const ObExpr &expr, common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); ObWkbBuffer res_wkb_buf(tmp_allocator); uint32_t srid = 0; + bool is_null_result = false; ObGeoType geo_type = get_geo_type(); if (ObGeoType::GEOMETRY >= geo_type || ObGeoType::GEOTYPEMAX <= geo_type) { @@ -273,9 +273,11 @@ int ObExprSpatialCollection::eval_spatial_collection(const ObExpr &expr, } else { ObDatum *datum = NULL; ObString wkb; - for (uint32_t i = 0; OB_SUCC(ret) && i < expr.arg_cnt_; i++) { + for (uint32_t i = 0; OB_SUCC(ret) && i < expr.arg_cnt_ && !is_null_result; i++) { if (OB_FAIL(expr.args_[i]->eval(ctx, datum))) { LOG_WARN("fail to eval datum", K(ret)); + } else if (datum->is_null() ) { + is_null_result = true; } else if (FALSE_IT(wkb = datum->get_string())) { } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(tmp_allocator, *datum, expr.args_[i]->datum_meta_, expr.args_[i]->obj_meta_.has_lob_header(), wkb))) { @@ -298,7 +300,14 @@ int ObExprSpatialCollection::eval_spatial_collection(const ObExpr &expr, const ObString wkb_sub = wkb; const char *data = wkb_sub.ptr() + WKB_OFFSET; const uint64_t len = wkb_sub.length() - WKB_OFFSET; - if (res_wkb_buf.append(data, len)) { + ObGeoType sub_type = ObGeoType::GEOTYPEMAX; + if (OB_FAIL(ObGeoTypeUtil::get_type_from_wkb(wkb_sub, sub_type))) { + LOG_WARN("fail to get geo type", K(ret), K(sub_type)); + } else if (ObGeoTypeUtil::is_3d_geo_type(sub_type)) { + ret = OB_INVALID_ARGUMENT; + LOG_USER_ERROR(OB_INVALID_ARGUMENT, get_func_name()); + LOG_WARN("unexpected sub geo type", K(ret), K(sub_type)); + } else if (res_wkb_buf.append(data, len)) { LOG_WARN("fail to append sub data to res wkb buf", K(ret), K(wkb_sub), K(len)); } } @@ -306,17 +315,16 @@ int ObExprSpatialCollection::eval_spatial_collection(const ObExpr &expr, } if (OB_SUCC(ret)) { - if (OB_FAIL(ObGeoExprUtils::pack_geo_res(expr, ctx, res, res_wkb_buf.string()))) { + if (is_null_result) { + res.set_null(); + } else if (ObGeoType::LINESTRING == geo_type && expr.arg_cnt_ < 2) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, get_func_name()); + LOG_WARN("invalid linestring data", K(ret), K(expr.arg_cnt_)); + } else if (OB_FAIL(ObGeoExprUtils::pack_geo_res(expr, ctx, res, res_wkb_buf.string()))) { LOG_WARN("fail to pack geo res", K(ret)); } } - - if (OB_SUCC(ret) && ObGeoType::LINESTRING == geo_type && expr.arg_cnt_ < 2) { // adapt mysql, check arg count at last. - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, get_func_name()); - LOG_WARN("invalid linestring data", K(ret), K(expr.arg_cnt_)); - } - return ret; } diff --git a/src/sql/engine/expr/ob_expr_sql_udt_construct.cpp b/src/sql/engine/expr/ob_expr_sql_udt_construct.cpp new file mode 100644 index 0000000000..e996398cf1 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_sql_udt_construct.cpp @@ -0,0 +1,424 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX SQL_ENG + +#include "ob_expr_sql_udt_construct.h" +#include "ob_expr_sql_udt_utils.h" +#include "sql/session/ob_sql_session_info.h" +#include "share/ob_lob_access_utils.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_sql_udt_utils.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "lib/number/ob_number_v2.h" +#include "common/object/ob_object.h" +#include "lib/json_type/ob_json_base.h" +#include "lib/geo/ob_sdo_geo_object.h" +#include "lib/geo/ob_geo_utils.h" +#ifdef OB_BUILD_ORACLE_PL +#include "pl/sys_package/ob_sdo_geometry.h" +#endif + +namespace oceanbase +{ +using namespace common; +namespace sql +{ + +OB_SERIALIZE_MEMBER((ObExprUdtConstruct, ObFuncExprOperator), udt_id_, root_udt_id_, attr_pos_); + +ObExprUdtConstruct::ObExprUdtConstruct(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT, N_PRIV_SQL_UDT_CONSTRUCT, PARAM_NUM_UNKNOWN, NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION, + false, INTERNAL_IN_ORACLE_MODE), + udt_id_(OB_INVALID_ID), + root_udt_id_(OB_INVALID_ID), + attr_pos_(0) {} + +ObExprUdtConstruct::~ObExprUdtConstruct() {} + +int ObExprUdtConstruct::calc_result_typeN(ObExprResType &type, + ObExprResType *types, + int64_t param_num, + ObExprTypeCtx &type_ctx) const +{ + int ret = OB_SUCCESS; + // need const cast to modify subschema ctx, in physcial plan ctx belong to cur exec_ctx; + ObSQLSessionInfo *session = const_cast(type_ctx.get_session()); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + + if (param_num < 1) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected para number", K(ret), K(param_num)); + } else if (types[0].get_type() != ObUserDefinedSQLType && + types[0].get_type() != ObCollectionSQLType && + types[0].get_type() != ObGeometryType) { + // check udt column + ret = OB_ERR_CALL_WRONG_ARG; + LOG_WARN("wrong number or types of arguments in call", K(ret)); + } else if (types[0].get_type() == ObGeometryType) { + if (udt_id_ == T_OBJ_SDO_POINT) { + type.set_type(ObUserDefinedSQLType); + } else if (udt_id_ == T_OBJ_SDO_ORDINATE_ARRAY || + udt_id_ == T_OBJ_SDO_ELEMINFO_ARRAY) { + type.set_type(ObCollectionSQLType); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid udt type", K(ret), K(udt_id_)); + } + } else { + type.set_type(types[0].get_type()); + } + if (OB_SUCC(ret)) { + type.set_udt_id(udt_id_); + uint16_t subschema_id; + if (OB_ISNULL(exec_ctx) && udt_id_ != T_OBJ_XML) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("need context to search subschema mapping", K(ret), K(udt_id_)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_udt_id(udt_id_, subschema_id))) { + LOG_WARN("failed to get sub schema id", K(ret), K(udt_id_)); + } else { + type.set_sql_udt(subschema_id); + } + } + return ret; +} + +int ObExprUdtConstruct::cg_expr(ObExprCGCtx &op_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + int ret = OB_SUCCESS; + ObIAllocator &alloc = *op_cg_ctx.allocator_; + const ObUDTConstructorRawExpr &fun_sys + = static_cast(raw_expr); + ObExprUdtConstructInfo *info + = OB_NEWx(ObExprUdtConstructInfo, (&alloc), alloc, T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT); + if (NULL == info) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret)); + } else { + OZ(info->from_raw_expr(fun_sys)); + rt_expr.extra_info_ = info; + } + rt_expr.eval_func_ = eval_udt_construct; + + return ret; +} + +uint64_t ObExprUdtConstruct::caculate_udt_data_length(const ObExpr &expr, ObEvalCtx &ctx) +{ + uint64_t total_len = ObSqlUDT::get_null_bitmap_len(expr.arg_cnt_); + total_len += (sizeof(int32_t) * (expr.arg_cnt_ )); + for (int64_t i = 0; i < expr.arg_cnt_; ++i) { + ObDatum ¶m = expr.locate_param_datum(ctx, i); + total_len += param.len_; + } + return total_len; +} + +int ObExprUdtConstruct::fill_sub_udt_nested_bitmap(ObSqlUDT &udt_obj, ObObj &nested_udt_bitmap_obj) +{ + int ret = OB_SUCCESS; + int64_t obj_size; + char *buf = NULL; + int64_t pos = 0; + ObArenaAllocator temp_allocator; + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_get_serialize_size(nested_udt_bitmap_obj, obj_size))) { + LOG_WARN("Failed to calculate serialize object size", K(ret)); + } else if (OB_ISNULL(buf = static_cast(temp_allocator.alloc(obj_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc memory", K(ret), K(obj_size)); + } else if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_serialize(nested_udt_bitmap_obj, buf, obj_size, pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(nested_udt_bitmap_obj)); + } else if (OB_FAIL(udt_obj.append_attribute(0, ObString(pos, buf)))) { + LOG_WARN("update attribute failed", K(ret), K(pos)); + } + return ret; +} + +int ObExprUdtConstruct::fill_udt_res_values(const ObExpr &expr, ObEvalCtx &ctx, ObSqlUDT &udt_obj, + bool is_sub_udt, ObObj &nested_udt_bitmap_obj) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(udt_obj.init_null_bitmap())) { + LOG_WARN("init null bitmap failed", K(ret), K(expr.arg_cnt_)); + } + for (int64_t i = 0; i < expr.arg_cnt_ && OB_SUCC(ret); ++i) { + ObDatum ¶m = expr.locate_param_datum(ctx, i); + if (i == 0 && is_sub_udt) { + if (OB_FAIL(fill_sub_udt_nested_bitmap(udt_obj, nested_udt_bitmap_obj))) { + LOG_WARN("Failed to fill sub udt nested bitmap", K(ret), K(nested_udt_bitmap_obj)); + } + } else if (!param.is_null() && expr.args_[i]->datum_meta_.type_ == ObNumberType) { + char num_buf[common::number::ObNumber::MAX_NUMBER_ALLOC_BUFF_SIZE] = {0}; + ObObj obj; + int64_t pos = 0; + obj.set_meta_type(expr.args_[i]->obj_meta_); + obj.set_number(param.get_number_desc(), const_cast(param.get_number_digits())); + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_serialize(obj, num_buf, common::number::ObNumber::MAX_NUMBER_ALLOC_BUFF_SIZE, pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(obj)); + } else if (OB_FAIL(udt_obj.append_attribute(i, ObString(pos, num_buf)))) { + LOG_WARN("update attribute failed", K(ret), K(expr.arg_cnt_), K(i)); + } + } else if (OB_FAIL(udt_obj.append_attribute(i, param.is_null() ? ObString() : param.get_string()))) { + LOG_WARN("update attribute failed", K(ret), K(expr.arg_cnt_), K(i)); + } + } + return ret; +} + +int ObExprUdtConstruct::eval_udt_construct(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObDatum *null_bit = NULL; + bool is_null = false; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObSqlUdtNullBitMap sub_nested_bitmap; + const ObExprUdtConstructInfo *info + = static_cast(expr.extra_info_); + bool is_sub_udt = info->root_udt_id_ != info->udt_id_; + if (expr.arg_cnt_ < 1) { + ret = OB_ERR_CALL_WRONG_ARG; + LOG_WARN("invalid params cnt", K(ret), K(expr.arg_cnt_)); + } else if (OB_FAIL(expr.args_[0]->eval(ctx, null_bit))) { + LOG_WARN("eval null bitmap failed", K(ret)); + } else if (null_bit->is_null()) { + is_null = true; + res.set_null(); + } else if (expr.args_[0]->datum_meta_.type_ == ObGeometryType) { + ObString raw_data = null_bit->get_string(); + if (OB_FAIL(ObTextStringHelper::read_real_string_data(&temp_allocator, ObLongTextType, + CS_TYPE_BINARY, true, + raw_data))) { + LOG_WARN("failed to get udt raw data", K(ret), K(info->udt_id_)); + } else if (OB_FAIL(eval_sdo_geom_udt_access(temp_allocator, expr, ctx, raw_data, info->udt_id_, res))) { + LOG_WARN("failed to eval sdo_geom udt access", K(ret), K(info->udt_id_)); + } + } else if (is_sub_udt) { + // access sub udt + uint16_t subschema_id; + ObSqlUDTMeta sub_udt_meta; + ObSqlUdtNullBitMap nested_bitmap; + ObObj udt_null_bitmap; + udt_null_bitmap.reset(); + ObString ser_element_data; + int64_t buf_pos = 0; + udt_null_bitmap.set_type(ObHexStringType); + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(udt_null_bitmap, + null_bit->get_string().ptr(), + null_bit->get_string().length(), + buf_pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(ser_element_data)); + } else if (OB_FAIL(ObSqlUDT::get_null_bitmap_pos(udt_null_bitmap.get_string().ptr(), + udt_null_bitmap.get_string().length(), + info->attr_pos_, + is_null))) { + LOG_WARN("Failed to get root null bit", K(ret)); + } else if (is_null) { + res.set_null(); + } else if (FALSE_IT(nested_bitmap.set_bitmap(udt_null_bitmap.get_string().ptr(), udt_null_bitmap.get_string().length()))) { + } else if (OB_FAIL(ctx.exec_ctx_.get_subschema_id_by_udt_id(info->udt_id_, subschema_id))) { + LOG_WARN("find subschema_id failed", K(ret), K(subschema_id)); + } else if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, sub_udt_meta))) { + LOG_WARN("get udt meta failed", K(ret), K(subschema_id)); + } else { + uint32_t nested_udt_count = sub_udt_meta.nested_udt_number_ + 1; + uint32_t nested_udt_bitmap_len = ObSqlUDT::get_null_bitmap_len(nested_udt_count); + char * bitmap_buffer = reinterpret_cast(temp_allocator.alloc(nested_udt_bitmap_len)); + if (OB_ISNULL(bitmap_buffer)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc memory sub udt bitmap", K(ret), K(nested_udt_count), K(nested_udt_bitmap_len), K(info->udt_id_)); + } else { + MEMSET(bitmap_buffer, 0, nested_udt_bitmap_len); + sub_nested_bitmap.set_bitmap(bitmap_buffer, nested_udt_bitmap_len); + // bitmap is preorder traversal, sub attr of udt is adjacent + if (OB_FAIL(sub_nested_bitmap.assign(nested_bitmap, info->attr_pos_, nested_udt_count))) { + LOG_WARN("failed to assign sub udt bitmap", K(ret), K(info->attr_pos_), K(info->udt_id_)); + } + } + } + } + if (OB_SUCC(ret) && !is_null && + expr.args_[0]->datum_meta_.type_ != ObGeometryType) { + ObObj nested_udt_bitmap_obj; + nested_udt_bitmap_obj.set_type(ObHexStringType); + uint64_t res_len = caculate_udt_data_length(expr, ctx); + char *res_buf = nullptr; + int64_t res_buf_len = 0; + ObExprStrResAlloc expr_res_alloc(expr, ctx); + ObTextStringResult blob_res(ObLongTextType, true, &expr_res_alloc); + if (is_sub_udt && OB_FAIL(ObSqlUdtUtils::ob_udt_build_nested_udt_bitmap_obj(nested_udt_bitmap_obj, sub_nested_bitmap))) { + LOG_WARN("failed to build nested udt bitmap object", K(ret)); + } else if (OB_FAIL(blob_res.init(res_len))) { + LOG_WARN("fail to init result", K(ret), K(res_len)); + } else if (OB_FAIL(blob_res.get_reserved_buffer(res_buf, res_buf_len))) { + LOG_WARN("failed to get reserved_buffer"); + } else if (res_buf_len < res_len) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_len)); + } else { + ObSqlUDT udt_obj; + ObSqlUDTMeta sql_udt_meta; + sql_udt_meta.attribute_cnt_ = expr.arg_cnt_; + udt_obj.set_udt_meta(sql_udt_meta); + udt_obj.set_data(ObString(res_len, 0, res_buf)); + if (OB_FAIL(fill_udt_res_values(expr, ctx, udt_obj, is_sub_udt, nested_udt_bitmap_obj))) { + LOG_WARN("fill udt value failed", K(ret), K(res_buf_len), K(res_len)); + } else if (OB_FAIL(blob_res.lseek(res_len, 0))) { + LOG_WARN("set result length failed", K(ret), K(res_buf_len), K(res_len)); + } else { + ObString tmp; + blob_res.get_result_buffer(tmp); + res.set_string(tmp.ptr(), tmp.length()); + } + } + } + + return ret; +} + +int ObExprUdtConstruct::eval_sdo_geom_udt_access(ObIAllocator &allocator, const ObExpr &expr, ObEvalCtx &ctx, + const ObString &swkb, uint64_t udt_id, ObDatum &res) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + uint16_t subschema_id; + ObSqlUDTMeta sql_udt_meta; + ObSdoGeoObject sdo_geo; + ObString res_str; + ObExprStrResAlloc expr_res_alloc(expr, ctx); + // pl obj should use this allocator + ObIAllocator &alloc = ctx.exec_ctx_.get_allocator(); + + if (OB_FAIL(ctx.exec_ctx_.get_subschema_id_by_udt_id(udt_id, subschema_id))) { + LOG_WARN("find subschema_id failed", K(ret), K(subschema_id)); + } else if (OB_FAIL(ctx.exec_ctx_.get_sqludt_meta_by_subschema_id(subschema_id, sql_udt_meta))) { + LOG_WARN("get udt meta failed", K(ret), K(subschema_id)); + } else if (OB_FAIL(ObGeoTypeUtil::wkb_to_sdo_geo(swkb, sdo_geo, true))) { + LOG_WARN("fail to wkb_to_sdo_geo", K(ret), K(swkb)); + } else { + ObSqlUDT sql_udt; + sql_udt.set_udt_meta(sql_udt_meta); + ObObj pl_ext; + switch (udt_id) { + case T_OBJ_SDO_POINT : { + if (sdo_geo.get_point().is_null()) { + res.set_null(); + } else if (pl::ObSdoGeometry::write_sdo_point(sdo_geo.get_point(), alloc, pl_ext)) { + LOG_WARN("fail to transform sdo point", K(ret)); + } else if (OB_FAIL(ObSqlUdtUtils::cast_pl_record_to_sql_record(allocator, + expr_res_alloc, + &ctx.exec_ctx_, + res_str, + sql_udt, + pl_ext))) { + LOG_WARN("fail to cast udt sdo point", K(ret)); + } else { + res.set_string(res_str.ptr(), res_str.length()); + } + break; + } + case T_OBJ_SDO_ELEMINFO_ARRAY : { + if (sdo_geo.get_elem_info().empty()) { + res.set_null(); + } else if (pl::ObSdoGeometry::write_sdo_elem_info(ctx.exec_ctx_, sdo_geo.get_elem_info(), alloc, pl_ext)) { + LOG_WARN("fail to transform sdo point", K(ret)); + } else if (OB_FAIL(ObSqlUdtUtils::cast_pl_varray_to_sql_varray(expr_res_alloc, res_str, pl_ext))) { + LOG_WARN("fail to cast udt sdo element", K(ret)); + } else { + res.set_string(res_str.ptr(), res_str.length()); + } + break; + } + case T_OBJ_SDO_ORDINATE_ARRAY : { + if (sdo_geo.get_ordinates().empty()) { + res.set_null(); + } else if (pl::ObSdoGeometry::write_sdo_ordinate(ctx.exec_ctx_, sdo_geo.get_ordinates(), alloc, pl_ext)) { + LOG_WARN("fail to transform sdo point", K(ret)); + } else if (OB_FAIL(ObSqlUdtUtils::cast_pl_varray_to_sql_varray(expr_res_alloc, res_str, pl_ext))) { + LOG_WARN("fail to cast udt sdo element", K(ret)); + } else { + res.set_string(res_str.ptr(), res_str.length()); + } + break; + } + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid udt id", K(ret), K(udt_id)); + } + } +#endif + return ret; +} + +OB_DEF_SERIALIZE(ObExprUdtConstructInfo) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_ENCODE, + udt_id_, + root_udt_id_, + attr_pos_); + return ret; +} + +OB_DEF_DESERIALIZE(ObExprUdtConstructInfo) +{ + int ret = OB_SUCCESS; + LST_DO_CODE(OB_UNIS_DECODE, + udt_id_, + root_udt_id_, + attr_pos_); + return ret; +} + +OB_DEF_SERIALIZE_SIZE(ObExprUdtConstructInfo) +{ + int64_t len = 0; + LST_DO_CODE(OB_UNIS_ADD_LEN, + udt_id_, + root_udt_id_, + attr_pos_); + return len; +} + +int ObExprUdtConstructInfo::deep_copy(common::ObIAllocator &allocator, + const ObExprOperatorType type, + ObIExprExtraInfo *&copied_info) const +{ + int ret = common::OB_SUCCESS; + OZ(ObExprExtraInfoFactory::alloc(allocator, type, copied_info)); + ObExprUdtConstructInfo &other = *static_cast(copied_info); + other.udt_id_ = udt_id_; + other.root_udt_id_ = root_udt_id_; + other.attr_pos_ = attr_pos_; + return ret; +} + +template +int ObExprUdtConstructInfo::from_raw_expr(RE &raw_expr) +{ + int ret = OB_SUCCESS; + ObUDTConstructorRawExpr &udt_raw_expr + = const_cast + (static_cast(raw_expr)); + udt_id_ = udt_raw_expr.get_udt_id(); + root_udt_id_ = udt_raw_expr.get_root_udt_id(); + attr_pos_ = udt_raw_expr.get_attribute_pos(); + return ret; +} + +} /* sql */ +} /* oceanbase */ diff --git a/src/sql/engine/expr/ob_expr_sql_udt_construct.h b/src/sql/engine/expr/ob_expr_sql_udt_construct.h new file mode 100644 index 0000000000..8fbd05576f --- /dev/null +++ b/src/sql/engine/expr/ob_expr_sql_udt_construct.h @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_UDT_CONSTRUCT_H_ +#define OCEANBASE_SQL_OB_EXPR_UDT_CONSTRUCT_H_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "sql/engine/expr/ob_i_expr_extra_info.h" +#include "deps/oblib/src/lib/udt/ob_udt_type.h" + + +namespace oceanbase +{ +namespace sql +{ + +struct ObExprUdtConstructInfo : public ObIExprExtraInfo +{ + OB_UNIS_VERSION(1); +public: + ObExprUdtConstructInfo(common::ObIAllocator &alloc, ObExprOperatorType type) + : ObIExprExtraInfo(alloc, type), + udt_id_(OB_INVALID_ID), root_udt_id_(OB_INVALID_ID), attr_pos_(0) + { + } + + virtual int deep_copy(common::ObIAllocator &allocator, + const ObExprOperatorType type, + ObIExprExtraInfo *&copied_info) const override; + + template + int from_raw_expr(RE &expr); + + uint64_t udt_id_; + uint64_t root_udt_id_; + uint64_t attr_pos_; + +}; + +class ObExprUdtConstruct : public ObFuncExprOperator +{ + OB_UNIS_VERSION(1); +public: + explicit ObExprUdtConstruct(common::ObIAllocator &alloc); + virtual ~ObExprUdtConstruct(); + + virtual int calc_result_typeN(ObExprResType &type, + ObExprResType *types_stack, + int64_t param_num, + common::ObExprTypeCtx &type_ctx) const; + + virtual int cg_expr(ObExprCGCtx &op_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; + static int eval_udt_construct(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + static int eval_sdo_geom_udt_access(ObIAllocator &allocator, const ObExpr &expr, ObEvalCtx &ctx, + const ObString &swkb, uint64_t udt_id, ObDatum &res); + inline void set_udt_id(uint64_t udt_id) { udt_id_ = udt_id; } + inline void set_root_udt_id(uint64_t udt_id) { root_udt_id_ = udt_id; } + inline void set_attribute_pos(uint64_t attr_pos) { attr_pos_ = attr_pos; } +private: + static uint64_t caculate_udt_data_length(const ObExpr &expr, ObEvalCtx &ctx); + static int fill_udt_res_values(const ObExpr &expr, ObEvalCtx &ctx, ObSqlUDT &udt_obj, + bool is_sub_udt, ObObj &nested_udt_bitmap_obj); + static int fill_sub_udt_nested_bitmap(ObSqlUDT &udt_obj, ObObj &nested_udt_bitmap_obj); + uint64_t udt_id_; + uint64_t root_udt_id_; + uint64_t attr_pos_; + +private: + DISALLOW_COPY_AND_ASSIGN(ObExprUdtConstruct); +}; + +} //sql +} //oceanbase +#endif //OCEANBASE_SQL_OB_EXPR_UDT_CONSTRUCT_H_ diff --git a/src/sql/engine/expr/ob_expr_sql_udt_utils.cpp b/src/sql/engine/expr/ob_expr_sql_udt_utils.cpp new file mode 100644 index 0000000000..76ea05b88a --- /dev/null +++ b/src/sql/engine/expr/ob_expr_sql_udt_utils.cpp @@ -0,0 +1,1600 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file is for implement of expr sql udt utils + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "lib/ob_errno.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/expr/ob_expr_sql_udt_utils.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "pl/ob_pl.h" +#include "pl/ob_pl_user_type.h" +#include "src/pl/ob_pl_resolver.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +bool ObSqlUdtNullBitMap::is_valid() +{ + return (OB_NOT_NULL(bitmap_) && bitmap_len_ > 0); +} + +int ObSqlUdtNullBitMap::check_bitmap_pos(uint32_t pos, bool &is_set) +{ + int ret = OB_SUCCESS; + is_set = false; + uint32 index = pos / 8; + uint32 byte_index = pos % 8; + if (index >= bitmap_len_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("check udt bitmap overflow", K(ret), K(*this), K(index), K(byte_index), K(pos)); + } else { + is_set = bitmap_[index] & (1 << byte_index); + } + return ret; +} + +int ObSqlUdtNullBitMap::check_current_bitmap_pos(bool &is_set) +{ + return check_bitmap_pos(pos_, is_set); +} + +int ObSqlUdtNullBitMap::set_bitmap_pos(uint32_t pos) +{ + int ret = OB_SUCCESS; + uint32 index = pos / 8; + uint32 byte_index = pos % 8; + if (index >= bitmap_len_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("set udt bitmap overflow", K(ret), K(*this), K(index), K(byte_index), K(pos)); + } else { + bitmap_[index] |= (1 << byte_index); + } + return ret; +} + +int ObSqlUdtNullBitMap::set_current_bitmap_pos() +{ + return set_bitmap_pos(pos_); +} + +int ObSqlUdtNullBitMap::reset_bitmap_pos(uint32_t pos) +{ + int ret = OB_SUCCESS; + uint32 index = pos / 8; + uint32 byte_index = pos % 8; + if (index >= bitmap_len_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("reset udt bitmap overflow", K(ret), K(*this), K(index), K(byte_index), K(pos)); + } else { + bitmap_[index] &= ~(1 << byte_index); + } + return ret; +} + +int ObSqlUdtNullBitMap::reset_current_bitmap_pos() +{ + return reset_bitmap_pos(pos_); +} + +int ObSqlUdtNullBitMap::assign(ObSqlUdtNullBitMap &src, uint32_t pos, uint32_t bit_len) +{ + int ret = OB_SUCCESS; + uint32_t src_pos = src.get_pos(); + for (int i = 0; i < bit_len && OB_SUCC(ret); i++) { + bool is_set = false; + if (OB_FAIL(src.check_bitmap_pos(pos + i, is_set))) { + LOG_WARN("failed to check nested udt bitmap", K(ret)); + } else if (is_set && OB_FAIL(set_current_bitmap_pos())) { + LOG_WARN("failed to set nested udt bitmap", K(ret)); + } else { + get_pos()++; + } + } + src.set_bitmap_pos(src_pos); + return ret; +} + +int ObSqlUdtUtils::ob_udt_flattern_varray(const ObObj **flattern_objs, + const int32_t &flattern_object_count, + int32_t &pos, + const ObObj *obj, + ObExecContext &exec_context, + ObSqlUDT &sql_udt) +{ + int ret = OB_SUCCESS; + flattern_objs[pos++] = obj; // varray in sql udt is a single obj + return ret; +} + +int ObSqlUdtUtils::ob_udt_flattern_record(const ObObj **flattern_objs, + const int32_t &flattern_object_count, + int32_t &pos, + ObSqlUdtNullBitMap &nested_udt_bitmap, + const ObObj *obj, + ObExecContext &exec_context, + ObSqlUDT &sql_udt) { + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + bool is_null_result = false; + pl::ObPLRecord *record = NULL; + if (OB_ISNULL(obj) || obj->get_ext() == 0) { + is_null_result = true; + } else if (FALSE_IT(record = reinterpret_cast(obj->get_ext()))) { + } else if (record->is_null()) { + is_null_result = true; + } else { + const ObObj *elements = record->get_element(); + const ObObj *cur_element = NULL; + ObSqlUDTAttrMeta *&attrs = sql_udt.get_udt_meta().child_attrs_meta_; + if (OB_ISNULL(attrs)) { + ret = OB_BAD_NULL_ERROR; + LOG_WARN("Unexpected NULL toplevel attributes meta", K(ret)); + } else { + uint32_t toplevel_attrs_count = sql_udt.get_udt_meta().child_attr_cnt_; + for (int32_t i = 0; OB_SUCC(ret) && i < toplevel_attrs_count; i++) { + ObObjType element_type = attrs[i].type_info_.get_type(); + cur_element = &elements[i]; + if (element_type >= ObMaxType) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected record element type", K(ret), K(element_type)); + } else if (ob_is_user_defined_sql_type(element_type) || // nested udt type + ob_is_collection_sql_type(element_type)) { + const uint16_t subschema_id = attrs[i].type_info_.get_subschema_id(); + ObSqlUDTMeta udt_meta; + ObSqlUDT sql_udt; + if (OB_FAIL(exec_context.get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (udt_meta.udt_id_ == T_OBJ_XML) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("nested xmltype not supported", K(ret), K(udt_meta.udt_id_)); + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_meta.udt_id_)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("inconsistent datatypes", K(ret), K(subschema_id), K(udt_meta.udt_id_)); + } else { + sql_udt.set_udt_meta(udt_meta); + int32_t element_pos = 0; // Notice: udt leaf is flattern + if (OB_FAIL(ob_udt_flattern_pl_extend(&flattern_objs[pos], + udt_meta.leaf_attr_cnt_, + element_pos, + nested_udt_bitmap, + cur_element, + exec_context, + sql_udt))) { + LOG_WARN("failed to flattern nested record", K(ret), K(subschema_id), K(udt_meta.udt_id_)); + } else { + pos += element_pos; + } + } + } else if (cur_element == NULL || cur_element->is_null()) { // basic type with null value + flattern_objs[pos] = NULL; + pos++; + } else if (!ob_udt_util_check_same_type(element_type, cur_element->get_type())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("record element type mismarch", K(ret), K(element_type), K(cur_element->get_type())); + } else { + flattern_objs[pos] = cur_element; + pos++; + } + } + } + } + + if (OB_SUCC(ret) && is_null_result) { + // Notice: 1. null extend data is null UDT; 2. bitmap pos is 1 + nested_udt_number_ + for (int32_t i = 0; OB_SUCC(ret) && i <= sql_udt.get_udt_meta().nested_udt_number_; i++) { + if (OB_FAIL(nested_udt_bitmap.set_current_bitmap_pos())) { + LOG_WARN("failed to set nested udt bitmap", K(ret)); + } else { + nested_udt_bitmap.get_pos()++; + } + } + for (int32_t i = 0; OB_SUCC(ret) && i < sql_udt.get_udt_meta().attribute_cnt_; i++) { + if (pos >= flattern_object_count) { + ret = OB_INDEX_OUT_OF_RANGE; + LOG_WARN("flatter objs number error", K(ret), K(pos), K(flattern_object_count)); + } else { + flattern_objs[pos] = NULL; + pos++; + } + } + } +#endif + return ret; +} + +int ObSqlUdtUtils::ob_udt_flattern_pl_extend(const ObObj **flattern_objs, + const int32_t &flattern_object_count, + int32_t &pos, + ObSqlUdtNullBitMap &nested_udt_bitmap, + const ObObj *obj, + ObExecContext &exec_context, + ObSqlUDT &sql_udt) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + if (sql_udt.get_udt_meta().udt_id_ == T_OBJ_XML) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("nested xmltype not supported", K(ret)); + } else if (sql_udt.get_udt_meta().pl_type_ == pl::PL_RECORD_TYPE) { + if (OB_FAIL(ob_udt_flattern_record(flattern_objs, flattern_object_count, pos, + nested_udt_bitmap, + obj, exec_context, sql_udt))) { + LOG_WARN("failed to cast sql record to pl record", K(ret), K(sql_udt.get_udt_meta().udt_id_)); + } + } else if (sql_udt.get_udt_meta().pl_type_ == pl::PL_VARRAY_TYPE) { + if (OB_FAIL(ob_udt_flattern_varray(flattern_objs, flattern_object_count, pos, + obj, exec_context, sql_udt))) { + LOG_WARN("failed to cast sql varray to pl varrayd", + K(ret), K(sql_udt.get_udt_meta().udt_id_)); + } + } else { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("inconsistent datatypes", K(ret), K(sql_udt.get_udt_meta().udt_id_)); + } +#endif + return ret; +} + +int ObSqlUdtUtils::ob_udt_reordering_leaf_objects(const ObObj **flattern_objs, + const ObObj **sorted_objs, + const int32_t &flattern_object_count, + ObSqlUDT &sql_udt) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; i < flattern_object_count; i++) { + int64_t index = sql_udt.get_udt_meta().leaf_attrs_meta_[i].order_; + sorted_objs[i] = flattern_objs[index]; + } + return ret; +} + +int ObSqlUdtUtils::ob_udt_calc_sql_varray_length(const ObObj *cur_obj, + int64_t &sql_udt_total_len, + bool with_lob_header) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + uint32_t count = 0; + uint32_t varray_len = 0; + pl::ObPLVArray *varray = reinterpret_cast(cur_obj->get_ext()); + if (OB_ISNULL(varray) || OB_ISNULL(varray->get_data())) { + // empty array, do nothing + } else { + count = varray->get_count(); + + // count length + varray_len += sizeof(uint32); + + // null count + varray_len += sizeof(uint32); + + // null bitmap length + varray_len += ObSqlUDT::get_offset_array_len(count); + + // offset array length + varray_len += ObSqlUDT::get_null_bitmap_len(count); + + // elements length + const ObObj *cur_obj = NULL; + for (int64_t i = 0; OB_SUCC(ret) && i < count; i++) { + cur_obj = &varray->get_data()[i]; + if (cur_obj == NULL || cur_obj->is_null()) { + // do nothing + } else if (cur_obj->is_ext() || cur_obj->is_user_defined_sql_type()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("varray with udt type is not supported", K(ret), K(cur_obj)); + } else { // serialize basic types + int64_t val_len = 0; + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_get_serialize_size(*cur_obj, val_len))) { + LOG_WARN("Failed to calc object val length", K(ret), K(*cur_obj)); + } else { + varray_len += val_len; + } + } + } + + // varray is a lob, calc lob locator len + int64_t templob_len = 0; + if (OB_FAIL(ret)) { + } else if (!with_lob_header) { + sql_udt_total_len += varray_len; + } else { + if (OB_FAIL(ObTextStringResult::calc_inrow_templob_len(varray_len, templob_len))) { + LOG_WARN("calc sql varray lob length failed", K(ret), K(*cur_obj)); + } else { + sql_udt_total_len += templob_len; + } + } + } +#endif + return ret; +} + +int ObSqlUdtUtils::ob_udt_calc_total_len(const ObObj **sorted_objs, + const int32_t &flattern_object_count, + int64_t &sql_udt_total_len, + ObSqlUDT &sql_udt) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + if (OB_ISNULL(sorted_objs) || flattern_object_count == 0) { + ret = OB_BAD_NULL_ERROR; + LOG_WARN("null objs", K(ret), KP(sorted_objs), K(flattern_object_count)); + } else { + int64_t leaf_attr_count = sql_udt.get_udt_meta().leaf_attr_cnt_ + 1; + if (sql_udt.get_udt_meta().pl_type_ == pl::PL_RECORD_TYPE) { + sql_udt_total_len += sql_udt.get_null_bitmap_len(leaf_attr_count); + sql_udt_total_len += sql_udt.get_offset_array_len(leaf_attr_count); + } + const ObObj *cur_obj = NULL; + for (int64_t i = 0; OB_SUCC(ret) && i < flattern_object_count; i++) { + cur_obj = sorted_objs[i]; + if (cur_obj == NULL) { + } else if (cur_obj->is_ext()) { + pl::ObPLType pl_type = static_cast(cur_obj->get_meta().get_extend_type()); + if (pl_type == pl::PL_VARRAY_TYPE) { + if (OB_FAIL(ob_udt_calc_sql_varray_length(cur_obj, sql_udt_total_len))) { + LOG_WARN("Failed to calc sql varray length", K(ret), K(i), K(pl_type)); + } + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("Unexpected supported pl type", K(ret), K(i), K(pl_type)); + } + } else { // serialize basic types + int64_t val_len = 0; + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_get_serialize_size(*cur_obj, val_len))) { + LOG_WARN("Failed to calc object val length", K(ret), K(*cur_obj)); + } else { + sql_udt_total_len += val_len; + } + } + } + } +#endif + return ret; +} + +int ObSqlUdtUtils::ob_udt_convert_pl_varray_to_sql_varray(const ObObj *cur_obj, + char *buf, + const int64_t buf_len, + int64_t &pos, + bool with_lob_header) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + uint32_t count = 0; + pl::ObPLVArray *varray = reinterpret_cast(cur_obj->get_ext()); + if (OB_ISNULL(varray) || OB_ISNULL(varray->get_data())) { + // empty array, do nothing + } else { + int64_t locator_header_offset = pos; + int64_t locator_header_len = with_lob_header + ? ObTextStringResult::calc_inrow_templob_locator_len() + : 0; + + // reserve length for templob header; + pos += locator_header_len; + + // related_start for calculating array element offset + int64_t related_start = pos; + + // encoding count + count = varray->get_count(); + *(reinterpret_cast(&buf[pos])) = count; + + // null count + pos += sizeof(uint32_t); + uint32_t null_count_offset = pos; + *(reinterpret_cast(&buf[pos])) = 0; + + // bitmap + pos += sizeof(uint32_t); + char *leaf_bitmap_ptr = buf + pos; + uint32_t leaf_bitmap_len = ObSqlUDT::get_null_bitmap_len(count); + MEMSET(leaf_bitmap_ptr, 0, leaf_bitmap_len); + + // reserve bitmap + pos += leaf_bitmap_len; + uint32_t *offset_ptr = reinterpret_cast(buf + pos); + + // reserve offset array + pos += ObSqlUDT::get_offset_array_len(count); + + // elements length + const ObObj *cur_obj = NULL; + for (int64_t i = 0; OB_SUCC(ret) && i < count; i++) { + cur_obj = &varray->get_data()[i]; + if (cur_obj == NULL|| cur_obj->is_null()) { + offset_ptr[i] = pos - related_start; + if (OB_FAIL(ObSqlUDT::set_null_bitmap_pos(leaf_bitmap_ptr, leaf_bitmap_len, i))) { + LOG_WARN("Failed to set varray element null bitmap", + K(ret), K(leaf_bitmap_ptr), K(leaf_bitmap_len), K(i)); + } else { + ObSqlUDT::increase_varray_null_count(buf + null_count_offset); + } + } else if (cur_obj->is_ext() || cur_obj->is_user_defined_sql_type()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("varray with udt type is not supported", K(ret), K(cur_obj)); + } else { // serialize basic types + uint64_t offset = pos - related_start; + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_serialize(*cur_obj, buf, buf_len, pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(*cur_obj)); + } else { + offset_ptr[i] = offset; + } + } + } + + if (with_lob_header) { + int64_t templob_inrow_data_len = pos - locator_header_len - locator_header_offset; + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObTextStringResult::fill_inrow_templob_header(templob_inrow_data_len, + buf + locator_header_offset, + pos - locator_header_offset))) { + LOG_WARN("Failed to set templob header for sql varray", K(ret), K(*cur_obj)); + } + } + } +#endif + return ret; +} + +// convert pl extend to sql udt by type +int ObSqlUdtUtils::ob_udt_convert_sorted_objs_array_to_udf_format(const ObObj **sorted_objs, + char *buf, + const int64_t buf_len, + int64_t &pos, + ObSqlUDT &sql_udt) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + if (OB_ISNULL(sorted_objs)) { + ret = OB_BAD_NULL_ERROR; + LOG_WARN("Unexpected NULL element", K(ret)); + } else { // record + int64_t leaf_attr_count = sql_udt.get_udt_meta().leaf_attr_cnt_ + 1; + char *leaf_bitmap_ptr = buf + pos; + uint32_t leaf_bitmap_len = ObSqlUDT::get_null_bitmap_len(leaf_attr_count); + MEMSET(leaf_bitmap_ptr, 0, leaf_bitmap_len); + + pos += sql_udt.get_null_bitmap_len(leaf_attr_count); + uint32_t *offset_ptr = reinterpret_cast(buf + pos); + + pos += sql_udt.get_offset_array_len(leaf_attr_count); + + if (pos > buf_len) { // pos could equal to buf_len, when all elements are NULL + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Buffer overflow", K(ret), K(pos), K(buf_len)); + } + + const ObObj *cur_element = NULL; + for (int64_t i = 0; OB_SUCC(ret) && i < leaf_attr_count; i++) { + cur_element = sorted_objs[i]; + ObObjType cur_element_type = ObMaxType; + offset_ptr[i] = 0; + if (OB_ISNULL(cur_element)) { + offset_ptr[i] = pos; + if (OB_FAIL(ObSqlUDT::set_null_bitmap_pos(leaf_bitmap_ptr, leaf_bitmap_len, i))) { + LOG_WARN("Failed to set varray element null bitmap", + K(ret), K(leaf_bitmap_ptr), K(leaf_bitmap_len), K(i)); + } + } else if (FALSE_IT(cur_element_type = cur_element->get_type())) { + } else if (cur_element_type == ObUserDefinedSQLType + || cur_element_type == ObCollectionSQLType + || cur_element_type >= ObMaxType) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected record element type", K(ret), K(cur_element_type)); + } else if (cur_element_type == ObExtendType) { + pl::ObPLType pl_type = static_cast(cur_element->get_meta().get_extend_type()); + if (pl_type == pl::PL_VARRAY_TYPE) { + uint64_t offset = pos; + if (OB_FAIL(ob_udt_convert_pl_varray_to_sql_varray(cur_element, buf, buf_len, pos))) { + LOG_WARN("convert pl varray to sql varray failed", K(ret), K(i), K(pl_type)); + } else { + offset_ptr[i] = offset; + } + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("Unexpected supported pl type", K(ret), K(i), K(pl_type)); + } + } else { + // serialize basic types + uint64_t offset = pos; + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_serialize(*cur_element, buf, buf_len, pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(*cur_element)); + } else { + offset_ptr[i] = offset; + } + } + } + + if (OB_SUCC(ret) && (pos != buf_len)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sql udt content length error", K(ret), K(pos), K(buf_len)); + } + } +#endif + return ret; +} + +// convert sql_udt to string by type +int ObSqlUdtUtils::covert_sql_udt_varray_to_string(ObStringBuffer &buf, + ObString &udt_varray_buf, + ObSqlUDTMeta &root_meta) +{ + int ret = OB_SUCCESS; + ObSqlUDT varray_handler; + varray_handler.set_udt_meta(root_meta); + ObString varray_data = udt_varray_buf; + ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + if (OB_FAIL(ObTextStringHelper::read_real_string_data(&lob_allocator, + ObLongTextType, + CS_TYPE_BINARY, + true, varray_data))) { + LOG_WARN("fail to get real string data", K(ret), K(varray_data)); + } else if (FALSE_IT(varray_handler.set_data(varray_data))) { + } else if (varray_data.empty()) { + if (OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print empty value", K(ret)); + } + } else if (OB_FAIL(buf.append(varray_handler.get_udt_meta().udt_name_, + varray_handler.get_udt_meta().udt_name_len_))) { + LOG_WARN("fail to print varray name start", K(ret)); + } else if (OB_FAIL(buf.append("("))){ + LOG_WARN("fail to print (", K(ret)); + } else { + uint64_t element_count = varray_handler.get_varray_element_count(); + ObString ser_element_data; + char number_buff[256]; + for (int64_t i = 0; OB_SUCC(ret) && i < element_count; i++) { + if (OB_FAIL(varray_handler.access_attribute(i, ser_element_data, true))) { + LOG_WARN("fail to access attribute buffer", K(ret)); + } else if (ser_element_data.empty()) { + if (OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print empty value", K(ret)); + } + } else { + ObObj obj; + obj.set_meta_type(varray_handler.get_udt_meta().child_attrs_meta_[0].type_info_); + int64_t pos = 0; + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj, + ser_element_data.ptr(), + ser_element_data.length(), + pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(ser_element_data)); + } else { + // ToDo: different types + if (obj.get_type_class() == ObNumberTC) { + int64_t str_len = 0; + const number::ObNumber &val = obj.get_number(); + int16_t scale = obj.get_scale(); + if (OB_FAIL(val.format(number_buff, sizeof(number_buff), str_len, scale))) { + LOG_WARN("fail to format number with oracle limit", K(ret), K(str_len), K(scale)); + } else if (OB_FAIL(buf.append(number_buff, str_len))) { + LOG_WARN("fail to print number value", K(ret), K(val)); + } + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported udt element type", K(ret), K(obj)); + } + } + } + + if (OB_SUCC(ret)) { + if ((i < element_count - 1) && OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } + } + } + + if (OB_SUCC(ret) && OB_FAIL(buf.append(")"))) { + LOG_WARN("fail to print )", K(ret)); + } + } + return ret; +} + +int ObSqlUdtUtils::convert_sql_udt_attributes_to_string(ObStringBuffer &buf, + ObString *attrs, + int64_t &pos, + sql::ObExecContext *exec_context, + ObSqlUDTMeta &root_meta, + ObSqlUdtNullBitMap &nested_udt_bitmap) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + if (OB_FAIL(buf.append(root_meta.udt_name_, root_meta.udt_name_len_))) { + LOG_WARN("fail to print point type start", K(ret)); + } else if (OB_FAIL(buf.append("("))){ + LOG_WARN("fail to print (", K(ret)); + } else { + ObObj obj; + char number_buff[256]; + for (int64_t i = 0; OB_SUCC(ret) && i < root_meta.child_attr_cnt_; i++) { + ObObjType type = root_meta.child_attrs_meta_[i].type_info_.get_type(); + obj.reset(); + obj.set_meta_type(root_meta.child_attrs_meta_[i].type_info_); + bool is_nested_record = false; + if (type == ObUserDefinedSQLType || + (type == ObCollectionSQLType && root_meta.child_attr_cnt_ > 1)) { + const uint16_t subschema_id = obj.get_meta().get_subschema_id(); + ObSqlUDTMeta udt_meta; + // should be varray or record + bool is_udt_null = false; + if (OB_FAIL(exec_context->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (nested_udt_bitmap.is_valid() + && OB_FAIL(nested_udt_bitmap.check_current_bitmap_pos(is_udt_null))) { + LOG_WARN("failed to get nested udt null bit", K(ret), K(nested_udt_bitmap)); + } else if (is_udt_null) { + if (OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print empty value", K(ret)); + } else { + pos += udt_meta.leaf_attr_cnt_; + nested_udt_bitmap.get_pos() += (udt_meta.nested_udt_number_ + 1); // count the nested udt itself + is_nested_record = true; + } + } else if (udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) { + if (OB_FAIL(covert_sql_udt_varray_to_string(buf, + attrs[pos], + udt_meta))) { + LOG_WARN("failed to convert sql udt varray to string failed", + K(ret), K(i), K(pos), K(subschema_id)); + } + } else if (udt_meta.pl_type_ == pl::PL_RECORD_TYPE) { + if (OB_FAIL(convert_sql_udt_attributes_to_string(buf, + attrs, + pos, + exec_context, + udt_meta, + nested_udt_bitmap))) { + LOG_WARN("failed to convert to string", K(ret), K(udt_meta.pl_type_)); + } + is_nested_record = true; + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected type to convert pl udt to sql udt format", K(ret), K(udt_meta.pl_type_)); + } + } else { // basic types + int64_t buf_pos = 0; + if (OB_ISNULL(attrs[pos])) { + if (OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print empty value", K(ret)); + } + } else if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj, + attrs[pos].ptr(), + attrs[pos].length(), + buf_pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(attrs[pos])); + } else { + // ToDo: @gehao, different basic types + int64_t str_len = 0; + const number::ObNumber &val = obj.get_number(); + int16_t scale = obj.get_scale(); + if (OB_FAIL(val.format(number_buff, sizeof(number_buff), str_len, scale))) { + LOG_WARN("fail to format number with oracle limit", K(ret), K(str_len), K(scale)); + } else if (OB_FAIL(buf.append(number_buff, str_len))) { + LOG_WARN("fail to print number value", K(ret), K(val)); + } + } + } + if (OB_SUCC(ret)) { // Notice: not use pos for ',' and ')' + if ((i < root_meta.child_attr_cnt_ - 1) && OB_FAIL(buf.append(", "))) { + LOG_WARN("fail to print ,", K(ret)); + } else if ((i == root_meta.child_attr_cnt_ - 1) && OB_FAIL(buf.append(")"))) { + LOG_WARN("fail to print )", K(ret)); + } else { + pos += (is_nested_record ? 0 : 1); + } + } + } + } +#endif + return ret; +} + +int ObSqlUdtUtils::rearrange_sql_udt_record(ObString &sql_udt_data, + ObSqlUDTMeta udt_meta, + common::ObIAllocator *allocator, + ObSqlUdtNullBitMap &nested_udt_bitmap, + ObString *&attrs, + bool &is_null) +{ + int ret = OB_SUCCESS; + ObString udt_data = sql_udt_data; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, ObLongTextType, CS_TYPE_BINARY, true, udt_data))) { + LOG_WARN("fail to get real string data", K(ret), K(udt_data)); + } else { + ObSqlUDT sql_udt; + sql_udt.set_udt_meta(udt_meta); + sql_udt.set_data(udt_data); + + ObString *temp_leaf_attrs = NULL; + ObString *leaf_attrs = NULL; + ObSqlUDTAttrMeta *top_attrs_meta = udt_meta.child_attrs_meta_; + ObSqlUDTAttrMeta *leaf_attrs_meta = udt_meta.leaf_attrs_meta_; + int64_t leaf_attr_count = udt_meta.leaf_attr_cnt_; + + if (OB_ISNULL(top_attrs_meta) || OB_ISNULL(leaf_attrs_meta) || (leaf_attr_count == 0)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid udt meta", K(ret), KP(top_attrs_meta), KP(leaf_attrs_meta), K(leaf_attr_count)); + } else { + uint64_t alloc_len = sizeof(ObString) * leaf_attr_count; + if (OB_ISNULL(temp_leaf_attrs = reinterpret_cast(allocator->alloc(alloc_len)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory for attributes", K(ret), K(alloc_len)); + } else if (OB_ISNULL(leaf_attrs = reinterpret_cast(allocator->alloc(alloc_len)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory for rearranged attributes", K(ret), K(alloc_len)); + } else { + ObString attribute_data; + bool root_udt_is_null = false; + ObObj udt_null_bitmap; + udt_null_bitmap.reset(); + udt_null_bitmap.set_type(ObHexStringType); + int64_t buf_pos = 0; + + // get first attribute(nested udt null bitmpa) + if (OB_FAIL(sql_udt.access_attribute(0, attribute_data))) { + LOG_WARN("fail to access null bitmap attribute", K(ret)); + } else if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(udt_null_bitmap, + attribute_data.ptr(), + attribute_data.length(), + buf_pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(attribute_data)); + } else { + nested_udt_bitmap.set_bitmap(udt_null_bitmap.get_string().ptr(), + udt_null_bitmap.get_string().length()); + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(nested_udt_bitmap.check_bitmap_pos(0, root_udt_is_null))) { + LOG_WARN("Failed to get root null bit", K(ret)); + } else if (root_udt_is_null) { + is_null = root_udt_is_null; + } else { + nested_udt_bitmap.get_pos()++; + // flattern all attribuites + for (int64_t i = 1; OB_SUCC(ret) && i < leaf_attr_count + 1; i++) { + if (OB_FAIL(sql_udt.access_attribute(i, attribute_data))) { + LOG_WARN("fail to access attribute buffer", K(ret)); + } else { + temp_leaf_attrs[i - 1] = attribute_data; + } + } + // rearrange attributes to original order + for (int64_t i = 0; OB_SUCC(ret) && i < leaf_attr_count; i++) { + leaf_attrs[i] = temp_leaf_attrs[leaf_attrs_meta[i].order_]; + } + } + } + if (OB_SUCC(ret)) { + attrs = leaf_attrs; + } + } + } + return ret; +} + +int ObSqlUdtUtils::convert_sql_udt_to_string(ObObj &sql_udt_obj, + common::ObIAllocator *allocator, + sql::ObExecContext *exec_context, + ObSqlUDT &sql_udt, + ObString &res_str) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + ObSqlUDTMeta &udt_meta = sql_udt.get_udt_meta(); + ObStringBuffer buf(allocator); + ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + ObString udt_data = sql_udt_obj.get_string(); + ObSqlUdtNullBitMap nested_udt_bitmap; + bool is_null_record = false; + ObString *attrs = NULL; + + if (udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) { // single varray + if (udt_meta.child_attr_cnt_ != 1) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("varray udt meta error", K(ret), K(udt_meta.child_attr_cnt_)); + } else if (OB_FAIL(covert_sql_udt_varray_to_string(buf, udt_data, udt_meta))) { + LOG_WARN("failed to convert sql udt varray to string failed", K(ret)); + } + } else { // record + if (OB_FAIL(rearrange_sql_udt_record(udt_data, + udt_meta, + &lob_allocator, + nested_udt_bitmap, + attrs, + is_null_record))) { + LOG_WARN("failed to rearrange sql udt record", K(ret)); + } else if (OB_ISNULL(attrs) || is_null_record) { + if (OB_FAIL(buf.append("NULL"))) { + LOG_WARN("fail to print empty value", K(ret)); + } + } else { + int64_t pos = 0; + if (OB_FAIL(convert_sql_udt_attributes_to_string(buf, + attrs, + pos, + exec_context, + udt_meta, + nested_udt_bitmap))) { + LOG_WARN("fail to convert sql udt attributes to string", K(ret)); + } else if (pos != udt_meta.leaf_attr_cnt_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("leaf element count mismarch", + K(ret), K(pos), K(udt_meta.leaf_attr_cnt_)); + } + } + } + + if (OB_SUCC(ret)) { + res_str.assign_ptr(buf.ptr(), buf.length()); + } +#endif + return ret; +} + +int ObSqlUdtUtils::cast_pl_varray_to_sql_varray(common::ObIAllocator &res_allocator, + ObString &res, + const ObObj root_obj, + bool with_lob_header) +{ + int ret = OB_SUCCESS; + // for single varray + int64_t total_len = 0; + char *res_ptr = NULL; + int64_t pos = 0; + if (OB_FAIL(ob_udt_calc_sql_varray_length(&root_obj, total_len, with_lob_header))) { + LOG_WARN("Failed to calc sql varray length", K(ret), K(root_obj)); + } else if (OB_ISNULL(res_ptr = static_cast(res_allocator.alloc(total_len)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret), K(total_len)); + } else if (OB_FAIL(ob_udt_convert_pl_varray_to_sql_varray(&root_obj, res_ptr, total_len, pos, with_lob_header))) { + LOG_WARN("convert pl varray to sql varray failed", K(ret), K(pos)); + } else if (total_len != pos) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("covert single varray failed, length error", K(ret), K(total_len), K(pos)); + } else { + res.assign_ptr(res_ptr, total_len); + } + return ret; +} + +int ObSqlUdtUtils::cast_pl_record_to_sql_record(common::ObIAllocator &tmp_allocator, + common::ObIAllocator &res_allocator, + sql::ObExecContext *exec_ctx, + ObString &res, + ObSqlUDT &sql_udt, + const ObObj &root_obj) +{ + int ret = OB_SUCCESS; + // root udt always has a nested udt bitmap, even if does not has any nested udt attributes + // the nested udt bitmap is a special attribute always at position 0 + ObObj nested_udt_bitmap_obj; + nested_udt_bitmap_obj.set_type(ObHexStringType); + int32_t leaf_attr_count = sql_udt.get_udt_meta().leaf_attr_cnt_ + 1; + uint32_t nested_udt_count = sql_udt.get_udt_meta().nested_udt_number_ + 1; + uint32_t nested_udt_bitmap_len = ObSqlUDT::get_null_bitmap_len(nested_udt_count); + int64_t sql_udt_total_len = 0; + + char * bitmap_buffer = reinterpret_cast(tmp_allocator.alloc(nested_udt_bitmap_len)); + const ObObj **flattern_objs = + reinterpret_cast(tmp_allocator.alloc(sizeof(ObObj *) * (leaf_attr_count))); + const ObObj **sorted_objs = + reinterpret_cast(tmp_allocator.alloc(sizeof(ObObj *) * (leaf_attr_count))); + + if (OB_ISNULL(flattern_objs) || OB_ISNULL(sorted_objs) || OB_ISNULL(bitmap_buffer)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc memory for pl extend cast to udt", + K(ret), KP(flattern_objs), KP(sorted_objs), KP(bitmap_buffer)); + } else { + MEMSET(bitmap_buffer, 0, nested_udt_bitmap_len); + } + + ObSqlUdtNullBitMap nested_udt_bitmap(bitmap_buffer, nested_udt_bitmap_len); + nested_udt_bitmap.get_pos()++; // first bit is used by root udt + int32_t pos = 1; + int32_t reorder_start_pos = 1; + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ob_udt_flattern_pl_extend(flattern_objs, leaf_attr_count, pos, + nested_udt_bitmap, &root_obj, + *exec_ctx, sql_udt))) { + LOG_WARN("failed to flattern pl extend", K(ret), K(root_obj), K(leaf_attr_count)); + } else if (OB_FAIL(ob_udt_reordering_leaf_objects(&flattern_objs[reorder_start_pos], + &sorted_objs[reorder_start_pos], + leaf_attr_count - reorder_start_pos, + sql_udt))) { + LOG_WARN("failed to reorder pl extend", K(ret), K(root_obj), K(leaf_attr_count)); + } else if (OB_FAIL(ob_udt_build_nested_udt_bitmap_obj(nested_udt_bitmap_obj, + nested_udt_bitmap))) { + LOG_WARN("failed to build nested udt bitmap object", K(ret), K(root_obj), K(leaf_attr_count)); + } else if (FALSE_IT(sorted_objs[0] = &nested_udt_bitmap_obj)) { + } else if (OB_FAIL(ob_udt_calc_total_len(sorted_objs,leaf_attr_count, + sql_udt_total_len, sql_udt))) { + LOG_WARN("failed to calc total sql udt len", K(ret), K(root_obj), K(leaf_attr_count)); + } else if (sql_udt_total_len == 0) { + res.reset(); + } else { + ObTextStringResult blob_res(ObLongTextType, true, &res_allocator); + char *buf = NULL; + int64_t buf_len = 0; + int64_t buf_pos = 0; + if (OB_FAIL(ret)) { + } else if (OB_FAIL(blob_res.init(sql_udt_total_len))) { + LOG_WARN("failed to alloc temp lob", K(ret), K(sql_udt_total_len)); + } else if (OB_FAIL(blob_res.get_reserved_buffer(buf, buf_len))) { + LOG_WARN("failed to reserve temp lob buffer", K(ret), K(sql_udt_total_len)); + } else if (sql_udt_total_len != buf_len) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get reserve len is invalid", K(ret), K(sql_udt_total_len), K(buf_len)); + } else if (OB_FAIL(ob_udt_convert_sorted_objs_array_to_udf_format(sorted_objs, buf, + buf_len, buf_pos, sql_udt))) { + LOG_WARN("faild to convert pl extend to sql udt", K(ret), K(sql_udt.get_udt_meta().udt_id_)); + } else if (OB_FAIL(blob_res.lseek(buf_pos, 0))) { + LOG_WARN("temp lob lseek failed", K(ret), K(blob_res), K(buf_pos)); + } else { + blob_res.get_result_buffer(res); + } + } + return ret; +} + +int ObSqlUdtUtils::build_empty_record(sql::ObExecContext *exec_ctx, ObObj &result, uint64_t udt_id) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("need execute ctx to get subschema map on phyplan ctx", K(ret), K(udt_id)); + } + ObSQLSessionInfo *session = exec_ctx->get_my_session(); + ObIAllocator &alloc = exec_ctx->get_allocator(); + pl::ObPLPackageGuard package_guard(session->get_effective_tenant_id()); + pl::ObPLResolveCtx resolve_ctx(alloc, + *session, + *(exec_ctx->get_sql_ctx()->schema_guard_), + package_guard, + *(exec_ctx->get_sql_proxy()), + false); + pl::ObPLINS *ns = NULL; + if (NULL == session->get_pl_context()) { + OZ (package_guard.init()); + OX (ns = &resolve_ctx); + } else { + ns = session->get_pl_context()->get_current_ctx(); + } + if (OB_SUCC(ret)) { + ObObj new_composite; + int64_t ptr = 0; + int64_t init_size = OB_INVALID_SIZE; + ObArenaAllocator tmp_alloc; + const pl::ObUserDefinedType *user_type = NULL; + OZ (ns->get_user_type(udt_id, user_type, &tmp_alloc)); + CK (OB_NOT_NULL(user_type)); + OZ (user_type->newx(alloc, ns, ptr)); + OZ (user_type->get_size(pl::PL_TYPE_INIT_SIZE, init_size)); + OX (new_composite.set_extend(ptr, user_type->get_type(), init_size)); + OX (result = new_composite); + } +#endif + return ret; +} + +int ObSqlUdtUtils::cast_sql_udt_varray_to_pl_varray(sql::ObExecContext *exec_ctx, + ObString &udt_varray_buf, + ObSqlUDTMeta &udt_meta, + ObObj &res_obj) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + ObSqlUDT varray_handler; + ObString varray_data = udt_varray_buf; + ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("need execute ctx to get subschema map on phyplan ctx", K(ret), K(udt_meta)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(&lob_allocator, + ObLongTextType, + CS_TYPE_BINARY, + true, varray_data))) { + LOG_WARN("fail to get real string data", K(ret), K(varray_data)); + } + ObIAllocator &alloc = exec_ctx->get_allocator(); + varray_handler.set_data(varray_data); + varray_handler.set_udt_meta(udt_meta); + if (OB_FAIL(ret)) { + } else if (varray_data.empty()) { + res_obj.set_null(); + } else { + // alloc collection(varray) hander + common::ObDataType elem_type; + pl::ObElemDesc elem_desc; + pl::ObPLCollection *coll = NULL; + if (OB_ISNULL(coll = static_cast(alloc.alloc(sizeof(pl::ObPLVArray) + 8)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to allocate memory for pl collection", K(ret), K(coll)); + } else { + coll = new(coll)pl::ObPLVArray(udt_meta.udt_id_); + static_cast(coll)->set_capacity(udt_meta.varray_capacity_); + elem_type.set_meta_type(udt_meta.child_attrs_meta_[0].type_info_); + elem_desc.set_data_type(elem_type); // Notice: accuracty and others not setted + elem_desc.set_field_count(1); // varray with basic type elements, field count is 1. + coll->set_element_desc(elem_desc); + coll->set_not_null(false); // should from udt meta + } + + ObObj *varray_objs = NULL; + uint64_t element_count = varray_handler.get_varray_element_count(); + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObSPIService::spi_set_collection(0, NULL, alloc, *coll, element_count))) { + LOG_WARN("failed to allocate memory for pl collection", K(ret), K(coll)); + } else if (OB_ISNULL(varray_objs = coll->get_data())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("varray data is null", K(ret)); + } + + ObString attr_data; + for (int64_t i = 0; OB_SUCC(ret) && i < element_count; i++) { + if (OB_FAIL(varray_handler.access_attribute(i, attr_data, true))) { + LOG_WARN("fail to access attribute buffer", K(ret)); + } else if (attr_data.empty()) { + // do nothing, all element objs in varray is set null in spi_set_collection + } else { + ObObj obj; + obj.set_meta_type(varray_handler.get_udt_meta().child_attrs_meta_[0].type_info_); + int64_t pos = 0; + if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj, + attr_data.ptr(), + attr_data.length(), + pos))) { + LOG_WARN("failed to serialize object value", K(ret), K(attr_data)); + } else if (deep_copy_obj(*coll->get_allocator(), obj, varray_objs[i])){ + LOG_WARN("failed to deep copy element object value", K(ret), K(obj), K(i)); + } + } + } + + // is nested varray needs add to pl ctx? may not needed for obobj cast + if (OB_SUCC(ret)) { + res_obj.set_extend(reinterpret_cast(coll), coll->get_type()); + if (OB_NOT_NULL(coll->get_allocator())) { + if (OB_ISNULL(exec_ctx->get_pl_ctx())) { + if (OB_FAIL(exec_ctx->init_pl_ctx() || OB_ISNULL(exec_ctx->get_pl_ctx()))) { + LOG_ERROR("fail to init pl ctx", K(ret)); + } + } + if (OB_SUCC(ret) && OB_FAIL(exec_ctx->get_pl_ctx()->add(res_obj))) { + LOG_ERROR("fail to collect pl collection allocator, may be exist memory issue", K(ret)); + } + } + } + } +#endif + return ret; +} + +int ObSqlUdtUtils::cast_sql_udt_attributes_to_pl_record(sql::ObExecContext *exec_ctx, + ObString *attrs, + int64_t &pos, + ObSqlUDTMeta &udt_meta, + ObSqlUdtNullBitMap &nest_udt_bitmap, + ObObj &res_obj) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("need execute ctx to get subschema map on phyplan ctx", K(ret), K(udt_meta)); + } else { + ObIAllocator &allocator = exec_ctx->get_allocator(); + // null root is handled by the caller + uint32_t top_level_attr_count = udt_meta.child_attr_cnt_; + pl::ObPLRecord *record = + static_cast(allocator.alloc(pl::ObRecordType::get_init_size(top_level_attr_count))); + if (OB_ISNULL(record)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc memory", K(ret)); + } else { + new(record)pl::ObPLRecord(udt_meta.udt_id_, top_level_attr_count); + } + ObObj obj; + for (int64_t i = 0; OB_SUCC(ret) && i < top_level_attr_count; i++) { + obj.reset(); + obj.set_meta_type(udt_meta.child_attrs_meta_[i].type_info_); + ObObjType type = obj.get_type(); + bool is_udt_null = false; + bool is_nested_record = false; + + if (type == ObUserDefinedSQLType || type == ObCollectionSQLType) { + const uint16_t subschema_id = obj.get_meta().get_subschema_id(); + ObSqlUDTMeta sub_udt_meta; + // should be varray or record + if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(subschema_id, sub_udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } + if (OB_FAIL(ret)) { + } else if (nest_udt_bitmap.is_valid() + && OB_FAIL(nest_udt_bitmap.check_current_bitmap_pos(is_udt_null))) { + LOG_WARN("failed to get nested udt null bit", K(ret)); + } else if (sub_udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) { + if (is_udt_null) { + obj.set_null(); + } else if (OB_FAIL(cast_sql_udt_varray_to_pl_varray(exec_ctx, attrs[pos], sub_udt_meta, obj))) { + LOG_WARN("failed to convert nested sql udt varray to pl extend", + K(ret), K(i), K(pos), K(subschema_id), K(sub_udt_meta.udt_id_)); + } + } else if (sub_udt_meta.pl_type_ == pl::PL_RECORD_TYPE) { + if (is_udt_null) { + if (OB_FAIL(build_empty_record(exec_ctx, obj, sub_udt_meta.udt_id_))) { + LOG_WARN("failed to create empty nested udt record", K(ret)); + } else { + pl::ObPLRecord *child_null_record = reinterpret_cast(obj.get_ext()); + child_null_record->set_null(); + pos += sub_udt_meta.leaf_attr_cnt_; + // count the nested udt itself + nest_udt_bitmap.get_pos() += (sub_udt_meta.nested_udt_number_ + 1); + } + } else if (OB_FAIL(cast_sql_udt_attributes_to_pl_record(exec_ctx, + attrs, + pos, + sub_udt_meta, + nest_udt_bitmap, + obj))) { + LOG_WARN("failed to convert nestd sql udt record to pl extend", K(ret), K(sub_udt_meta.pl_type_)); + } + is_nested_record = true; + // pos is changed inside; + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Unexpected type to convert sql udt to pl udt format", K(ret), K(sub_udt_meta.pl_type_)); + } + } else { // basic types + int64_t buf_pos = 0; + if (OB_ISNULL(attrs[pos])) { + obj.set_null(); + } else if (OB_FAIL(ObObjUDTUtil::ob_udt_obj_value_deserialize(obj, + attrs[pos].ptr(), + attrs[pos].length(), + buf_pos))) { + LOG_WARN("Failed to serialize object value", K(ret), K(attrs[pos])); + } + } + + if (OB_SUCC(ret)){ + pos += (is_nested_record ? 0 : 1); + if (type == ObUserDefinedSQLType || type == ObCollectionSQLType) { + obj.meta_.set_ext(); + obj.meta_.set_extend_type(type == ObUserDefinedSQLType ? pl::PL_RECORD_TYPE : pl::PL_VARRAY_TYPE); + } + record->get_element()[i] = obj; + } + } + if (OB_SUCC(ret)) { + res_obj.set_extend(reinterpret_cast(record), + pl::PL_RECORD_TYPE, pl::ObRecordType::get_init_size(top_level_attr_count)); + } + } +#endif + return ret; +} + +int ObSqlUdtUtils::cast_sql_record_to_pl_record(sql::ObExecContext *exec_ctx, + ObObj &result, + ObString &udt_data, + ObSqlUDTMeta &udt_meta) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + if (udt_meta.pl_type_ == pl::PL_VARRAY_TYPE) { // single varray + if (udt_meta.child_attr_cnt_ != 1) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("varray udt meta error", K(ret), K(udt_meta.child_attr_cnt_)); + } else if (OB_FAIL(cast_sql_udt_varray_to_pl_varray(exec_ctx, udt_data, udt_meta, result))) { + LOG_WARN("failed to convert sql udt varray to pl varray", K(ret)); + } + } else { + // udt meta already set + bool is_null_record = false; + ObSqlUdtNullBitMap nested_udt_bitmap; + ObString *attrs = NULL; + ObArenaAllocator lob_allocator(ObModIds::OB_LOB_ACCESS_BUFFER, OB_MALLOC_NORMAL_BLOCK_SIZE, MTL_ID()); + + if (OB_FAIL(rearrange_sql_udt_record(udt_data, + udt_meta, + &lob_allocator, + nested_udt_bitmap, + attrs, + is_null_record))) { + LOG_WARN("failed to rearrange sql udt record", K(ret)); + } else if (OB_ISNULL(attrs) || is_null_record) { + result.set_null(); + } else { + int64_t pos = 0; + if (OB_FAIL(cast_sql_udt_attributes_to_pl_record(exec_ctx, + attrs, + pos, + udt_meta, + nested_udt_bitmap, + result))) { + LOG_WARN("fail to cast sql udt record to pl record", K(ret)); + } else if (pos != udt_meta.leaf_attr_cnt_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("leaf element count mismarch", + K(ret), K(pos), K(udt_meta.leaf_attr_cnt_)); + } + } + } +#endif + return ret; +} + +int ObSqlUdtUtils::get_sqludt_meta_by_subschema_id(sql::ObExecContext *exec_ctx, + const uint16_t subschema_id, + ObSqlUDTMeta &udt_meta) { + int ret = OB_SUCCESS; + if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("need execute ctx to get subschema map on phyplan ctx", K(ret), K(subschema_id)); + } else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } + return ret; +} + +int ObSqlUdtMetaUtils::get_udt_meta_attr_info(ObSchemaGetterGuard *schema_guard, + uint64_t tenant_id, + const ObUDTTypeInfo *parent_udt_info, + uint32_t &nested_udt_number, + common::ObIArray &leaf_attr_meta) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(schema_guard) || OB_ISNULL(parent_udt_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null schema guard or parent udt info", K(ret), KP(schema_guard), KP(parent_udt_info)); + } else { + uint32_t count = parent_udt_info->get_attrs_count(); + for (uint32_t i = 0; i < count; i++) { + ObUDTTypeAttr *udt_attr = parent_udt_info->get_attrs().at(i); + if (udt_attr->get_type_attr_id() < ObMaxType) { + if (OB_FAIL(leaf_attr_meta.push_back(udt_attr))) { + LOG_WARN("failed to push back leaf attr pointer", K(i), K(count), K(leaf_attr_meta.count())); + } + } else { + uint64_t udt_id = udt_attr->get_type_attr_id(); + const ObUDTTypeInfo *attr_udt_info = NULL; + if (OB_FAIL(schema_guard->get_udt_info(tenant_id, udt_id, attr_udt_info))) { + // pl::get_tenant_id_by_object_id + LOG_WARN("failed to get udt info", K(ret), K(tenant_id), K(udt_id)); + } else if (OB_ISNULL(attr_udt_info) ) { // try system udt + ret = OB_ERR_UNEXPECTED; + LOG_WARN("udt info not found", K(ret), K(tenant_id), K(udt_id)); + } else if (OB_FAIL(get_udt_meta_attr_info(schema_guard, + tenant_id, + attr_udt_info, + nested_udt_number, + leaf_attr_meta))) { + LOG_WARN("failed to get nested udt meta attr info", + K(ret), K(tenant_id), K(parent_udt_info->get_type_id()), K(udt_id)); + } else if (attr_udt_info->is_object_type()) { + nested_udt_number++; + } else if (attr_udt_info->is_varray()) { // varray is special to other udts, it is a basic type in sql + if (OB_FAIL(leaf_attr_meta.push_back(udt_attr))) { + LOG_WARN("failed to push back leaf attr pointer", K(i), K(count), K(leaf_attr_meta.count())); + } + } + } + } + } + return ret; +} + +int ObSqlUdtMetaUtils::fill_udt_meta_attr_info(ObSchemaGetterGuard *schema_guard, + ObSubSchemaCtx *subschema_ctx, + uint64_t tenant_id, + const common::ObIArray &src, + ObSqlUDTAttrMeta *dst, + const uint32 dst_cnt, + bool is_leaf) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(dst)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null src or dest for udt type attr", K(src), KP(dst)); + } else if (src.count() != dst_cnt) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("attr count mismarch", K(src), K(src.count()), K(dst_cnt)); + } else { + for (int32_t i = 0; OB_SUCC(ret) && i < dst_cnt; i++) { + ObUDTTypeAttr *udt_attr = src.at(i); + ObSqlUDTAttrMeta *udt_attr_meta = &dst[i]; + udt_attr_meta->order_ = i; // order of orignal leaf attributes + udt_attr_meta->type_info_.reset(); + + if (OB_ISNULL(udt_attr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null udt attribute", K(i), K(src.count())); + } else if (udt_attr->get_type_attr_id() < ObMaxType) { + udt_attr_meta->type_info_.set_type(static_cast(udt_attr->get_type_attr_id())); + udt_attr_meta->type_info_.set_collation_type(static_cast(udt_attr->get_coll_type())); + udt_attr_meta->type_info_.set_scale(static_cast(udt_attr->get_scale())); + } else { // udt attributes + const ObUDTTypeInfo *attr_udt_info = NULL; + uint64_t udt_id = udt_attr->get_type_attr_id(); + if (OB_ISNULL(schema_guard)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null schema guard", K(ret)); + } else if (OB_FAIL(schema_guard->get_udt_info(tenant_id, udt_id, attr_udt_info))) { + LOG_WARN("failed to get udt info", K(ret), K(tenant_id), K(udt_id)); + } else if (OB_ISNULL(attr_udt_info) ) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("udt info not found", K(ret), K(tenant_id), K(udt_id)); + } else if (attr_udt_info->is_object_type()) { + udt_attr_meta->type_info_.set_type(ObUserDefinedSQLType); + } else if (attr_udt_info->is_varray()) { + udt_attr_meta->type_info_.set_type(ObCollectionSQLType); + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported udt type", K(ret), K(*attr_udt_info)); + } + + uint16_t subschema_id = ObMaxSystemUDTSqlType; + if (OB_FAIL(ret)) { + } else if (is_leaf + && udt_attr->get_type_attr_id() > ObMaxType + && !attr_udt_info->is_varray()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected non-leaf attrs", K(ret), K(*udt_attr), K(i), K(src.count())); + } else if (OB_ISNULL(subschema_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null subschema ctx", K(ret)); + } else if (OB_FAIL(subschema_ctx->get_subschema_id(udt_id, + OB_SUBSCHEMA_UDT_TYPE, + subschema_id))) { + // ToDo: @gehao, refine + if (OB_HASH_NOT_EXIST != ret) { + LOG_WARN("failed to get subschema id by udt_id", K(ret), K(udt_id)); + } else { // build new meta + ret = OB_SUCCESS; + uint16 new_subschema_id = ObMaxSystemUDTSqlType; + ObSqlUDTMeta *udt_meta = NULL; + ObSubSchemaValue value; + ObIAllocator &allocator = subschema_ctx->get_allocator(); + if (OB_ISNULL(schema_guard)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("No schema gurad to generate udt_meta", K(ret), K(udt_id)); + } else if (FALSE_IT(udt_meta = reinterpret_cast(allocator.alloc(sizeof(ObSqlUDTMeta))))) { + } else if (OB_ISNULL(udt_meta)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc udt meta", K(ret), K(udt_id), K(sizeof(ObSqlUDTMeta))); + } else if (FALSE_IT(MEMSET(udt_meta, 0, sizeof(ObSqlUDTMeta)))) { + } else if (OB_FAIL(ObSqlUdtMetaUtils::generate_udt_meta_from_schema(schema_guard, + subschema_ctx, + allocator, // use allocator in physical plan + tenant_id, + udt_id, + *udt_meta))) { + LOG_WARN("generate udt_meta failed", K(ret), K(tenant_id), K(udt_id)); + } else if (OB_FAIL(subschema_ctx->get_subschema_id_from_fields(udt_id, new_subschema_id))) { + LOG_WARN("failed to get subschema id from result fields", K(ret), K(tenant_id), K(udt_id)); + } else if (new_subschema_id == ObInvalidSqlType // not get from fields, generate new + && OB_FAIL(subschema_ctx->get_new_subschema_id(new_subschema_id))) { + LOG_WARN("failed to get new subschema id", K(ret), K(tenant_id), K(udt_id)); + } else { + value.type_ = OB_SUBSCHEMA_UDT_TYPE; + value.signature_ = udt_id; + value.value_ = static_cast(udt_meta); + if (OB_FAIL(subschema_ctx->set_subschema(new_subschema_id, value))) { + LOG_WARN("failed to set new subschema", K(ret), K(new_subschema_id), K(udt_id), K(value)); + } else { + subschema_id = new_subschema_id; + udt_attr_meta->type_info_.set_subschema_id(subschema_id); + } + } + } + } else { + udt_attr_meta->type_info_.set_subschema_id(subschema_id); + } + if (OB_FAIL(ret)) { + } else if (udt_attr_meta->type_info_.is_collection_sql_type()) { + udt_attr_meta->type_info_.set_inrow(); + } else if (is_lob_storage(udt_attr_meta->type_info_.get_type())) { + udt_attr_meta->type_info_.set_has_lob_header(); + } + } + } + } + return ret; +} + +int ObSqlUdtMetaUtils::generate_udt_meta_from_schema(ObSchemaGetterGuard *schema_guard, + ObSubSchemaCtx *subschema_ctx, + common::ObIAllocator &allocator, + uint64_t tenant_id, + uint64_t udt_id, + ObSqlUDTMeta &udt_meta) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_WARN("not support", K(ret)); +#else + const ObUDTTypeInfo *root_udt_info = NULL; + ObSEArray temp_leaf_attr_meta; + uint32_t child_attrs_cnt = 0; + uint32_t leaf_attrs_cnt = 0; + uint32_t fixed_len_attr_cnt = 0; + uint32_t fixed_attr_cnt = 0; // not used leaf an empty interface + int32_t fixed_offset_ = 0; + int32_t pl_type = 0; + uint32_t nested_udt_number = 0; + uint32_t varray_capacity = 0; + ObString type_name; + + if (is_inner_pl_object_id(udt_id)) { + tenant_id = OB_SYS_TENANT_ID; + } + if (OB_ISNULL(schema_guard)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null schema guard", K(ret)); + } else if (OB_FAIL(schema_guard->get_udt_info(tenant_id, udt_id, root_udt_info))) { + // pl::get_tenant_id_by_object_id + LOG_WARN("failed to get udt info", K(ret), K(tenant_id), K(udt_id)); + } else if (OB_ISNULL(root_udt_info) ) { // try system udt + ret = OB_ERR_UNEXPECTED; + LOG_WARN("udt info not found", K(ret), K(tenant_id), K(udt_id)); + } else if (root_udt_info->get_type_name().empty()) { // copy name + ret = OB_ERR_UNEXPECTED; + LOG_WARN("udt info without name", K(ret), K(tenant_id), K(udt_id)); + } else if (OB_FAIL(ob_write_string(allocator, root_udt_info->get_type_name(), type_name))) { + LOG_WARN("failed to copy udt name", K(ret), K(tenant_id), K(udt_id)); + } else { + udt_meta.set_name(type_name); + udt_meta.udt_id_ = udt_id; + if (root_udt_info->is_object_type()) { + pl_type = static_cast(pl::PL_RECORD_TYPE); + child_attrs_cnt = root_udt_info->get_local_attrs(); + } else if (root_udt_info->is_varray()) { + pl_type = static_cast(pl::PL_VARRAY_TYPE); + if (OB_NOT_NULL(root_udt_info->get_coll_info())) { + varray_capacity = root_udt_info->get_coll_info()->get_upper_bound(); + } + child_attrs_cnt = 1; + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported udt type", K(ret), K(*root_udt_info)); + } + if (OB_SUCC(ret)) { + udt_meta.varray_capacity_ = varray_capacity; + udt_meta.pl_type_ = pl_type; + udt_meta.child_attr_cnt_ = child_attrs_cnt; + if (OB_FAIL(get_udt_meta_attr_info(schema_guard, + tenant_id, + root_udt_info, + nested_udt_number, + temp_leaf_attr_meta))) { + LOG_WARN("failed to fill udt meta info"); + } else { + leaf_attrs_cnt = temp_leaf_attr_meta.count(); + udt_meta.nested_udt_number_ = nested_udt_number; + udt_meta.leaf_attr_cnt_ = leaf_attrs_cnt; + udt_meta.attribute_cnt_ = leaf_attrs_cnt; + udt_meta.fixed_attr_cnt_ = fixed_attr_cnt; + udt_meta.fixed_offset_ = fixed_offset_; + udt_meta.child_attrs_meta_ = NULL; + udt_meta.leaf_attrs_meta_ = NULL; + ObSqlUDTAttrMeta *leaf_attrs_meta = NULL; + uint32_t child_attrs_size = sizeof(ObSqlUDTAttrMeta) * child_attrs_cnt; + ObSqlUDTAttrMeta *child_attrs_meta + = reinterpret_cast(allocator.alloc(child_attrs_size)); + if (child_attrs_cnt > 0 && OB_ISNULL(child_attrs_meta)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory for child attrs failed", + K(ret), K(child_attrs_cnt), K(child_attrs_size)); + } else if (root_udt_info->is_varray()) { + if (child_attrs_cnt != 1) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("error child attribute count for varray", K(ret), K(child_attrs_cnt)); + } else { + ObObjType elem_type = static_cast(root_udt_info->get_coll_info()->get_elem_type_id()); + ObCollationType coll_type = static_cast( + root_udt_info->get_coll_info()->get_coll_type()); + child_attrs_meta->order_ = 0; + child_attrs_meta->type_info_.set_type(elem_type); + // child_attrs_meta->type_info_.set_collation_level(CS_LEVEL_IMPLICIT); // setted in set_type + child_attrs_meta->type_info_.set_collation_type(coll_type); + child_attrs_meta->type_info_.set_scale(static_cast(root_udt_info->get_coll_info()->get_scale())); + udt_meta.child_attrs_meta_ = child_attrs_meta; + } + } else if (OB_FAIL(fill_udt_meta_attr_info(schema_guard, + subschema_ctx, + tenant_id, + root_udt_info->get_attrs(), + child_attrs_meta, + child_attrs_cnt, + false))) { // record type + LOG_WARN("failed to fill udt meta attr info", K(ret), K(child_attrs_cnt), K(*root_udt_info)); + } else { + udt_meta.child_attrs_meta_ = child_attrs_meta; + } + + uint32_t leaf_attrs_size = sizeof(ObSqlUDTAttrMeta) * leaf_attrs_cnt; + if (OB_FAIL(ret) || leaf_attrs_cnt == 0) { + } else if (FALSE_IT(leaf_attrs_meta = reinterpret_cast( + allocator.alloc(leaf_attrs_size)))) { + } else if (OB_ISNULL(leaf_attrs_meta)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed for leaf attrs failed", + K(ret), K(leaf_attrs_cnt), K(leaf_attrs_size)); + } else if (OB_FAIL(fill_udt_meta_attr_info(schema_guard, + subschema_ctx, + tenant_id, + temp_leaf_attr_meta, + leaf_attrs_meta, + leaf_attrs_cnt, + true))) { + LOG_WARN("failed to fill udt meta attr info", + K(ret), K(leaf_attrs_cnt), K(temp_leaf_attr_meta)); + } else { + udt_meta.leaf_attrs_meta_ = leaf_attrs_meta; + } + } + } + } +#endif + return ret; +} + +} +} diff --git a/src/sql/engine/expr/ob_expr_sql_udt_utils.h b/src/sql/engine/expr/ob_expr_sql_udt_utils.h new file mode 100644 index 0000000000..1d8b1320dc --- /dev/null +++ b/src/sql/engine/expr/ob_expr_sql_udt_utils.h @@ -0,0 +1,227 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file is for define of expr sql udt utils + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_SQL_UDT_UTILS_H_ +#define OCEANBASE_SQL_OB_EXPR_SQL_UDT_UTILS_H_ + +#include "share/ob_lob_access_utils.h" +#include "sql/engine/expr/ob_expr_util.h" +#include "sql/session/ob_sql_session_info.h" + +namespace oceanbase +{ +namespace sql +{ + +class ObSqlUdtNullBitMap final +{ +public: + ObSqlUdtNullBitMap() : bitmap_(NULL), bitmap_len_(0), ver_(0), pos_(0) + {}; + ObSqlUdtNullBitMap(char *bitmap, uint32_t bitmap_len) : + bitmap_(bitmap), bitmap_len_(bitmap_len), ver_(0), pos_(0) + {}; + ObSqlUdtNullBitMap(ObString &bitmap_str) : + bitmap_(bitmap_str.ptr()), bitmap_len_(bitmap_str.length()), ver_(0), pos_(0) + {}; + ~ObSqlUdtNullBitMap(){}; + + TO_STRING_KV(KP_(bitmap), K_(bitmap_len), K_(ver), K_(pos)); + + bool is_valid(); + void set_bitmap(char *bitmap, uint32_t bitmap_len) { + bitmap_ = bitmap; + bitmap_len_ = bitmap_len; + ver_ = 0; + pos_ = 0; + } + int check_bitmap_pos(uint32_t pos, bool &is_set); + int set_bitmap_pos(uint32_t pos); + int reset_bitmap_pos(uint32_t pos); + + int check_current_bitmap_pos(bool &is_set); + int set_current_bitmap_pos(); + int reset_current_bitmap_pos(); + int assign(ObSqlUdtNullBitMap &src, uint32_t pos, uint32_t bit_len); + inline uint32_t &get_pos() { return pos_; }; + inline char *&get_bitmap_ptr() { return bitmap_; }; + inline uint32_t get_bitmap_bytelen() { return bitmap_len_; }; + + +private: + char *bitmap_; + uint32_t bitmap_len_; // byte len + uint32_t ver_; // reserved for inheritance + uint32_t pos_; +}; + +// wrapper class to handle udt format(sql/pl) convert +class ObSqlUdtUtils final +{ +public: + // functions to flattern nested udt to a single object array + static int ob_udt_flattern_pl_extend(const ObObj **flattern_objs, + const int32_t &flattern_object_count, + int32_t &pos, + ObSqlUdtNullBitMap &nested_udt_bitmap, + const ObObj *pl_ext_addr, + ObExecContext &exec_context, + ObSqlUDT &sql_udt); + + static int ob_udt_flattern_varray(const ObObj **flattern_objs, + const int32_t &flattern_object_count, + int32_t &pos, + const ObObj *obj, + ObExecContext &exec_context, + ObSqlUDT &sql_udt); + + static int ob_udt_flattern_record(const ObObj **flattern_objs, + const int32_t &flattern_object_count, + int32_t &pos, + ObSqlUdtNullBitMap &nested_udt_bitmap, + const ObObj *obj, + ObExecContext &exec_context, + ObSqlUDT &sql_udt); + + // functions to reorder object array + static int ob_udt_reordering_leaf_objects(const ObObj **flattern_objs, + const ObObj **sorted_objs, + const int32_t &flattern_object_count, + ObSqlUDT &sql_udt); + + // functions to calc sql udt length (from nested pl extend objects) + static int ob_udt_calc_total_len(const ObObj **sorted_objs, + const int32_t &flattern_object_count, + int64_t &sql_udt_total_len, + ObSqlUDT &sql_udt); + static int ob_udt_calc_sql_varray_length(const ObObj *cur_obj, + int64_t &sql_udt_total_len, + bool with_lob_header = true); + + // functions to convert objects (basic type, varray) to sql udt type + static int ob_udt_convert_pl_varray_to_sql_varray(const ObObj *cur_obj, + char *buf, + const int64_t buf_len, + int64_t &pos, + bool with_lob_header = true); + + static int ob_udt_convert_sorted_objs_array_to_udf_format(const ObObj **sorted_objs, + char *buf, + const int64_t buf_len, + int64_t &pos, + ObSqlUDT &sql_udt); + + // functions to convert sql udt to string (only used in text protocal) + static int covert_sql_udt_varray_to_string(ObStringBuffer &buf, + ObString &udt_varray_buf, + ObSqlUDTMeta &root_meta); + + static int convert_sql_udt_attributes_to_string(ObStringBuffer &buf, + ObString *attrs, + int64_t &pos, + sql::ObExecContext *exec_context, + ObSqlUDTMeta &root_meta, + ObSqlUdtNullBitMap &nested_udt_bitmap); + + static int rearrange_sql_udt_record(ObString &sql_udt_data, + ObSqlUDTMeta udt_meta, + common::ObIAllocator *allocator, + ObSqlUdtNullBitMap &nested_udt_bitmap, + ObString *&attrs, + bool &is_null); + + static int convert_sql_udt_to_string(ObObj &sql_udt_obj, + common::ObIAllocator *allocator, + sql::ObExecContext *exec_context, + ObSqlUDT &sql_udt, + ObString &res_str); + + static bool ob_udt_util_check_same_type(ObObjType type1, ObObjType type2) + { + return (type1 == type2) || (ob_is_user_defined_type(type1) && ob_is_user_defined_type(type2)); + } + + static int ob_udt_build_nested_udt_bitmap_obj(ObObj &obj, ObSqlUdtNullBitMap &udt_bitmap) + { + int ret = OB_SUCCESS; + if (udt_bitmap.is_valid()) { + obj.set_hex_string_value(udt_bitmap.get_bitmap_ptr(), udt_bitmap.get_bitmap_bytelen()); + } + return ret; + } + + static int cast_pl_varray_to_sql_varray(common::ObIAllocator &res_allocator, + ObString &res, + const ObObj root_obj, + bool with_lob_header = true); + + static int cast_pl_record_to_sql_record(common::ObIAllocator &tmp_allocator, + common::ObIAllocator &res_allocator, + sql::ObExecContext *exec_ctx, + ObString &res, + ObSqlUDT &sql_udt, + const ObObj &root_obj); + + static int build_empty_record(sql::ObExecContext *exec_ctx, ObObj &result, uint64_t udt_id); + static int cast_sql_udt_varray_to_pl_varray(sql::ObExecContext *exec_ctx, + ObString &udt_varray_buf, + ObSqlUDTMeta &udt_meta, + ObObj &res_obj); + + static int cast_sql_udt_attributes_to_pl_record(sql::ObExecContext *exec_ctx, + ObString *attrs, + int64_t &pos, + ObSqlUDTMeta &udt_meta, + ObSqlUdtNullBitMap &nest_udt_bitmap, + ObObj &res_obj); + + static int cast_sql_record_to_pl_record(sql::ObExecContext *exec_ctx, + ObObj &result, + ObString &udt_data, + ObSqlUDTMeta &udt_meta); + + static int get_sqludt_meta_by_subschema_id(sql::ObExecContext *exec_ctx, + const uint16_t subschema_id, + ObSqlUDTMeta &udt_meta); +}; + +class ObSqlUdtMetaUtils final +{ + +public: + static int get_udt_meta_attr_info(ObSchemaGetterGuard *schema_guard, + uint64_t tenant_id, + const ObUDTTypeInfo *parent_udt_info, + uint32_t &nested_udt_number, + common::ObIArray &leaf_attr_meta); + + static int fill_udt_meta_attr_info(ObSchemaGetterGuard *schema_guard, + ObSubSchemaCtx *subschema_ctx, + uint64_t tenant_id, + const common::ObIArray &src, + ObSqlUDTAttrMeta *dst, + const uint32 dst_cnt, + bool is_leaf); + + // get udttypeinfo from schema by tenant id and udt id, get child udt defines recursively + static int generate_udt_meta_from_schema(ObSchemaGetterGuard *schema_guard, + ObSubSchemaCtx *subschema_ctx, + common::ObIAllocator &allocator, + uint64_t tenant_id, + uint64_t udt_id, + ObSqlUDTMeta &udt_meta); +}; + +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_SQL_UDT_UTILS_H_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_st_area.cpp b/src/sql/engine/expr/ob_expr_st_area.cpp index c23872a969..ec36d7ff60 100644 --- a/src/sql/engine/expr/ob_expr_st_area.cpp +++ b/src/sql/engine/expr/ob_expr_st_area.cpp @@ -83,7 +83,7 @@ int ObExprSTArea::eval_st_area(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) LOG_WARN("fail to get real string data", K(ret), K(wkb)); } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb, srs, true, N_ST_AREA))) { LOG_WARN("fail to get srs item", K(ret), K(wkb)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb, geo, srs, N_ST_AREA))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb, geo, srs, N_ST_AREA, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("get geo by wkb failed", K(ret)); } else if (geo->type() != ObGeoType::POLYGON && geo->type() != ObGeoType::MULTIPOLYGON) { ret = OB_ERR_UNEXPECTED_GEOMETRY_TYPE; diff --git a/src/sql/engine/expr/ob_expr_st_asgeojson.cpp b/src/sql/engine/expr/ob_expr_st_asgeojson.cpp new file mode 100644 index 0000000000..4bbe3754b7 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_asgeojson.cpp @@ -0,0 +1,213 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_asgeojson. + */ +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_st_asgeojson.h" +#include "share/object/ob_obj_cast_util.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/json_type/ob_json_parse.h" +#include "observer/omt/ob_tenant_srs.h" +#include "lib/utility/ob_fast_convert.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "lib/geo/ob_wkb_to_json_visitor.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "sql/engine/expr/ob_expr_json_func_helper.h" +using namespace oceanbase::common; +using namespace oceanbase::sql; +namespace oceanbase +{ +namespace sql +{ +ObExprSTAsGeoJson::ObExprSTAsGeoJson(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_ST_ASGEOJSON, N_ST_ASGEOJSON, MORE_THAN_ZERO, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprSTAsGeoJson::~ObExprSTAsGeoJson() +{} + +int ObExprSTAsGeoJson::calc_result_typeN(ObExprResType &type, ObExprResType *types_stack, + int64_t param_num, ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + INIT_SUCC(ret); + if (OB_UNLIKELY(param_num > 3)) { + ObString func_name_(get_name()); + ret = OB_ERR_PARAM_SIZE; + LOG_USER_ERROR(OB_ERR_PARAM_SIZE, func_name_.length(), func_name_.ptr()); + } else { + for (uint8_t i = 0; i < param_num && OB_SUCC(ret); i++) { + ObObjType type = types_stack[i].get_type(); + if (i == 0) { + // geometry + if (!ob_is_geometry(type) && !ob_is_string_type(type) && !ob_is_null(type)) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid type for geometry", K(ret), K(type)); + } + } else { + if (!ob_is_integer_type(type) && !ob_is_null(type) + && !ob_is_varchar_char_type(type, types_stack[i].get_collation_type()) + && !ob_is_enum_or_set_type(type)) { + ret = OB_ERR_INVALID_TYPE_FOR_ARGUMENT; + LOG_WARN("invalid type", K(ret), K(type)); + } else { + types_stack[i].set_calc_type(ObIntType); + type_ctx.set_cast_mode(type_ctx.get_cast_mode() | CM_STRING_INTEGER_TRUNC); + } + } + } + } + if (OB_SUCC(ret)) { + type.set_json(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObJsonType]).get_length()); + } + return ret; +} + +int ObExprSTAsGeoJson::process_input_params(const ObExpr &expr, ObEvalCtx &ctx, + ObIAllocator &allocator, ObGeometry *&geo, bool &is_null_res, ObGeoSrid& srid, + uint32_t &max_dec_digits, uint8_t &flag) +{ + int ret = OB_SUCCESS; + // geometry + ObDatum *datum = nullptr; + ObExpr *arg1 = expr.args_[0]; + ObObjType type1 = arg1->datum_meta_.type_; + is_null_res = false; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs = nullptr; + if (ob_is_null(type1)) { + is_null_res = true; + } else if (OB_FAIL(arg1->eval(ctx, datum))) { + LOG_WARN("fail to eval args", K(ret)); + } else if (datum->is_null()) { + is_null_res = true; + } else { + // construct geometry + ObString wkb = datum->get_string(); + if (OB_FAIL(ObTextStringHelper::read_real_string_data( + allocator, *datum, arg1->datum_meta_, arg1->obj_meta_.has_lob_header(), wkb))) { + LOG_WARN("fail to read real string data", K(ret), K(arg1->obj_meta_.has_lob_header())); + } else if (OB_FAIL(ObGeoExprUtils::construct_geometry( + allocator, wkb, srs_guard, srs, geo, N_ST_ASGEOJSON))) { + LOG_WARN("fail to build geometry from wkb", K(ret), K(wkb)); + } else { + srid = ObGeoWkbByteOrderUtil::read(wkb.ptr(), ObGeoWkbByteOrder::LittleEndian); + } + } + // max_dec_digits + max_dec_digits = INT_MAX32; + if (!is_null_res && OB_SUCC(ret) && expr.arg_cnt_ > 1) { + if (OB_FAIL(expr.args_[1]->eval(ctx, datum))) { + LOG_WARN("failed to eval second argument", K(ret)); + } else if (datum->is_null()) { + is_null_res = true; + } else if (datum->get_int() < 0 || datum->get_int() > INT_MAX32) { + ret = OB_ERR_INCORRECT_VALUE_FOR_FUNCTION; + char flag_buf[ObFastFormatInt::MAX_DIGITS10_STR_SIZE] = {0}; + int32_t len = ObFastFormatInt::format_signed(datum->get_int(), flag_buf); + ObString string_type_str("max decimal digits"); + ObString func_str(N_ST_ASGEOJSON); + LOG_USER_ERROR(OB_ERR_INCORRECT_VALUE_FOR_FUNCTION, + string_type_str.length(), + string_type_str.ptr(), + len, + flag_buf, + func_str.length(), + func_str.ptr()); + LOG_WARN("Incorrect max decimal digits value for function st_asgeojson", K(ret), K(datum->get_int())); + } else { + max_dec_digits = datum->get_uint32(); + } + } + // flag + flag = 0; + if (!is_null_res && OB_SUCC(ret) && expr.arg_cnt_ > 2) { + if (OB_FAIL(expr.args_[2]->eval(ctx, datum))) { + LOG_WARN("failed to eval second argument", K(ret)); + } else if (datum->is_null()) { + is_null_res = true; + } else if (datum->get_int() < 0 || datum->get_int() > 7) { + ret = OB_ERR_INCORRECT_VALUE_FOR_FUNCTION; + char flag_buf[ObFastFormatInt::MAX_DIGITS10_STR_SIZE] = {0}; + int32_t len = ObFastFormatInt::format_signed(datum->get_int(), flag_buf); + ObString string_type_str("options"); + ObString func_str(N_ST_ASGEOJSON); + LOG_USER_ERROR(OB_ERR_INCORRECT_VALUE_FOR_FUNCTION, + string_type_str.length(), + string_type_str.ptr(), + len, + flag_buf, + func_str.length(), + func_str.ptr()); + LOG_WARN("Incorrect options value for function st_asgeojson", K(ret), K(datum->get_int())); + } else { + flag = datum->get_uint8(); + } + } + return ret; +} + +int ObExprSTAsGeoJson::eval_st_asgeojson(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_null_res = false; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + uint32_t max_dec_digits = UINT_MAX32; + uint8_t flag = 0; + ObGeometry *geo = nullptr; + ObString json_res; + ObGeoSrid srid = 0; + if (OB_FAIL(process_input_params( + expr, ctx, temp_allocator, geo, is_null_res, srid, max_dec_digits, flag))) { + LOG_WARN("fail to process input geometry", K(ret)); + } else if (!is_null_res) { + // cal asgeojson + ObWkbToJsonVisitor visitor(&temp_allocator, max_dec_digits, flag, srid); + if (OB_FAIL(geo->do_visit(visitor))) { + LOG_WARN("fail to do visit", K(ret)); + } else { + visitor.get_geojson(json_res); + } + } + uint32_t parse_flag = ObJsonParser::JSN_RELAXED_FLAG; + ObJsonNode *j_tree = NULL; + // set result + if (OB_FAIL(ret)) { + // do nothing + } else if (is_null_res) { + res.set_null(); + } else if (OB_FAIL(ObJsonParser::get_tree(&temp_allocator, json_res, j_tree, parse_flag))) { + LOG_WARN("fail to parse string as json", K(ret)); + } else { + ObIJsonBase *j_base = j_tree; + ObString raw_bin; + if (OB_FAIL(j_base->get_raw_binary(raw_bin, &temp_allocator))) { + LOG_WARN("fail to get string json binary", K(ret)); + } else if (OB_FAIL(ObJsonExprHelper::pack_json_str_res(expr, ctx, res, raw_bin))) { + LOG_WARN("fail to pack json result", K(ret)); + } + } + return ret; +} + +int ObExprSTAsGeoJson::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_st_asgeojson; + return OB_SUCCESS; +} +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_st_asgeojson.h b/src/sql/engine/expr/ob_expr_st_asgeojson.h new file mode 100644 index 0000000000..c8b395332c --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_asgeojson.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_asgeojson. + */ +#ifndef OCEANBASE_SQL_OB_EXPR_ST_ASGEOJSON_ +#define OCEANBASE_SQL_OB_EXPR_ST_ASGEOJSON_ +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" +using namespace oceanbase::common; +namespace oceanbase +{ +namespace sql +{ +class ObExprSTAsGeoJson : public ObFuncExprOperator +{ +public: + explicit ObExprSTAsGeoJson(common::ObIAllocator &alloc); + virtual ~ObExprSTAsGeoJson(); + virtual int calc_result_typeN(ObExprResType &type, ObExprResType *types, int64_t param_num, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_st_asgeojson(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int process_input_params(const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, + ObGeometry *&geo, bool &is_null_res, ObGeoSrid& srid, uint32_t &max_dec_digits, + uint8_t &flag); + DISALLOW_COPY_AND_ASSIGN(ObExprSTAsGeoJson); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_ASGEOJSON_ diff --git a/src/sql/engine/expr/ob_expr_st_astext.cpp b/src/sql/engine/expr/ob_expr_st_astext.cpp index 6cb62529c0..bccd731028 100755 --- a/src/sql/engine/expr/ob_expr_st_astext.cpp +++ b/src/sql/engine/expr/ob_expr_st_astext.cpp @@ -19,6 +19,7 @@ #include "lib/geo/ob_geo_reverse_coordinate_visitor.h" #include "lib/geo/ob_geo_to_wkt_visitor.h" #include "lib/geo/ob_geo_func_common.h" +#include "lib/geo/ob_geo_3d.h" using namespace oceanbase::common; using namespace oceanbase::sql; @@ -104,6 +105,7 @@ int ObExprSTAsText::eval_st_astext_common(const ObExpr &expr, bool need_reverse = false; ObDatum *gis_datum = NULL; ObString wkb; + bool is_3d_geo = false; // get geo if (OB_FAIL(expr.args_[0]->eval(ctx, gis_datum))) { LOG_WARN("eval geo args failed", K(ret)); @@ -167,23 +169,12 @@ int ObExprSTAsText::eval_st_astext_common(const ObExpr &expr, ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null geo", K(ret)); } else { - if (is_geog && need_reverse) { - ObGeoReverseCoordinateVisitor rcoord_visitor; - if (OB_FAIL(geo->do_visit(rcoord_visitor))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); - LOG_WARN("failed to reverse geometry coordinate", K(ret)); - } + if (is_geog && need_reverse && OB_FAIL(ObGeoExprUtils::reverse_coordinate(geo, func_name))) { + LOG_WARN("failed to reverse geometry coordinate", K(ret)); } - if (OB_FAIL(ret)) { - } else { - ObGeoToWktVisitor wkt_visitor(&tmp_allocator); - if (OB_FAIL(geo->do_visit(wkt_visitor))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); + if (OB_SUCC(ret)) { + if (OB_FAIL(to_wkt(tmp_allocator, geo, res_wkt, func_name))) { LOG_WARN("failed to transform geo to wkt", K(ret)); - } else { - wkt_visitor.get_wkt(res_wkt); } } } @@ -199,6 +190,30 @@ int ObExprSTAsText::eval_st_astext_common(const ObExpr &expr, return ret; } +int ObExprSTAsText::to_wkt(ObIAllocator &allocator, ObGeometry *geo, ObString &res_wkt, const char *func_name) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geo", K(ret)); + } else if (ObGeoTypeUtil::is_3d_geo_type(geo->type())) { + ObGeometry3D *geo_3d = static_cast(geo); + if (OB_FAIL(geo_3d->to_wkt(allocator, res_wkt))) { + LOG_WARN("fail to reserver coordiante in geo 3d", K(ret)); + } + } else { + ObGeoToWktVisitor wkt_visitor(&allocator); + if (OB_FAIL(geo->do_visit(wkt_visitor))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); + LOG_WARN("failed to transform geo to wkt", K(ret)); + } else { + wkt_visitor.get_wkt(res_wkt); + } + } + return ret; +} + int ObExprSTAsText::eval_st_astext(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) { return eval_st_astext_common(expr, ctx, res, N_ST_ASTEXT); diff --git a/src/sql/engine/expr/ob_expr_st_astext.h b/src/sql/engine/expr/ob_expr_st_astext.h index 6fa28d1e8a..1cc55a81d9 100644 --- a/src/sql/engine/expr/ob_expr_st_astext.h +++ b/src/sql/engine/expr/ob_expr_st_astext.h @@ -18,6 +18,10 @@ namespace oceanbase { +namespace common +{ +class ObGeometry; +} namespace sql { class ObExprSTAsText : public ObFuncExprOperator @@ -44,6 +48,7 @@ public: virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + static int to_wkt(ObIAllocator &allocator, ObGeometry *geo, ObString &res_wkt, const char *func_name); private: DISALLOW_COPY_AND_ASSIGN(ObExprSTAsText); }; diff --git a/src/sql/engine/expr/ob_expr_st_aswkb.cpp b/src/sql/engine/expr/ob_expr_st_aswkb.cpp index 3795813d19..7e4c35c59b 100644 --- a/src/sql/engine/expr/ob_expr_st_aswkb.cpp +++ b/src/sql/engine/expr/ob_expr_st_aswkb.cpp @@ -169,13 +169,8 @@ int ObExprGeomWkb::eval_geom_wkb(const ObExpr &expr, if (srid_default_ordering && is_geog && is_lat_long_order) { need_reverse = true; } - if (need_reverse && is_geog) { - ObGeoReverseCoordinateVisitor rcoord_visitor; - if (OB_FAIL(geo->do_visit(rcoord_visitor))) { - LOG_WARN("failed to reverse geometry coordinate", K(ret)); - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, get_func_name()); - } + if (need_reverse && is_geog && OB_FAIL(ObGeoExprUtils::reverse_coordinate(geo, get_func_name()))) { + LOG_WARN("failed to reverse geometry coordinate", K(ret)); } } diff --git a/src/sql/engine/expr/ob_expr_st_bestsrid.cpp b/src/sql/engine/expr/ob_expr_st_bestsrid.cpp index d8fd883bf1..644b5e798e 100644 --- a/src/sql/engine/expr/ob_expr_st_bestsrid.cpp +++ b/src/sql/engine/expr/ob_expr_st_bestsrid.cpp @@ -76,8 +76,9 @@ int ObExprPrivSTBestsrid::get_geog_box(ObEvalCtx &ctx, ObArenaAllocator &temp_al const ObSrsItem *srs = NULL; if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb, srs))) { LOG_WARN("get srs failed", K(ret), K(wkb)); - } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_wkb(temp_allocator, wkb, srs, geo))) { - LOG_WARN("get geo by wkb failed", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb, geo, srs, N_PRIV_ST_BESTSRID, + ObGeoBuildFlag::GEO_ALLOW_3D))) { + LOG_WARN("get geo failed", K(ret)); if (ret != OB_ERR_SRS_NOT_FOUND && ret != OB_ERR_INVALID_GEOMETRY_TYPE) { ret = OB_ERR_GIS_INVALID_DATA; LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_BESTSRID); diff --git a/src/sql/engine/expr/ob_expr_st_buffer.cpp b/src/sql/engine/expr/ob_expr_st_buffer.cpp index 64f217072a..11983a65c4 100644 --- a/src/sql/engine/expr/ob_expr_st_buffer.cpp +++ b/src/sql/engine/expr/ob_expr_st_buffer.cpp @@ -491,15 +491,16 @@ int ObExprSTBuffer::eval_st_buffer(const ObExpr &expr, ObEvalCtx &ctx, ObDatum & // Consist with mysql, return wkb(add version) if distance is too small. // However pg will return fixed geometry. ObString res_wkb; - if (OB_FAIL(ObGeoTypeUtil::create_geo_by_wkb(temp_allocator, geo_str, srs, geo))) { - LOG_WARN("get geo by wkb failed", K(ret), K(geo_str)); + if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, geo_str, + geo, srs, N_ST_BUFFER, ObGeoBuildFlag::GEO_ALLOW_3D))) { + LOG_WARN("parse wkb failed", K(ret), K(geo_str)); } else if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*geo, expr, ctx, srs, res_wkb))) { LOG_WARN("failed to write geometry to wkb", K(ret)); } else { res.set_string(res_wkb); } } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, geo_str, - geo, srs, N_ST_BUFFER))) { + geo, srs, N_ST_BUFFER, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("parse wkb failed", K(ret), K(geo_str)); } else if (OB_FAIL(ObGeoTypeUtil::get_srid_from_wkb(geo_str, srid))) { LOG_WARN("get type and srid from wkb failed", K(ret)); @@ -830,7 +831,8 @@ int ObExprPrivSTBuffer::eval_priv_st_buffer(const ObExpr &expr, ObEvalCtx &ctx, LOG_WARN("fail to get real string data", K(ret), K(geo_str)); } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, geo_str, srs, true))) { LOG_WARN("fail to get srs item", K(ret)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, geo_str, geo, srs, N_PRIV_ST_BUFFER, false, true))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, geo_str, geo, srs, N_PRIV_ST_BUFFER, + ObGeoBuildFlag::GEO_CHECK_RING | ObGeoBuildFlag::GEO_CORRECT | ObGeoBuildFlag::GEO_ALLOW_3D | ObGeoBuildFlag::GEO_CHECK_RANGE))) { LOG_WARN("parse wkb failed", K(ret), K(geo_str)); } else if (OB_FAIL(ObGeoTypeUtil::get_srid_from_wkb(geo_str, srid))) { LOG_WARN("get type and srid from wkb failed", K(ret)); diff --git a/src/sql/engine/expr/ob_expr_st_centroid.cpp b/src/sql/engine/expr/ob_expr_st_centroid.cpp new file mode 100644 index 0000000000..2079166315 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_centroid.cpp @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for st_valid. + */ + +#define USING_LOG_PREFIX SQL_ENG + +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_func_centroid.h" +#include "ob_expr_st_centroid.h" +#include "lib/geo/ob_srs_info.h" +#include "observer/omt/ob_tenant_srs.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +ObExprSTCentroid::ObExprSTCentroid(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_ST_CENTROID, N_ST_CENTROID, 1, VALID_FOR_GENERATED_COL, + NOT_ROW_DIMENSION) +{} + +int ObExprSTCentroid::calc_result_type1( + ObExprResType &type, ObExprResType &type1, common::ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + int ret = OB_SUCCESS; + if (ob_is_null(type1.get_type())) { + // do nothing + } else if (ob_is_numeric_type(type1.get_type())) { + type1.set_calc_type(ObLongTextType); + } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, get_name()); + } + if (OB_SUCC(ret)) { + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); + } + return ret; +} + +int ObExprSTCentroid::eval_st_centroid(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &tmp_allocator = tmp_alloc_g.get_allocator(); + ObDatum *datum = NULL; + bool is_null_result = false; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs = NULL; + ObGeometry *geo = NULL; + ObGeometry *res_geo = nullptr; + + if (OB_FAIL(expr.args_[0]->eval(ctx, datum))) { + LOG_WARN("failed to eval first argument", K(ret)); + } else if (datum->is_null()) { + is_null_result = true; + } else { + ObString wkb = datum->get_string(); + if (OB_FAIL(ObTextStringHelper::read_real_string_data(tmp_allocator, + *datum, + expr.args_[0]->datum_meta_, + expr.args_[0]->obj_meta_.has_lob_header(), + wkb))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb)); + } else if (OB_FAIL( + ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb, srs, true, N_ST_CENTROID))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(tmp_allocator, + wkb, + geo, + srs, + N_ST_CENTROID, + ObGeoBuildFlag::GEO_NORMALIZE | ObGeoBuildFlag::GEO_CHECK_RANGE))) { + LOG_WARN("failed to parse wkb", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo, is_null_result))) { + LOG_WARN("fail to check is geometry empty", K(ret)); + } else if (!is_null_result) { + bool is_valid = true; + if (geo->crs() == ObGeoCRS::Cartesian + && OB_FAIL((ObGeoTypeUtil::is_polygon_valid_simple(geo, is_valid)))) { + LOG_WARN("fail to check if geometry contain polygon", K(ret)); + } else if (geo->crs() == ObGeoCRS::Geographic + && OB_FAIL((ObGeoTypeUtil::is_polygon_valid_simple(geo, is_valid)))) { + LOG_WARN("fail to check if geometry contain polygon", K(ret)); + } else if (!is_valid) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_CENTROID); + LOG_WARN("input geometry is invalid", K(ret)); + } + ObGeoEvalCtx gis_context(&tmp_allocator, srs); + if (OB_FAIL(ret)) { + // do nothing + } else if (OB_FAIL(ObGeoTypeUtil::correct_polygon(tmp_allocator, srs, true, *geo))) { + LOG_WARN("correct geo failed", K(ret), K(geo)); + } else if (OB_FAIL(gis_context.append_geo_arg(geo))) { + LOG_WARN("build geo gis context failed", K(ret)); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, res_geo))) { + LOG_WARN("eval geo func centroid failed", K(ret), K(geo->type())); + if (ret == OB_ERR_BOOST_GEOMETRY_CENTROID_EXCEPTION) { + ret = OB_SUCCESS; + is_null_result = true; + } else { + ObGeoExprUtils::geo_func_error_handle(ret, N_ST_CENTROID); + } + } + } + } + + if (OB_SUCC(ret)) { + if (is_null_result) { + res.set_null(); + } else { + ObString res_wkb; + if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*res_geo, expr, ctx, srs, res_wkb, geo->get_srid()))) { + LOG_WARN("fail to get wkb from geometry", K(ret)); + } else { + res.set_string(res_wkb); + } + } + } + + return ret; +} + +int ObExprSTCentroid::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSEDx(expr_cg_ctx, raw_expr); + rt_expr.eval_func_ = eval_st_centroid; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_st_centroid.h b/src/sql/engine/expr/ob_expr_st_centroid.h new file mode 100644 index 0000000000..29c15c571d --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_centroid.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for st_centroid. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_CENTROID_ +#define OCEANBASE_SQL_OB_EXPR_ST_CENTROID_ + +#include "sql/engine/expr/ob_expr_operator.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprSTCentroid : public ObFuncExprOperator +{ +public: + explicit ObExprSTCentroid(common::ObIAllocator &alloc); + virtual ~ObExprSTCentroid() {} + virtual int calc_result_type1(ObExprResType &type, + ObExprResType &type1, + common::ObExprTypeCtx &type_ctx) + const override; + static int eval_st_centroid(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, + const ObRawExpr &raw_expr, + ObExpr &rt_expr) const override; +private: + DISALLOW_COPY_AND_ASSIGN(ObExprSTCentroid); +}; +} // sql +} // oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_CENTROID_ diff --git a/src/sql/engine/expr/ob_expr_st_contains.cpp b/src/sql/engine/expr/ob_expr_st_contains.cpp index 07e1fa6e9a..1fe9dd9835 100644 --- a/src/sql/engine/expr/ob_expr_st_contains.cpp +++ b/src/sql/engine/expr/ob_expr_st_contains.cpp @@ -46,33 +46,19 @@ int ObExprSTContains::calc_result_type2(ObExprResType &type, { UNUSED(type_ctx); INIT_SUCC(ret); - int unexpected_types = 0; - int null_types = 0; - if (type1.get_type() == ObNullType) { - null_types++; } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { - unexpected_types++; - LOG_WARN("invalid type", K(type1.get_type())); + type1.set_calc_type(ObVarcharType); + type1.set_calc_collation_type(CS_TYPE_BINARY); } if (type2.get_type() == ObNullType) { - null_types++; } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { - unexpected_types++; - LOG_WARN("invalid type", K(type2.get_type())); - } - // an invalid type and a null type will return null - // an invalid type and a valid type return error - if (null_types == 0 && unexpected_types > 0) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_CONTAINS); - LOG_WARN("invalid type", K(ret)); - } - if (OB_SUCC(ret)) { - type.set_int32(); - type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); - type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + type2.set_calc_type(ObVarcharType); + type2.set_calc_collation_type(CS_TYPE_BINARY); } + type.set_int32(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); return ret; } @@ -116,15 +102,18 @@ int ObExprSTContains::eval_st_contains(const ObExpr &expr, ObEvalCtx &ctx, ObDat } LOG_WARN("get type and srid from wkb failed", K(wkb1), K(ret)); } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb2, type2, srid2))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_CONTAINS); + } LOG_WARN("get type and srid from wkb failed", K(wkb2), K(ret)); } else if (srid1 != srid2) { LOG_WARN("srid not the same", K(srid1), K(srid2)); ret = OB_ERR_GIS_DIFFERENT_SRIDS; } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb1, srs, true, N_ST_CONTAINS))) { LOG_WARN("fail to get srs item", K(ret), K(wkb1)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_ST_CONTAINS))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_ST_CONTAINS, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("get first geo by wkb failed", K(ret)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_ST_CONTAINS))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_ST_CONTAINS, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("get second geo by wkb failed", K(ret)); } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo1, is_geo1_empty)) || OB_FAIL(ObGeoExprUtils::check_empty(geo2, is_geo2_empty))) { diff --git a/src/sql/engine/expr/ob_expr_st_covers.cpp b/src/sql/engine/expr/ob_expr_st_covers.cpp index 0285119e1c..5f1bdd67be 100644 --- a/src/sql/engine/expr/ob_expr_st_covers.cpp +++ b/src/sql/engine/expr/ob_expr_st_covers.cpp @@ -94,10 +94,10 @@ int ObExprPrivSTCovers::eval_st_covers_common(ObEvalCtx &ctx, } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb1, srs, true, N_PRIV_ST_COVERS))) { LOG_WARN("fail to get srs item", K(ret), K(wkb1)); } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_PRIV_ST_COVERS, - true, true))) { + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT | ObGeoBuildFlag::GEO_CHECK_RING))) { LOG_WARN("get first geo by wkb failed", K(ret)); } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_PRIV_ST_COVERS, - true, true))) { + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT | ObGeoBuildFlag::GEO_CHECK_RING))) { LOG_WARN("get second geo by wkb failed", K(ret)); } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo1, is_geo1_empty)) || OB_FAIL(ObGeoExprUtils::check_empty(geo2, is_geo2_empty))) { diff --git a/src/sql/engine/expr/ob_expr_st_crosses.cpp b/src/sql/engine/expr/ob_expr_st_crosses.cpp new file mode 100644 index 0000000000..a377f0d834 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_crosses.cpp @@ -0,0 +1,189 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_crosses. + */ + +#define USING_LOG_PREFIX SQL_ENG + +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_ibin.h" +#include "sql/engine/ob_exec_context.h" +#include "ob_expr_st_crosses.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ + +ObExprSTCrosses::ObExprSTCrosses(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_ST_CROSSES, N_ST_CROSSES, 2, + VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprSTCrosses::~ObExprSTCrosses() +{} + +int ObExprSTCrosses::calc_result_type2(ObExprResType &type, ObExprResType &type1, + ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + INIT_SUCC(ret); + if (type1.get_type() == ObNullType) { + } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { + type1.set_calc_type(ObVarcharType); + type1.set_calc_collation_type(CS_TYPE_BINARY); + } + if (type2.get_type() == ObNullType) { + } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { + type2.set_calc_type(ObVarcharType); + type2.set_calc_collation_type(CS_TYPE_BINARY); + } + type.set_int(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + return ret; +} + +int ObExprSTCrosses::process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, + ObIAllocator &allocator, ObGeometry *&geo1, ObGeometry *&geo2, bool &is_null_res, + const ObSrsItem *&srs) +{ + int ret = OB_SUCCESS; + ObDatum *gis_datum1 = NULL; + ObDatum *gis_datum2 = NULL; + ObExpr *gis_arg1 = expr.args_[0]; + ObExpr *gis_arg2 = expr.args_[1]; + ObObjType input_type1 = gis_arg1->datum_meta_.type_; + ObObjType input_type2 = gis_arg2->datum_meta_.type_; + is_null_res = false; + if (OB_FAIL(gis_arg1->eval(ctx, gis_datum1)) || OB_FAIL(gis_arg2->eval(ctx, gis_datum2))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum1->is_null() || gis_datum2->is_null()) { + is_null_res = true; + } else if (input_type1 == ObIntType || input_type2 == ObIntType) { + // bugfix 53283098, should allow int type in calc_result_type2 + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_CROSSES); + LOG_WARN("invalid type", K(ret), K(input_type1), K(input_type2)); + } else { + ObGeoType type1; + ObGeoType type2; + uint32_t srid1; + uint32_t srid2; + ObString wkb1 = gis_datum1->get_string(); + ObString wkb2 = gis_datum2->get_string(); + bool is_geo1_valid = false; + bool is_geo2_valid = false; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum1, + gis_arg1->datum_meta_, + gis_arg1->obj_meta_.has_lob_header(), + wkb1))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb1)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum2, + gis_arg2->datum_meta_, + gis_arg2->obj_meta_.has_lob_header(), + wkb2))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb2)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb1, type1, srid1))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_CROSSES); + } + LOG_WARN("get type and srid from wkb failed", K(wkb1), K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb2, type2, srid2))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_CROSSES); + } + LOG_WARN("get type and srid from wkb failed", K(wkb2), K(ret)); + } else if (srid1 != srid2) { + ret = OB_ERR_GIS_DIFFERENT_SRIDS; + LOG_WARN("srid not the same", K(ret), K(srid1), K(srid2)); + LOG_USER_ERROR(OB_ERR_GIS_DIFFERENT_SRIDS, N_ST_CROSSES, srid1, srid2); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb1, srs, true, N_ST_CROSSES))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb1)); + } else if (OB_FAIL( + ObGeoExprUtils::build_geometry(allocator, wkb1, geo1, srs, N_ST_CROSSES, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { + LOG_WARN("get first geo by wkb failed", K(ret)); + } else if (OB_FAIL( + ObGeoExprUtils::build_geometry(allocator, wkb2, geo2, srs, N_ST_CROSSES, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { + LOG_WARN("get second geo by wkb failed", K(ret)); + } + } + return ret; +} + +int ObExprSTCrosses::eval_st_crosses(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_geo1_empty = false; + bool is_geo2_empty = false; + ObGeometry *geo1 = NULL; + ObGeometry *geo2 = NULL; + bool is_null_res = false; + bool result = false; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs = NULL; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + if (OB_FAIL(process_input_geometry(srs_guard, expr, ctx, temp_allocator, geo1, geo2, is_null_res, srs))) { + LOG_WARN("fail to process input geometry", K(ret)); + } else if (is_null_res) { + // do nothing + } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo1, is_geo1_empty)) + || OB_FAIL(ObGeoExprUtils::check_empty(geo2, is_geo2_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_geo1_empty || is_geo2_empty) { + is_null_res = true; + } else if (OB_FAIL(ObGeoExprUtils::zoom_in_geos_for_relation(*geo1, *geo2))) { + LOG_WARN("zoom in geos failed", K(ret)); + } else { + ObGeoFuncResWithNull crosses_result; + ObGeoEvalCtx gis_context(&temp_allocator, srs); + if (OB_FAIL(gis_context.append_geo_arg(geo1)) || OB_FAIL(gis_context.append_geo_arg(geo2))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval( + gis_context, crosses_result))) { + LOG_WARN("eval st intersection failed", K(ret)); + ObGeoExprUtils::geo_func_error_handle(ret, N_ST_CROSSES); + } else if (crosses_result.is_null) { + is_null_res = true; + } else { + result = crosses_result.bret; + } + } + + if (OB_SUCC(ret)) { + if (is_null_res) { + res.set_null(); + } else { + res.set_bool(result); + } + } + return ret; +} + +int ObExprSTCrosses::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_st_crosses; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_st_crosses.h b/src/sql/engine/expr/ob_expr_st_crosses.h new file mode 100644 index 0000000000..c7db2d8815 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_crosses.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_crosses. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_CROSSES_H_ +#define OCEANBASE_SQL_OB_EXPR_ST_CROSSES_H_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" +#include "observer/omt/ob_tenant_srs.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprSTCrosses : public ObFuncExprOperator +{ +public: + explicit ObExprSTCrosses(common::ObIAllocator &alloc); + virtual ~ObExprSTCrosses(); + virtual int calc_result_type2(ObExprResType &type, ObExprResType &type1, ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_st_crosses(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, ObGeometry *&geo1, + ObGeometry *&geo2, bool &is_null_res, const ObSrsItem *&srs); + DISALLOW_COPY_AND_ASSIGN(ObExprSTCrosses); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_CROSSES_H_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_st_difference.cpp b/src/sql/engine/expr/ob_expr_st_difference.cpp new file mode 100644 index 0000000000..197f98e5ad --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_difference.cpp @@ -0,0 +1,261 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_difference. + */ + +#define USING_LOG_PREFIX SQL_ENG + +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_ibin.h" +#include "sql/engine/ob_exec_context.h" +#include "observer/omt/ob_tenant_srs.h" +#include "ob_expr_st_difference.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" +#include "lib/geo/ob_geo_elevation_visitor.h" +#include "lib/geo/ob_geo_func_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ + +ObExprSTDifference::ObExprSTDifference(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_ST_DIFFERENCE, N_ST_DIFFERENCE, 2, + VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprSTDifference::~ObExprSTDifference() +{} + +int ObExprSTDifference::calc_result_type2(ObExprResType &type, ObExprResType &type1, + ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + INIT_SUCC(ret); + if (type1.get_type() == ObNullType) { + } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { + type1.set_calc_type(ObVarcharType); + type1.set_calc_collation_type(CS_TYPE_BINARY); + } + if (type2.get_type() == ObNullType) { + } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { + type2.set_calc_type(ObVarcharType); + type2.set_calc_collation_type(CS_TYPE_BINARY); + } + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); + return ret; +} + +int ObExprSTDifference::process_input_geometry(const ObExpr &expr, ObEvalCtx &ctx, + ObIAllocator &allocator, ObGeometry *&geo1, ObGeometry *&geo2, bool &is_null_res, + const ObSrsItem *&srs) +{ + int ret = OB_SUCCESS; + ObDatum *gis_datum1 = nullptr; + ObDatum *gis_datum2 = nullptr; + ObExpr *gis_arg1 = expr.args_[0]; + ObExpr *gis_arg2 = expr.args_[1]; + ObObjType input_type1 = gis_arg1->datum_meta_.type_; + ObObjType input_type2 = gis_arg2->datum_meta_.type_; + is_null_res = false; + if (OB_FAIL(gis_arg1->eval(ctx, gis_datum1)) || OB_FAIL(gis_arg2->eval(ctx, gis_datum2))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum1->is_null() || gis_datum2->is_null()) { + is_null_res = true; + } else { + ObGeoType type1; + ObGeoType type2; + uint32_t srid1; + uint32_t srid2; + ObString wkb1 = gis_datum1->get_string(); + ObString wkb2 = gis_datum2->get_string(); + omt::ObSrsCacheGuard srs_guard; + bool is_geo1_valid = false; + bool is_geo2_valid = false; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum1, + gis_arg1->datum_meta_, + gis_arg1->obj_meta_.has_lob_header(), + wkb1))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb1)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum2, + gis_arg2->datum_meta_, + gis_arg2->obj_meta_.has_lob_header(), + wkb2))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb2)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb1, type1, srid1))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_DIFFERENCE); + } + LOG_WARN("get type and srid from wkb failed", K(wkb1), K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb2, type2, srid2))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_DIFFERENCE); + } + LOG_WARN("get type and srid from wkb failed", K(wkb2), K(ret)); + } else if (srid1 != srid2) { + ret = OB_ERR_GIS_DIFFERENT_SRIDS; + LOG_WARN("srid not the same", K(ret), K(srid1), K(srid2)); + LOG_USER_ERROR(OB_ERR_GIS_DIFFERENT_SRIDS, N_ST_DIFFERENCE, srid1, srid2); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb1, srs, true, N_ST_DIFFERENCE))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb1)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(allocator, + wkb1, + geo1, + srs, + N_ST_DIFFERENCE, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT | GEO_RESERVE_3D))) { + LOG_WARN("get first geo by wkb failed", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(allocator, + wkb2, + geo2, + srs, + N_ST_DIFFERENCE, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT | GEO_RESERVE_3D))) { + LOG_WARN("get second geo by wkb failed", K(ret)); + } + } + return ret; +} + +int ObExprSTDifference::eval_st_difference(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_geo1_empty = false; + bool is_geo2_empty = false; + ObGeometry *geo1_3d = nullptr; + ObGeometry *geo2_3d = nullptr; + bool is_null_res = false; + const ObSrsItem *srs = nullptr; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObGeometry *diff_res = nullptr; + bool is_empty_res = false; + if (OB_FAIL( + process_input_geometry(expr, ctx, temp_allocator, geo1_3d, geo2_3d, is_null_res, srs))) { + LOG_WARN("fail to process input geometry", K(ret)); + } else if (!is_null_res) { + ObGeometry *geo1 = nullptr; + ObGeometry *geo2 = nullptr; + bool is_3d_geo1 = ObGeoTypeUtil::is_3d_geo_type(geo1_3d->type()); + bool is_3d_geo2 = ObGeoTypeUtil::is_3d_geo_type(geo2_3d->type()); + if ((is_3d_geo1 && !is_3d_geo2) || (!is_3d_geo1 && is_3d_geo2)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("mixed dimension geometries", K(ret), K(is_3d_geo1), K(is_3d_geo2)); + } else if (is_3d_geo1) { + if (OB_FAIL(ObGeoTypeUtil::convert_geometry_3D_to_2D( + srs, temp_allocator, geo1_3d, ObGeoBuildFlag::GEO_DEFAULT, geo1))) { + LOG_WARN("fail to convert 3D geometry to 2D", K(ret)); + } + } else { + geo1 = geo1_3d; + } + if (OB_FAIL(ret)) { + } else if (is_3d_geo2) { + if (OB_FAIL(ObGeoTypeUtil::convert_geometry_3D_to_2D( + srs, temp_allocator, geo2_3d, ObGeoBuildFlag::GEO_DEFAULT, geo2))) { + LOG_WARN("fail to convert 3D geometry to 2D", K(ret)); + } + } else { + geo2 = geo2_3d; + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo1, is_geo1_empty)) + || OB_FAIL(ObGeoExprUtils::check_empty(geo2, is_geo2_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_geo1_empty) { + is_empty_res = true; + } else if (is_geo2_empty) { + ObGeoToTreeVisitor to_tree(&temp_allocator); + if (OB_FAIL(geo1->do_visit(to_tree))) { + LOG_WARN("fail to transfer geo1 to tree", K(ret)); + } else { + diff_res = to_tree.get_geometry(); + } + } else { + ObGeoEvalCtx gis_context(&temp_allocator, srs); + if (OB_FAIL(gis_context.append_geo_arg(geo1)) || OB_FAIL(gis_context.append_geo_arg(geo2))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL( + ObGeoFunc::geo_func::eval(gis_context, diff_res))) { + LOG_WARN("eval st difference failed", K(ret)); + ObGeoExprUtils::geo_func_error_handle(ret, N_ST_DIFFERENCE); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(diff_res, is_empty_res))) { + LOG_WARN("check geo empty failed", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (is_empty_res) { + // 2D return GEOMETRYCOLLECTION EMPTY, 3D return GEOMETRYCOLLECTION Z EMPTY + if (OB_FAIL(ObGeoExprUtils::create_3D_empty_collection(temp_allocator, geo1->get_srid(), is_3d_geo1, + geo1->crs() == ObGeoCRS::Geographic, diff_res))) { + LOG_WARN("fail to create 3D empty collection", K(ret)); + } + } else { + if (geo1->crs() == ObGeoCRS::Cartesian + && OB_FAIL(ObGeoFuncUtils::remove_duplicate_multi_geo(diff_res, temp_allocator, srs))) { + // should not do simplify in symdifference functor, it may affect + // ObGeoFuncUtils::ob_geo_gc_union + LOG_WARN("fail to simplify result", K(ret)); + } else if (geo1->crs() == ObGeoCRS::Geographic + && OB_FAIL(ObGeoFuncUtils::remove_duplicate_multi_geo(diff_res, temp_allocator, srs))) { + // should not do simplify in symdifference functor, it may affect + // ObGeoFuncUtils::ob_geo_gc_union + LOG_WARN("fail to simplify result", K(ret)); + } else if (is_3d_geo1 && is_3d_geo2) { + // populate Z coordinates + ObGeoElevationVisitor visitor(temp_allocator, srs); + ObGeometry *diff_res_bin = nullptr; + if (OB_FAIL(visitor.init(*geo1_3d, *geo2_3d))) { + LOG_WARN("fail to init elevation visitor", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(temp_allocator, diff_res, diff_res_bin, srs))) { + LOG_WARN("fail to do tree to bin", K(ret)); + } else if (OB_FAIL(diff_res_bin->do_visit(visitor))) { + LOG_WARN("fail to do elevation visitor", K(ret)); + } else if (OB_FAIL(visitor.get_geometry_3D(diff_res))) { + LOG_WARN("failed get geometry 3D", K(ret)); + } + } + } + } + + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res.set_null(); + } else { + ObString res_wkb; + if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*diff_res, expr, ctx, srs, res_wkb))) { + LOG_WARN("failed to write geometry to wkb", K(ret)); + } else { + res.set_string(res_wkb); + } + } + return ret; +} + +int ObExprSTDifference::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_st_difference; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_st_difference.h b/src/sql/engine/expr/ob_expr_st_difference.h new file mode 100644 index 0000000000..ccd8d57fdf --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_difference.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_difference. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_DIFFERENCE_H_ +#define OCEANBASE_SQL_OB_EXPR_ST_DIFFERENCE_H_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprSTDifference : public ObFuncExprOperator +{ +public: + explicit ObExprSTDifference(common::ObIAllocator &alloc); + virtual ~ObExprSTDifference(); + virtual int calc_result_type2(ObExprResType &type, ObExprResType &type1, ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_st_difference(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int process_input_geometry(const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, + ObGeometry *&geo1, ObGeometry *&geo2, bool &is_null_res, const ObSrsItem *&srs); + DISALLOW_COPY_AND_ASSIGN(ObExprSTDifference); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_DIFFERENCE_H_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_st_distance.cpp b/src/sql/engine/expr/ob_expr_st_distance.cpp index c9104aaba2..3d5da9956a 100644 --- a/src/sql/engine/expr/ob_expr_st_distance.cpp +++ b/src/sql/engine/expr/ob_expr_st_distance.cpp @@ -30,99 +30,6 @@ namespace oceanbase namespace sql { -struct ObGeoUnit -{ - const char *name; - double factor; -}; - -const ObGeoUnit ob_geo_units[] = { - // order by unit s, asc - { "British chain (Benoit 1895 A)", 20.1167824 }, - { "British chain (Benoit 1895 B)", 20.1167824943758 }, - { "British chain (Sears 1922 truncated)", 20.116756 }, - { "British chain (Sears 1922)", 20.1167651215526 }, - { "British foot (1865)", 0.304800833333333 }, - { "British foot (1936)", 0.3048007491 }, - { "British foot (Benoit 1895 A)", 0.304799733333333 }, - { "British foot (Benoit 1895 B)", 0.30479973476327077 }, - { "British foot (Sears 1922 truncated)", 0.304799333333333 }, - { "British foot (Sears 1922)", 0.304799471538676 }, - { "British link (Benoit 1895 A)", 0.201167824 }, - { "British link (Benoit 1895 B)", 0.201167824943758 }, - { "British link (Sears 1922 truncated)", 0.20116756 }, - { "British link (Sears 1922)", 0.201167651215526 }, - { "British yard (Benoit 1895 A)", 0.9143992 }, - { "British yard (Benoit 1895 B)", 0.914399204289812 }, - { "British yard (Sears 1922 truncated)", 0.914398 }, - { "British yard (Sears 1922)", 0.914398414616028 }, - { "centimetre", 0.01 }, - { "chain", 20.1168 }, - { "Clarke's chain", 20.1166195164 }, - { "Clarke's foot", 0.3047972654 }, - { "Clarke's link", 0.201166195164 }, - { "Clarke's yard", 0.9143917962 }, - { "fathom", 1.8288 }, - { "foot", 0.3048 }, - { "German legal metre", 1.0000135965 }, - { "Gold Coast foot", 0.304799710181508 }, - { "Indian foot", 0.304799510248146 }, - { "Indian foot (1937)", 0.30479841 }, - { "Indian foot (1962)", 0.3047996 }, - { "Indian foot (1975)", 0.3047995 }, - { "Indian yard", 0.91439853074444 }, - { "Indian yard (1937)", 0.91439523 }, - { "Indian yard (1962)", 0.9143988 }, - { "Indian yard (1975)", 0.9143985 }, - { "kilometre", 1000 }, - { "link", 0.201168 }, - { "metre", 1 }, - { "millimetre", 0.001 }, - { "nautical mile", 1852 }, - { "Statute mile", 1609.344 }, - { "US survey chain", 20.1168402336804 }, - { "US survey foot", 0.304800609601219 }, - { "US survey link", 0.201168402336804 }, - { "US survey mile", 1609.34721869443 }, - { "yard", 0.9144 } -}; - -static int ob_geo_find_unit(const ObGeoUnit *units, const ObString &name, double &factor) -{ - INIT_SUCC(ret); - int begin = 0; - int end = sizeof(ob_geo_units)/sizeof(ObGeoUnit) - 1; - bool is_found = false; - while (begin <= end && !is_found) { - int mid = begin + (end - begin) / 2; - const int cmp_len = MIN(strlen(units[mid].name), name.length()); - int cmp_res = strncasecmp(units[mid].name, name.ptr(), cmp_len); - if (cmp_res > 0) { - end = mid - 1; - } else if (cmp_res < 0) { - begin = mid + 1; - } else { - if (name.length() == strlen(units[mid].name)) { - is_found = true; - factor = units[mid].factor; - } else if (name.length() > strlen(units[mid].name)) { - begin = mid + 1; - } else { - end = mid - 1; - } - } - } - - if (!is_found) { - ret = OB_ERR_UNIT_NOT_FOUND; - char name_str[name.length() + 1]; - name_str[name.length()] = '\0'; - MEMCPY(name_str, name.ptr(), name.length()); - LOG_USER_ERROR(OB_ERR_UNIT_NOT_FOUND, name_str); - } - return ret; -} - ObExprSTDistance::ObExprSTDistance(ObIAllocator &alloc) : ObFuncExprOperator(alloc, T_FUN_SYS_ST_DISTANCE, N_ST_DISTANCE, TWO_OR_THREE, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) { @@ -139,47 +46,29 @@ int ObExprSTDistance::calc_result_typeN(ObExprResType& type, { UNUSED(type_ctx); INIT_SUCC(ret); - int unexpected_types = 0; - int null_types = 0; for (int64_t i = 0; i < 2; i++) { if (types_stack[i].get_type() == ObNullType) { - null_types++; } else if (!ob_is_geometry(types_stack[i].get_type()) - && !ob_is_string_type(types_stack[i].get_type())) { // first 2 params are geometries - unexpected_types++; - LOG_WARN("invalid type", K(types_stack[i].get_type())); - } else if (ob_is_string_type(types_stack[i].get_type())) { - // ToDo: fix later, not checking range - // String now can be check in parse_geometry - // types_stack[i].set_calc_type(ObGeometryType); - // types_stack[i].set_calc_collation_type(CS_TYPE_BINARY); - // types_stack[i].set_calc_collation_level(CS_LEVEL_IMPLICIT); + && !ob_is_string_type(types_stack[i].get_type()) + && ObDoubleType != types_stack[i].get_type()) { // first 2 params are geometries + types_stack[i].set_calc_type(ObVarcharType); + types_stack[i].set_calc_collation_type(CS_TYPE_BINARY); } } - const int unit_param_index = 2; if (param_num == 3) { - if (types_stack[unit_param_index].get_type() == ObNullType) { - null_types++; - } else if (!(ob_is_string_type(types_stack[unit_param_index].get_type()))) { - unexpected_types++; - LOG_WARN("invalid option param type", K(types_stack[unit_param_index].get_type())); + ObObjType param_type = types_stack[unit_param_index].get_type(); + if (ob_is_string_type(param_type)) { + types_stack[unit_param_index].set_calc_collation_type(CS_TYPE_BINARY); } else { - types_stack[unit_param_index].set_calc_collation_type(CS_TYPE_UTF8MB4_BIN); + types_stack[unit_param_index].set_calc_type(ObVarcharType); + types_stack[unit_param_index].set_calc_collation_type(CS_TYPE_BINARY); } } - // an invalid type and a null type will return null - // an invalid type and a valid type return error - if (null_types == 0 && unexpected_types > 0) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_DISTANCE); - LOG_WARN("invalid type", K(ret)); - } if (OB_SUCC(ret)) { type.set_double(); } - return ret; } @@ -190,6 +79,8 @@ int ObExprSTDistance::eval_st_distance(const ObExpr &expr, ObEvalCtx &ctx, ObDat ObDatum *gis_datum2 = NULL; ObExpr *gis_arg1 = expr.args_[0]; ObExpr *gis_arg2 = expr.args_[1]; + ObObjType input_type1 = gis_arg1->datum_meta_.type_; + ObObjType input_type2 = gis_arg2->datum_meta_.type_; ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); @@ -197,7 +88,12 @@ int ObExprSTDistance::eval_st_distance(const ObExpr &expr, ObEvalCtx &ctx, ObDat LOG_WARN("eval geo args failed", K(ret)); } else if (gis_datum1->is_null() || gis_datum2->is_null()) { res.set_null(); - } else { + } else if (input_type1 == ObDoubleType || input_type2 == ObDoubleType) { + // bugfix 53283098, should allow double type in calc_result_type2 + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_DISTANCE); + LOG_WARN("invalid type", K(ret), K(input_type1), K(input_type2)); + } else { bool is_geo1_empty = false; bool is_geo2_empty = false; ObGeometry *geo1 = NULL; @@ -219,9 +115,9 @@ int ObExprSTDistance::eval_st_distance(const ObExpr &expr, ObEvalCtx &ctx, ObDat LOG_WARN("fail to get real string data", K(ret), K(wkb2)); } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb1, srs, true, N_ST_DISTANCE))) { LOG_WARN("fail to get srs item", K(ret), K(wkb1)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_ST_DISTANCE))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_ST_DISTANCE, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("get first geo by wkb failed", K(ret)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_ST_DISTANCE))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_ST_DISTANCE, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("get second geo by wkb failed", K(ret)); } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb1, type1, srid1))) { LOG_WARN("get type and srid from wkb failed", K(wkb1), K(ret)); @@ -256,22 +152,17 @@ int ObExprSTDistance::eval_st_distance(const ObExpr &expr, ObEvalCtx &ctx, ObDat LOG_WARN("eval geo unit arg failed", K(ret)); } else if (gis_unit->is_null()) { res.set_null(); - } else if (srid1 == 0) { - ret = OB_ERR_GEOMETRY_IN_UNKNOWN_LENGTH_UNIT; - char name_str[gis_unit->get_string().length() + 1]; - name_str[gis_unit->get_string().length()] = '\0'; - MEMCPY(name_str, gis_unit->get_string().ptr(), gis_unit->get_string().length()); - LOG_USER_ERROR(OB_ERR_GEOMETRY_IN_UNKNOWN_LENGTH_UNIT, N_ST_DISTANCE, name_str); - } else if (OB_FAIL(ob_geo_find_unit(ob_geo_units, gis_unit->get_string(), factor))) { - LOG_WARN("invalid geo unit name", K(ret), K(gis_unit->get_string())); + } else if (OB_FAIL(ObGeoExprUtils::length_unit_conversion(gis_unit->get_string(), srs, result, result))) { + LOG_WARN("fail to do unit conversion", K(ret), K(result)); + } else if (std::isinf(result)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_DISTANCE); } else { - result = result * (srs->linear_uint() / factor); - if (std::isinf(result)) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_DISTANCE); - } res.set_double(result); } + } else if (std::isinf(result)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_DISTANCE); } else { res.set_double(result); } diff --git a/src/sql/engine/expr/ob_expr_st_distance_sphere.cpp b/src/sql/engine/expr/ob_expr_st_distance_sphere.cpp index 91721ff756..7e9fdfaf2c 100644 --- a/src/sql/engine/expr/ob_expr_st_distance_sphere.cpp +++ b/src/sql/engine/expr/ob_expr_st_distance_sphere.cpp @@ -124,7 +124,7 @@ int ObExprSTDistanceSphere::eval_st_distance_sphere(const ObExpr &expr, true, N_ST_DISTANCE_SPHERE))) { LOG_WARN("fail to get srs1 item", K(ret), K(wkb1_copy)); } else if (OB_FAIL(ObGeoExprUtils::build_geometry(tmp_allocator, wkb1_copy, - g1, srs1, N_ST_DISTANCE_SPHERE))) { + g1, srs1, N_ST_DISTANCE_SPHERE, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("fail to create geo1", K(ret), K(wkb1_copy)); } else if (OB_FAIL(ob_write_string(tmp_allocator, wkb2, wkb2_copy))) { LOG_WARN("fail to copy wkb2", K(ret), K(wkb2)); @@ -132,7 +132,7 @@ int ObExprSTDistanceSphere::eval_st_distance_sphere(const ObExpr &expr, true, N_ST_DISTANCE_SPHERE))) { LOG_WARN("fail to get srs2 item", K(ret), K(wkb2_copy)); } else if (OB_FAIL(ObGeoExprUtils::build_geometry(tmp_allocator, wkb2_copy, - g2, srs2, N_ST_DISTANCE_SPHERE))) { + g2, srs2, N_ST_DISTANCE_SPHERE, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("fail to create geo2", K(ret), K(wkb2_copy)); } else { srid1 = OB_ISNULL(srs1) ? 0:srs1->get_srid(); diff --git a/src/sql/engine/expr/ob_expr_st_dwithin.cpp b/src/sql/engine/expr/ob_expr_st_dwithin.cpp index 3520a13d54..8d569a84bf 100644 --- a/src/sql/engine/expr/ob_expr_st_dwithin.cpp +++ b/src/sql/engine/expr/ob_expr_st_dwithin.cpp @@ -46,37 +46,22 @@ int ObExprPrivSTDWithin::calc_result_type3(ObExprResType &type, { UNUSED(type_ctx); int ret = OB_SUCCESS; - int unexpected_types = 0; - int null_types = 0; - if (input1.get_type() == ObNullType) { - null_types++; } else if (!ob_is_geometry(input1.get_type()) && !ob_is_string_type(input1.get_type())) { - unexpected_types++; - LOG_WARN("invalid type", K(input1.get_type())); + input1.set_calc_type(ObVarcharType); + input1.set_calc_collation_type(CS_TYPE_BINARY); } if (input2.get_type() == ObNullType) { - null_types++; } else if (!ob_is_geometry(input2.get_type()) && !ob_is_string_type(input2.get_type())) { - unexpected_types++; - LOG_WARN("invalid type", K(input2.get_type())); + input2.set_calc_type(ObVarcharType); + input2.set_calc_collation_type(CS_TYPE_BINARY); } - // an invalid type and a null type will return null - // an invalid type and a valid type return error - if (null_types == 0 && unexpected_types > 0) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_DWITHIN); - LOG_WARN("invalid type", K(ret)); - } - - if (OB_SUCC(ret)) { - if (!ob_is_double_type(input3.get_type())) { - input3.set_calc_type(ObDoubleType); - } - type.set_int32(); - type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); - type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + if (!ob_is_double_type(input3.get_type())) { + input3.set_calc_type(ObDoubleType); } + type.set_int32(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); return ret; } @@ -114,18 +99,23 @@ int ObExprPrivSTDWithin::eval_st_dwithin_common(ObEvalCtx &ctx, } } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb2, type2, srid2))) { LOG_WARN("get type and srid from wkb failed", K(wkb2), K(ret)); + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_DWITHIN); + } } else if (srid1 != srid2) { ret = OB_ERR_GIS_DIFFERENT_SRIDS; LOG_WARN("srid not the same", K(srid1), K(srid2), K(ret)); } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb1, srs))) { LOG_WARN("fail to get srs item", K(ret), K(wkb1)); - } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_wkb(temp_allocator, wkb1, srs, geo1))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_PRIV_ST_TRANSFORM, + ObGeoBuildFlag::GEO_ALLOW_3D))) { LOG_WARN("get first geo by wkb failed", K(ret)); if (ret != OB_ERR_SRS_NOT_FOUND && ret != OB_ERR_INVALID_GEOMETRY_TYPE) { ret = OB_ERR_GIS_INVALID_DATA; LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_DWITHIN); } - } else if (OB_FAIL(ObGeoTypeUtil::create_geo_by_wkb(temp_allocator, wkb2, srs, geo2))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_PRIV_ST_TRANSFORM, + ObGeoBuildFlag::GEO_ALLOW_3D))) { LOG_WARN("get second geo by wkb failed", K(ret)); if (ret != OB_ERR_SRS_NOT_FOUND && ret != OB_ERR_INVALID_GEOMETRY_TYPE) { ret = OB_ERR_GIS_INVALID_DATA; diff --git a/src/sql/engine/expr/ob_expr_st_geomfromewkb.cpp b/src/sql/engine/expr/ob_expr_st_geomfromewkb.cpp index c82408eb4d..0954d6c764 100644 --- a/src/sql/engine/expr/ob_expr_st_geomfromewkb.cpp +++ b/src/sql/engine/expr/ob_expr_st_geomfromewkb.cpp @@ -20,6 +20,7 @@ #include "lib/geo/ob_geo_wkb_check_visitor.h" #include "lib/geo/ob_geo_to_tree_visitor.h" #include "lib/geo/ob_geo_func_common.h" +#include "lib/geo/ob_geo_3d.h" #include "observer/omt/ob_tenant_srs.h" using namespace oceanbase::common; @@ -84,7 +85,7 @@ int ObExprPrivSTGeomFromEWKB::eval_st_geomfromewkb(const ObExpr &expr, ObEvalCtx ObGeometry *geo_tree = NULL; bool need_reverse = false; bool is_geographical = false; - + bool is_3d_geo = false; // get ewkb if (OB_FAIL(expr.args_[0]->eval(ctx, datum))) { LOG_WARN("failed to eval first argument", K(ret)); @@ -116,6 +117,7 @@ int ObExprPrivSTGeomFromEWKB::eval_st_geomfromewkb(const ObExpr &expr, ObEvalCtx ret = OB_ERR_GIS_INVALID_DATA; LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_GEOMFROMEWKB); } + } else if (FALSE_IT(is_3d_geo = ObGeoTypeUtil::is_3d_geo_type(geo->type()))) { } else if (OB_NOT_NULL(srs)) { is_geographical = srs->is_geographical_srs(); } @@ -139,13 +141,8 @@ int ObExprPrivSTGeomFromEWKB::eval_st_geomfromewkb(const ObExpr &expr, ObEvalCtx } if (!is_null_result && OB_SUCC(ret)) { - if (need_reverse) { - ObGeoReverseCoordinateVisitor reverse_visitor; - if (OB_FAIL(geo->do_visit(reverse_visitor))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_PRIV_ST_GEOMFROMEWKB); - LOG_WARN("failed to reverse geometry coordinate", K(ret)); - } + if (need_reverse && OB_FAIL(ObGeoExprUtils::reverse_coordinate(geo, N_PRIV_ST_GEOMFROMEWKB))) { + LOG_WARN("failed to reverse geometry coordinate", K(ret)); } if (OB_SUCC(ret) && is_geographical) { @@ -185,7 +182,7 @@ int ObExprPrivSTGeomFromEWKB::get_header_info_from_ewkb(const ObString &ewkb, header.bo_ = static_cast(*(ewkb.ptr())); char *ptr = const_cast(ewkb.ptr() + WKB_GEO_BO_SIZE); uint32_t wkb_type = ObGeoWkbByteOrderUtil::read(ptr, header.bo_); - if (wkb_type & ObGeoTypeUtil::EWKB_M_FLAG || wkb_type & ObGeoTypeUtil::EWKB_Z_FLAG) { + if (wkb_type & ObGeoTypeUtil::EWKB_M_FLAG) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid ewkb type, higher than two dimension is not supported", K(ewkb.length()), K(wkb_type)); } else { @@ -194,6 +191,7 @@ int ObExprPrivSTGeomFromEWKB::get_header_info_from_ewkb(const ObString &ewkb, ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid ewkb length", K(ewkb.length()), K(wkb_type)); } else { + uint32_t offset = wkb_type & ObGeoTypeUtil::EWKB_Z_FLAG ? ObGeoTypeUtil::WKB_3D_TYPE_OFFSET : 0; wkb_type &= 0x0FFFFFFF; if (wkb_type >= 4000) { ret = OB_INVALID_ARGUMENT; @@ -204,7 +202,7 @@ int ObExprPrivSTGeomFromEWKB::get_header_info_from_ewkb(const ObString &ewkb, ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid ewkb type", K(ewkb.length()), K(wkb_type)); } else { - header.type_ = static_cast(wkb_type); + header.type_ = static_cast(wkb_type + offset); } } if (OB_SUCC(ret) && has_srid) { @@ -279,15 +277,22 @@ int ObExprPrivSTGeomFromEWKB::create_geo_by_ewkb(ObIAllocator &allocator, } else { geo->set_data(ewkb_data); geo->set_srid(header.srid_); - ObGeoWkbCheckVisitor ewkb_check(ewkb_data, header.bo_); - ObIWkbGeometry *geo_bin = static_cast(geo); - if (OB_FAIL(geo->do_visit(ewkb_check))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("fail to do ewkb check by wkb checker", K(ret), K(ewkb_data), K(header), K(crs)); - } else if (geo_bin->length() != ewkb_data.length() - && (geo_bin->length() + WKB_GEO_SRID_SIZE != ewkb.length())) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("invalid ewkb length", K(ewkb_data.length()), K(geo_bin->length()), K(header)); + if (ObGeoTypeUtil::is_3d_geo_type(header.type_)) { + ObGeometry3D *geo_3d = static_cast(geo); + if (OB_FAIL(geo_3d->check_wkb_valid())) { + LOG_WARN("fail to check geo 3d is valid", K(ret)); + } + } else { + ObGeoWkbCheckVisitor ewkb_check(ewkb_data, header.bo_); + ObIWkbGeometry *geo_bin = static_cast(geo); + if (OB_FAIL(geo->do_visit(ewkb_check))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("fail to do ewkb check by wkb checker", K(ret), K(ewkb_data), K(header), K(crs)); + } else if (geo_bin->length() != ewkb_data.length() + && (geo_bin->length() + WKB_GEO_SRID_SIZE != ewkb.length())) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid ewkb length", K(ewkb_data.length()), K(geo_bin->length()), K(header)); + } } } } diff --git a/src/sql/engine/expr/ob_expr_st_geomfromewkt.cpp b/src/sql/engine/expr/ob_expr_st_geomfromewkt.cpp index 6b377c9b2a..b1abf6c4a3 100644 --- a/src/sql/engine/expr/ob_expr_st_geomfromewkt.cpp +++ b/src/sql/engine/expr/ob_expr_st_geomfromewkt.cpp @@ -70,6 +70,7 @@ int ObExprPrivSTGeomFromEwkt::eval_st_geomfromewkt(const ObExpr &expr, ObEvalCtx ObSQLSessionInfo *session = ctx.exec_ctx_.get_my_session(); ObGeometry *geo = NULL; bool is_geog = false; + bool is_3d_geo = false; // get wkt if (OB_FAIL(expr.args_[0]->eval(ctx, datum))) { diff --git a/src/sql/engine/expr/ob_expr_st_geomfromtext.cpp b/src/sql/engine/expr/ob_expr_st_geomfromtext.cpp index 18ec1e83ec..4653cf976d 100644 --- a/src/sql/engine/expr/ob_expr_st_geomfromtext.cpp +++ b/src/sql/engine/expr/ob_expr_st_geomfromtext.cpp @@ -64,8 +64,8 @@ int ObExprSTGeomFromText::calc_result_typeN(ObExprResType& type, if (ob_is_null(types_stack[i].get_type())) { } else if (!ob_is_string_type(types_stack[i].get_type()) || ObCharset::is_cs_nonascii(types_stack[i].get_collation_type())) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, get_name()); + types_stack[i].set_calc_type(common::ObVarcharType); + types_stack[i].set_calc_collation_type(CS_TYPE_BINARY); } } // srid @@ -109,6 +109,7 @@ int ObExprSTGeomFromText::eval_st_geomfromtext_common(const ObExpr &expr, bool is_lat_long = false; bool is_geog = false; bool need_reverse = false; + bool is_3d_geo = false; // get wkt if (OB_FAIL(expr.args_[0]->eval(ctx, datum))) { @@ -189,15 +190,11 @@ int ObExprSTGeomFromText::eval_st_geomfromtext_common(const ObExpr &expr, LOG_WARN("failed to parse wkt", K(ret)); } else if (OB_ISNULL(geo)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected null geo afer parse_wkt", K(ret), K(wkt)); + LOG_WARN("unexpected null geo after parse_wkt", K(ret), K(wkt)); } else { - if (is_geog && need_reverse) { - ObGeoReverseCoordinateVisitor rcoord_visitor; - if (OB_FAIL(geo->do_visit(rcoord_visitor))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); - LOG_WARN("failed to reverse geometry coordinate", K(ret)); - } + is_3d_geo = ObGeoTypeUtil::is_3d_geo_type(geo->type()); + if (is_geog && need_reverse && OB_FAIL(ObGeoExprUtils::reverse_coordinate(geo, func_name))) { + LOG_WARN("failed to reverse geometry coordinate", K(ret)); } if (is_geog && OB_SUCC(ret)) { if (OB_FAIL(ObGeoExprUtils::check_coordinate_range(srs_item, geo, func_name))) { diff --git a/src/sql/engine/expr/ob_expr_st_geomfromwkb.cpp b/src/sql/engine/expr/ob_expr_st_geomfromwkb.cpp index 486e7a6c9d..c3f13d846b 100644 --- a/src/sql/engine/expr/ob_expr_st_geomfromwkb.cpp +++ b/src/sql/engine/expr/ob_expr_st_geomfromwkb.cpp @@ -18,7 +18,9 @@ #include "lib/geo/ob_geo_reverse_coordinate_visitor.h" #include "lib/geo/ob_geo_to_tree_visitor.h" #include "lib/geo/ob_geo_wkb_check_visitor.h" +#include "lib/geo/ob_wkb_byte_order_visitor.h" #include "lib/geo/ob_geo_func_common.h" +#include "lib/geo/ob_geo_3d.h" #include "observer/omt/ob_tenant_srs.h" using namespace oceanbase::common; @@ -63,8 +65,8 @@ int ObIExprSTGeomFromWKB::calc_result_typeN(ObExprResType& type, if (ob_is_null(types_stack[i].get_type())) { } else if (!ob_is_string_type(types_stack[i].get_type()) || ObCharset::is_cs_nonascii(types_stack[i].get_collation_type())) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, get_name()); + types_stack[i].set_calc_type(ObVarcharType); + types_stack[i].set_calc_collation_type(CS_TYPE_BINARY); } } // srid @@ -111,7 +113,7 @@ int ObIExprSTGeomFromWKB::eval_geom_wkb(const ObExpr &expr, ObEvalCtx &ctx, ObDa bool is_lat_long = false; ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian; uint32_t srid = 0; - + bool is_3d_geo = false; // get srid if (num_args > 1) { expr.args_[1]->eval(ctx, datum); @@ -175,21 +177,17 @@ int ObIExprSTGeomFromWKB::eval_geom_wkb(const ObExpr &expr, ObEvalCtx &ctx, ObDa } if (OB_SUCC(ret)) { geo->set_srid(srid); + is_3d_geo = ObGeoTypeUtil::is_3d_geo_type(geo->type()); } } } if (!is_null_result && OB_SUCC(ret)) { - if (need_reverse && is_geographical) { - ObGeoReverseCoordinateVisitor reverse_visitor; - if (OB_FAIL(geo->do_visit(reverse_visitor))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, get_func_name()); - LOG_WARN("failed to reverse geometry coordinate", K(ret)); - } + if (need_reverse && is_geographical && OB_FAIL(ObGeoExprUtils::reverse_coordinate(geo, get_func_name()))) { + LOG_WARN("failed to reverse geometry coordinate", K(ret)); } - if (bo == ObGeoWkbByteOrder::BigEndian) { + if (OB_SUCC(ret) && !is_3d_geo && bo == ObGeoWkbByteOrder::BigEndian) { ObGeoToTreeVisitor tree_visitor(&tmp_allocator); if (OB_FAIL(geo->do_visit(tree_visitor))) { LOG_WARN("fail to do visit", K(ret), K(geo->type())); @@ -198,7 +196,7 @@ int ObIExprSTGeomFromWKB::eval_geom_wkb(const ObExpr &expr, ObEvalCtx &ctx, ObDa } } - if (OB_SUCC(ret) && is_geographical) { + if (OB_SUCC(ret)&& is_geographical) { if (OB_FAIL(ObGeoExprUtils::check_coordinate_range(srs_item, geo, get_func_name()))) { LOG_WARN("check geo coordinate range failed", K(ret)); } @@ -256,14 +254,31 @@ int ObIExprSTGeomFromWKB::create_by_wkb_without_srid(ObIAllocator &allocator, geo->set_srid(srid); ObString wkb_nosrid(wkb.length(), wkb.ptr()); geo->set_data(wkb_nosrid); - ObGeoWkbCheckVisitor wkb_check(wkb_nosrid, bo); - ObIWkbGeometry *geo_bin = static_cast(geo); - if (OB_FAIL(geo->do_visit(wkb_check))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("invalid wkb", K(wkb), K(type), K(srid), K(crs)); - } else if (geo_bin->length() != wkb.length()) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_WARN("invalid wkb", K(wkb.length()), K(geo_bin->length()), K(type), K(srid), K(crs)); + if (ObGeoTypeUtil::is_3d_geo_type(geo->type())) { + ObGeometry3D *geo_3d = static_cast(geo); + if (OB_FAIL(geo_3d->check_wkb_valid())) { + LOG_WARN("invalid wkb", K(ret), K(type), K(srid), K(crs)); + } + } else { + ObGeoWkbCheckVisitor wkb_check(wkb_nosrid, bo); + ObIWkbGeometry *geo_bin = static_cast(geo); + if (OB_FAIL(geo->do_visit(wkb_check))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid wkb", K(wkb), K(type), K(srid), K(crs)); + } else if (bo == ObGeoWkbByteOrder::BigEndian) { + // transform to LittleEndian + ObWkbByteOrderVisitor bo_visitor(&allocator, ObGeoWkbByteOrder::LittleEndian); + if (OB_FAIL(geo->do_visit(bo_visitor))) { + LOG_WARN("fail to transform big endian to little endian", K(ret)); + } else { + geo->set_data(bo_visitor.get_wkb()); + bo = ObGeoWkbByteOrder::LittleEndian; + } + } + if (OB_SUCC(ret) && geo_bin->length() != wkb.length()) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid wkb", K(wkb.length()), K(geo_bin->length()), K(type), K(srid), K(crs)); + } } } } diff --git a/src/sql/engine/expr/ob_expr_st_intersects.cpp b/src/sql/engine/expr/ob_expr_st_intersects.cpp index 2b765c1886..8eee47d38b 100644 --- a/src/sql/engine/expr/ob_expr_st_intersects.cpp +++ b/src/sql/engine/expr/ob_expr_st_intersects.cpp @@ -45,33 +45,19 @@ int ObExprSTIntersects::calc_result_type2(ObExprResType &type, { UNUSED(type_ctx); INIT_SUCC(ret); - int unexpected_types = 0; - int null_types = 0; - if (type1.get_type() == ObNullType) { - null_types++; } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { - unexpected_types++; - LOG_WARN("invalid type", K(type1.get_type())); + type1.set_calc_type(ObVarcharType); + type1.set_calc_collation_type(CS_TYPE_BINARY); } if (type2.get_type() == ObNullType) { - null_types++; } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { - unexpected_types++; - LOG_WARN("invalid type", K(type2.get_type())); - } - // an invalid type and a null type will return null - // an invalid type and a valid type return error - if (null_types == 0 && unexpected_types > 0) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_INTERSECTS); - LOG_WARN("invalid type", K(ret)); - } - if (OB_SUCC(ret)) { - type.set_int32(); - type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); - type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + type2.set_calc_type(ObVarcharType); + type2.set_calc_collation_type(CS_TYPE_BINARY); } + type.set_int32(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); return ret; } @@ -117,15 +103,18 @@ int ObExprSTIntersects::eval_st_intersects(const ObExpr &expr, ObEvalCtx &ctx, O } LOG_WARN("get type and srid from wkb failed", K(wkb1), K(ret)); } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb2, type2, srid2))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_INTERSECTS); + } LOG_WARN("get type and srid from wkb failed", K(wkb2), K(ret)); } else if (srid1 != srid2) { LOG_WARN("srid not the same", K(srid1), K(srid2)); ret = OB_ERR_GIS_DIFFERENT_SRIDS; } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb1, srs, true, N_ST_INTERSECTS))) { LOG_WARN("fail to get srs item", K(ret), K(wkb1)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_ST_INTERSECTS))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_ST_INTERSECTS, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("get first geo by wkb failed", K(ret)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_ST_INTERSECTS))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_ST_INTERSECTS, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("get second geo by wkb failed", K(ret)); } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo1, is_geo1_empty)) || OB_FAIL(ObGeoExprUtils::check_empty(geo2, is_geo2_empty))) { diff --git a/src/sql/engine/expr/ob_expr_st_isvalid.cpp b/src/sql/engine/expr/ob_expr_st_isvalid.cpp index 0c58c8db1b..0a34ee49c2 100644 --- a/src/sql/engine/expr/ob_expr_st_isvalid.cpp +++ b/src/sql/engine/expr/ob_expr_st_isvalid.cpp @@ -80,7 +80,7 @@ int ObExprSTIsValid::eval_st_isvalid(const ObExpr &expr, ObEvalCtx &ctx, ObDatum LOG_WARN("fail to get real string data", K(ret), K(wkb)); } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb, srs, true, N_ST_ISVALID))) { LOG_WARN("fail to get srs item", K(ret), K(wkb)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(tmp_allocator, wkb, geo, srs, N_ST_ISVALID))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(tmp_allocator, wkb, geo, srs, N_ST_ISVALID, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("failed to parse wkb", K(ret)); } } diff --git a/src/sql/engine/expr/ob_expr_st_length.cpp b/src/sql/engine/expr/ob_expr_st_length.cpp new file mode 100644 index 0000000000..c9e83d31ee --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_length.cpp @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_length. + */ +#define USING_LOG_PREFIX SQL_ENG +#include "sql/engine/expr/ob_expr_st_length.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "share/object/ob_obj_cast_util.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_func_register.h" +#include "observer/omt/ob_tenant_srs.h" +using namespace oceanbase::common; +using namespace oceanbase::sql; +namespace oceanbase +{ +namespace sql +{ +ObExprSTLength::ObExprSTLength(common::ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_ST_LENGTH, N_ST_LENGTH, ONE_OR_TWO, + NOT_VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} +ObExprSTLength::~ObExprSTLength() +{} +int ObExprSTLength::calc_result_typeN(ObExprResType &type, ObExprResType *types_stack, + int64_t param_num, ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + INIT_SUCC(ret); + ObObjType geo_tp = types_stack[0].get_type(); + if (!ob_is_geometry(geo_tp) && !ob_is_string_type(geo_tp) && !ob_is_null(geo_tp)) { + types_stack[0].set_calc_type(ObVarcharType); + types_stack[0].set_calc_collation_type(CS_TYPE_BINARY); + } else if (param_num == 2) { + ObObjType unit_tp = types_stack[1].get_type(); + if (ob_is_string_type(unit_tp) || ob_is_null(unit_tp)) { + // do nothing + } else { + types_stack[1].set_calc_type(ObVarcharType); + types_stack[1].set_calc_collation_type(types_stack[1].get_collation_type()); + types_stack[1].set_calc_collation_level(types_stack[1].get_collation_level()); + } + } + if (OB_SUCC(ret)) { + type.set_double(); + } + return ret; +} + +int ObExprSTLength::eval_st_length(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_null_res = false; + ObDatum *datum1 = nullptr; + ObExpr *arg1 = expr.args_[0]; + ObObjType type1 = arg1->datum_meta_.type_; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + double res_num = 0; + if (ob_is_null(type1)) { + is_null_res = true; + } else if (OB_FAIL(arg1->eval(ctx, datum1))) { + LOG_WARN("fail to eval args", K(ret)); + } else if (datum1->is_null()) { + is_null_res = true; + } else if (type1 == ObIntType) { + // bugfix 53283098, should allow double type in calc_result_type2 + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_CROSSES); + LOG_WARN("invalid type", K(ret), K(type1)); + } else { + // construct geometry + ObString wkb = datum1->get_string(); + ObGeoType gtype = ObGeoType::GEOTYPEMAX; + ObGeometry *geo = nullptr; + const ObSrsItem *srs = NULL; + omt::ObSrsCacheGuard srs_guard; + if (OB_FAIL(ObTextStringHelper::read_real_string_data( + temp_allocator, *datum1, arg1->datum_meta_, arg1->obj_meta_.has_lob_header(), wkb))) { + LOG_WARN("fail to read real string data", K(ret), K(arg1->obj_meta_.has_lob_header())); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb, srs, true, N_ST_LENGTH))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry( + temp_allocator, wkb, geo, srs, N_ST_LENGTH, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { // ObIWkbGeom + LOG_WARN("fail to build geometry from wkb", K(ret), K(wkb)); + } else if (geo->type() != ObGeoType::LINESTRING && geo->type() != ObGeoType::MULTILINESTRING) { + is_null_res = true; + } else { + // cal length + ObGeoEvalCtx gis_context(&temp_allocator, srs); + if (OB_FAIL(gis_context.append_geo_arg(geo))) { + LOG_WARN("build gis context failed", K(ret)); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, res_num))) { + LOG_WARN("eval st distance failed", K(ret)); + if (OB_ERR_GIS_INVALID_DATA == ret) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_LENGTH); + } else { + ObGeoExprUtils::geo_func_error_handle(ret, N_ST_LENGTH); + } + } else if (std::isinf(res_num)) { + ret = OB_OPERATE_OVERFLOW; + LOG_WARN("Length value is out of range in st_length", K(ret)); + LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "Length", N_ST_LENGTH); + } else if (expr.arg_cnt_ == 2) { + // transfer to unit + ObDatum *gis_unit = NULL; + if (OB_FAIL(expr.args_[1]->eval(ctx, gis_unit))) { + LOG_WARN("eval geo unit arg failed", K(ret)); + } else if (gis_unit->is_null()) { + is_null_res = true; + } else if (OB_FAIL(ObGeoExprUtils::length_unit_conversion( + gis_unit->get_string(), srs, res_num, res_num))) { + LOG_WARN("fail to do unit conversion", K(ret), K(res_num)); + } else if (std::isinf(res_num)) { + ret = OB_OPERATE_OVERFLOW; + LOG_WARN("Length value is out of range in st_length", K(ret)); + LOG_USER_ERROR(OB_OPERATE_OVERFLOW, "Length", N_ST_LENGTH); + } + } + } + } + // set result + if (OB_SUCC(ret)) { + if (is_null_res) { + res.set_null(); + } else { + res.set_double(res_num); + } + } + return ret; +} +int ObExprSTLength::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_st_length; + return OB_SUCCESS; +} +} // namespace sql +} // namespace oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_st_length.h b/src/sql/engine/expr/ob_expr_st_length.h new file mode 100644 index 0000000000..ee43700cfa --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_length.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for _st_length. + */ +#ifndef OCEANBASE_SQL_OB_EXPR_ST_LENGTH_ +#define OCEANBASE_SQL_OB_EXPR_ST_LENGTH_ +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" +using namespace oceanbase::common; +namespace oceanbase +{ +namespace sql +{ +class ObExprSTLength : public ObFuncExprOperator +{ +public: + explicit ObExprSTLength(common::ObIAllocator &alloc); + virtual ~ObExprSTLength(); + virtual int calc_result_typeN(ObExprResType &type, ObExprResType *types, int64_t param_num, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_st_length(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + DISALLOW_COPY_AND_ASSIGN(ObExprSTLength); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_LENGTH_ diff --git a/src/sql/engine/expr/ob_expr_st_overlaps.cpp b/src/sql/engine/expr/ob_expr_st_overlaps.cpp new file mode 100644 index 0000000000..f8cc79b375 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_overlaps.cpp @@ -0,0 +1,189 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_overlaps. + */ + +#define USING_LOG_PREFIX SQL_ENG + +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_ibin.h" +#include "sql/engine/ob_exec_context.h" +#include "ob_expr_st_overlaps.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ + +ObExprSTOverlaps::ObExprSTOverlaps(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_ST_OVERLAPS, N_ST_OVERLAPS, 2, + VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprSTOverlaps::~ObExprSTOverlaps() +{} + +int ObExprSTOverlaps::calc_result_type2(ObExprResType &type, ObExprResType &type1, + ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + INIT_SUCC(ret); + if (type1.get_type() == ObNullType) { + } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { + type1.set_calc_type(ObVarcharType); + type1.set_calc_collation_type(CS_TYPE_BINARY); + } + if (type2.get_type() == ObNullType) { + } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { + type2.set_calc_type(ObVarcharType); + type2.set_calc_collation_type(CS_TYPE_BINARY); + } + type.set_int(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + return ret; +} + +int ObExprSTOverlaps::process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, + ObIAllocator &allocator, ObGeometry *&geo1, ObGeometry *&geo2, bool &is_null_res, + const ObSrsItem *&srs) +{ + int ret = OB_SUCCESS; + ObDatum *gis_datum1 = NULL; + ObDatum *gis_datum2 = NULL; + ObExpr *gis_arg1 = expr.args_[0]; + ObExpr *gis_arg2 = expr.args_[1]; + ObObjType input_type1 = gis_arg1->datum_meta_.type_; + ObObjType input_type2 = gis_arg2->datum_meta_.type_; + is_null_res = false; + if (OB_FAIL(gis_arg1->eval(ctx, gis_datum1)) || OB_FAIL(gis_arg2->eval(ctx, gis_datum2))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum1->is_null() || gis_datum2->is_null()) { + is_null_res = true; + } else if (input_type1 == ObIntType || input_type2 == ObIntType) { + // bugfix 53283098, should allow int type in calc_result_type2 + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_CROSSES); + LOG_WARN("invalid type", K(ret), K(input_type1), K(input_type2)); + } else { + ObGeoType type1; + ObGeoType type2; + uint32_t srid1; + uint32_t srid2; + ObString wkb1 = gis_datum1->get_string(); + ObString wkb2 = gis_datum2->get_string(); + bool is_geo1_valid = false; + bool is_geo2_valid = false; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum1, + gis_arg1->datum_meta_, + gis_arg1->obj_meta_.has_lob_header(), + wkb1))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb1)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum2, + gis_arg2->datum_meta_, + gis_arg2->obj_meta_.has_lob_header(), + wkb2))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb2)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb1, type1, srid1))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_OVERLAPS); + } + LOG_WARN("get type and srid from wkb failed", K(wkb1), K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb2, type2, srid2))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_OVERLAPS); + } + LOG_WARN("get type and srid from wkb failed", K(wkb2), K(ret)); + } else if (srid1 != srid2) { + ret = OB_ERR_GIS_DIFFERENT_SRIDS; + LOG_WARN("srid not the same", K(ret), K(srid1), K(srid2)); + LOG_USER_ERROR(OB_ERR_GIS_DIFFERENT_SRIDS, N_ST_OVERLAPS, srid1, srid2); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb1, srs, true, N_ST_OVERLAPS))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb1)); + } else if (OB_FAIL( + ObGeoExprUtils::build_geometry(allocator, wkb1, geo1, srs, N_ST_OVERLAPS, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { + LOG_WARN("get first geo by wkb failed", K(ret)); + } else if (OB_FAIL( + ObGeoExprUtils::build_geometry(allocator, wkb2, geo2, srs, N_ST_OVERLAPS, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { + LOG_WARN("get second geo by wkb failed", K(ret)); + } + } + return ret; +} + +int ObExprSTOverlaps::eval_st_overlaps(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_geo1_empty = false; + bool is_geo2_empty = false; + ObGeometry *geo1 = NULL; + ObGeometry *geo2 = NULL; + bool is_null_res = false; + bool result = false; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs = NULL; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + if (OB_FAIL(process_input_geometry(srs_guard, expr, ctx, temp_allocator, geo1, geo2, is_null_res, srs))) { + LOG_WARN("fail to process input geometry", K(ret)); + } else if (is_null_res) { + // do nothing + } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo1, is_geo1_empty)) + || OB_FAIL(ObGeoExprUtils::check_empty(geo2, is_geo2_empty))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_geo1_empty || is_geo2_empty) { + is_null_res = true; + } else if (OB_FAIL(ObGeoExprUtils::zoom_in_geos_for_relation(*geo1, *geo2))) { + LOG_WARN("zoom in geos failed", K(ret)); + } else { + ObGeoFuncResWithNull overlaps_result; + ObGeoEvalCtx gis_context(&temp_allocator, srs); + if (OB_FAIL(gis_context.append_geo_arg(geo1)) || OB_FAIL(gis_context.append_geo_arg(geo2))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval( + gis_context, overlaps_result))) { + LOG_WARN("eval st intersection failed", K(ret)); + ObGeoExprUtils::geo_func_error_handle(ret, N_ST_OVERLAPS); + } else if (overlaps_result.is_null) { + is_null_res = true; + } else { + result = overlaps_result.bret; + } + } + + if (OB_SUCC(ret)) { + if (is_null_res) { + res.set_null(); + } else { + res.set_bool(result); + } + } + return ret; +} + +int ObExprSTOverlaps::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_st_overlaps; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_st_overlaps.h b/src/sql/engine/expr/ob_expr_st_overlaps.h new file mode 100644 index 0000000000..b1a47f40d6 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_overlaps.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_overlaps. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_OVERLAPS_H_ +#define OCEANBASE_SQL_OB_EXPR_ST_OVERLAPS_H_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" +#include "observer/omt/ob_tenant_srs.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprSTOverlaps : public ObFuncExprOperator +{ +public: + explicit ObExprSTOverlaps(common::ObIAllocator &alloc); + virtual ~ObExprSTOverlaps(); + virtual int calc_result_type2(ObExprResType &type, ObExprResType &type1, ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_st_overlaps(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, ObGeometry *&geo1, + ObGeometry *&geo2, bool &is_null_res, const ObSrsItem *&srs); +// static int is_geometry_valid( + // ObGeometry *geo, ObIAllocator &allocator, const common::ObSrsItem *srs_item, bool &is_valid); + DISALLOW_COPY_AND_ASSIGN(ObExprSTOverlaps); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_OVERLAPS_H_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_st_srid.cpp b/src/sql/engine/expr/ob_expr_st_srid.cpp index 42da87a5b6..34125a2b1e 100644 --- a/src/sql/engine/expr/ob_expr_st_srid.cpp +++ b/src/sql/engine/expr/ob_expr_st_srid.cpp @@ -65,7 +65,7 @@ int ObExprSTSRID::calc_result_typeN(ObExprResType& type, ret = OB_ERR_GIS_INVALID_DATA; LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, get_name()); } else { - type.set_uint32(); + type.set_int32(); } if (OB_SUCC(ret) && param_num > 1) { types_stack[1].set_calc_type(ObIntType); @@ -145,7 +145,7 @@ int ObExprSTSRID::eval_st_srid_common(const ObExpr &expr, ObEvalCtx &ctx, ObDatu } if (OB_FAIL(ret)) { // do nothing - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(tmp_allocator, wkb, geo, srs, func_name, false, false, false))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(tmp_allocator, wkb, geo, srs, func_name, ObGeoBuildFlag::GEO_CHECK_RANGE))) { LOG_WARN("failed to parse geometry from wkb", K(ret)); } else if (OB_FAIL(ObGeoTypeUtil::get_srid_from_wkb(wkb, srid))) { LOG_WARN("failed to get srid from wkb", K(ret)); @@ -154,7 +154,7 @@ int ObExprSTSRID::eval_st_srid_common(const ObExpr &expr, ObEvalCtx &ctx, ObDatu LOG_WARN("srs not found"); } } else { - if (OB_FAIL(ObGeoExprUtils::build_geometry(tmp_allocator, wkb, geo, srs, func_name, false, false, false))) { + if (OB_FAIL(ObGeoExprUtils::build_geometry(tmp_allocator, wkb, geo, srs, func_name, ObGeoBuildFlag::GEO_CHECK_RANGE))) { LOG_WARN("fail to create geo", K(ret), K(wkb)); } else if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*geo, expr, ctx, srs, res_wkb))) { LOG_WARN("failed to write geometry to wkb", K(ret)); @@ -167,7 +167,7 @@ int ObExprSTSRID::eval_st_srid_common(const ObExpr &expr, ObEvalCtx &ctx, ObDatu } else if (is_null_result) { res.set_null(); } else if (num_args == 1) { - res.set_uint32(srid); + res.set_int32(srid); } else if (OB_ISNULL(geo)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected null geometry", K(ret)); diff --git a/src/sql/engine/expr/ob_expr_st_symdifference.cpp b/src/sql/engine/expr/ob_expr_st_symdifference.cpp new file mode 100644 index 0000000000..1159fba0c7 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_symdifference.cpp @@ -0,0 +1,235 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_symdifference. + */ +#define USING_LOG_PREFIX SQL_ENG +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_ibin.h" +#include "sql/engine/ob_exec_context.h" +#include "ob_expr_st_symdifference.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" +#include "lib/geo/ob_geo_elevation_visitor.h" +#include "lib/geo/ob_geo_func_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; +namespace oceanbase +{ +namespace sql +{ +ObExprSTSymDifference::ObExprSTSymDifference(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_ST_SYMDIFFERENCE, N_ST_SYMDIFFERENCE, 2, + VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} +ObExprSTSymDifference::~ObExprSTSymDifference() +{} +int ObExprSTSymDifference::calc_result_type2(ObExprResType &type, ObExprResType &type1, + ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + INIT_SUCC(ret); + if (type1.get_type() == ObNullType) { + } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { + type1.set_calc_type(ObVarcharType); + type1.set_calc_collation_type(CS_TYPE_BINARY); + } + if (type2.get_type() == ObNullType) { + } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { + type2.set_calc_type(ObVarcharType); + type2.set_calc_collation_type(CS_TYPE_BINARY); + } + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); + return ret; +} +int ObExprSTSymDifference::process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, + ObIAllocator &allocator, ObGeometry *&geo1, ObGeometry *&geo2, bool &is_null_res, + const ObSrsItem *&srs) +{ + int ret = OB_SUCCESS; + ObDatum *gis_datum1 = nullptr; + ObDatum *gis_datum2 = nullptr; + ObExpr *gis_arg1 = expr.args_[0]; + ObExpr *gis_arg2 = expr.args_[1]; + ObObjType input_type1 = gis_arg1->datum_meta_.type_; + ObObjType input_type2 = gis_arg2->datum_meta_.type_; + is_null_res = false; + if (OB_FAIL(gis_arg1->eval(ctx, gis_datum1)) || OB_FAIL(gis_arg2->eval(ctx, gis_datum2))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum1->is_null() || gis_datum2->is_null()) { + is_null_res = true; + } else { + ObGeoType type1; + ObGeoType type2; + uint32_t srid1; + uint32_t srid2; + ObString wkb1 = gis_datum1->get_string(); + ObString wkb2 = gis_datum2->get_string(); + bool is_geo1_valid = false; + bool is_geo2_valid = false; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum1, + gis_arg1->datum_meta_, + gis_arg1->obj_meta_.has_lob_header(), + wkb1))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb1)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum2, + gis_arg2->datum_meta_, + gis_arg2->obj_meta_.has_lob_header(), + wkb2))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb2)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb1, type1, srid1))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_SYMDIFFERENCE); + } + LOG_WARN("get type and srid from wkb failed", K(wkb1), K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb2, type2, srid2))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_SYMDIFFERENCE); + } + LOG_WARN("get type and srid from wkb failed", K(wkb2), K(ret)); + } else if (srid1 != srid2) { + ret = OB_ERR_GIS_DIFFERENT_SRIDS; + LOG_WARN("srid not the same", K(ret), K(srid1), K(srid2)); + LOG_USER_ERROR(OB_ERR_GIS_DIFFERENT_SRIDS, N_ST_SYMDIFFERENCE, srid1, srid2); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb1, srs, true, N_ST_SYMDIFFERENCE))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb1)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(allocator, + wkb1, + geo1, + srs, + N_ST_SYMDIFFERENCE, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT | GEO_RESERVE_3D))) { + LOG_WARN("get first geo by wkb failed", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(allocator, + wkb2, + geo2, + srs, + N_ST_SYMDIFFERENCE, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT | GEO_RESERVE_3D))) { + LOG_WARN("get second geo by wkb failed", K(ret)); + } + } + return ret; +} + +int ObExprSTSymDifference::eval_st_symdifference(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_geo1_empty = false; + bool is_geo2_empty = false; + ObGeometry *geo1_3d = nullptr; + ObGeometry *geo2_3d = nullptr; + bool is_null_res = false; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs = nullptr; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObGeometry *diff_res = nullptr; + if (OB_FAIL( + process_input_geometry(srs_guard, expr, ctx, temp_allocator, geo1_3d, geo2_3d, is_null_res, srs))) { + LOG_WARN("fail to process input geometry", K(ret)); + } else if (!is_null_res) { + ObGeometry *geo1 = nullptr; + ObGeometry *geo2 = nullptr; + bool is_3d_geo1 = ObGeoTypeUtil::is_3d_geo_type(geo1_3d->type()); + bool is_3d_geo2 = ObGeoTypeUtil::is_3d_geo_type(geo2_3d->type()); + if ((is_3d_geo1 && !is_3d_geo2) || (!is_3d_geo1 && is_3d_geo2)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("mixed dimension geometries", K(ret), K(is_3d_geo1), K(is_3d_geo2)); + } else if (is_3d_geo1) { + if (OB_FAIL(ObGeoTypeUtil::convert_geometry_3D_to_2D( + srs, temp_allocator, geo1_3d, ObGeoBuildFlag::GEO_DEFAULT, geo1))) { + LOG_WARN("fail to convert 3D geometry to 2D", K(ret)); + } + } else { + geo1 = geo1_3d; + } + if (OB_FAIL(ret)) { + } else if (is_3d_geo2) { + if (OB_FAIL(ObGeoTypeUtil::convert_geometry_3D_to_2D( + srs, temp_allocator, geo2_3d, ObGeoBuildFlag::GEO_DEFAULT, geo2))) { + LOG_WARN("fail to convert 3D geometry to 2D", K(ret)); + } + } else { + geo2 = geo2_3d; + } + if (OB_SUCC(ret)) { + ObGeoEvalCtx gis_context(&temp_allocator, srs); + bool is_empty_res = false; + if (OB_FAIL(gis_context.append_geo_arg(geo1)) || OB_FAIL(gis_context.append_geo_arg(geo2))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval( + gis_context, diff_res))) { + LOG_WARN("eval st symdifference failed", K(ret)); + ObGeoExprUtils::geo_func_error_handle(ret, N_ST_SYMDIFFERENCE); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(diff_res, is_empty_res))) { + LOG_WARN("check geo empty failed", K(ret)); + } else if (is_empty_res) { + // 2D return GEOMETRYCOLLECTION EMPTY, 3D return GEOMETRYCOLLECTION Z EMPTY + if (OB_FAIL(ObGeoExprUtils::create_3D_empty_collection(temp_allocator, geo1->get_srid(), is_3d_geo1, + geo1->crs() == ObGeoCRS::Geographic, diff_res))) { + LOG_WARN("fail to create 3D empty collection", K(ret)); + } + } else if (geo1->crs() == ObGeoCRS::Cartesian + && OB_FAIL(ObGeoFuncUtils::remove_duplicate_multi_geo(diff_res, temp_allocator, srs))) { + // should not do simplify in symdifference functor, it may affect + // ObGeoFuncUtils::ob_geo_gc_union + LOG_WARN("fail to simplify result", K(ret)); + } else if (geo1->crs() == ObGeoCRS::Geographic + && OB_FAIL(ObGeoFuncUtils::remove_duplicate_multi_geo(diff_res, temp_allocator, srs))) { + // should not do simplify in symdifference functor, it may affect + // ObGeoFuncUtils::ob_geo_gc_union + LOG_WARN("fail to simplify result", K(ret)); + } else if (is_3d_geo1 && is_3d_geo2) { + // populate Z coordinates + ObGeoElevationVisitor visitor(temp_allocator, srs); + ObGeometry *diff_res_bin = nullptr; + if (OB_FAIL(visitor.init(*geo1_3d, *geo2_3d))) { + LOG_WARN("fail to init elevation visitor", K(ret)); + } else if (OB_FAIL( + ObGeoTypeUtil::tree_to_bin(temp_allocator, diff_res, diff_res_bin, srs))) { + LOG_WARN("fail to do tree to bin", K(ret)); + } else if (OB_FAIL(diff_res_bin->do_visit(visitor))) { + LOG_WARN("fail to do elevation visitor", K(ret)); + } else if (OB_FAIL(visitor.get_geometry_3D(diff_res))) { + LOG_WARN("failed get geometry 3D", K(ret)); + } + } + } + } + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res.set_null(); + } else { + ObString res_wkb; + if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*diff_res, expr, ctx, srs, res_wkb))) { + LOG_WARN("failed to write geometry to wkb", K(ret)); + } else { + res.set_string(res_wkb); + } + } + return ret; +} +int ObExprSTSymDifference::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_st_symdifference; + return OB_SUCCESS; +} +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_st_symdifference.h b/src/sql/engine/expr/ob_expr_st_symdifference.h new file mode 100644 index 0000000000..86c6f7cf65 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_symdifference.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_symdifference. + */ +#ifndef OCEANBASE_SQL_OB_EXPR_ST_SYMDIFFERENCE_H_ +#define OCEANBASE_SQL_OB_EXPR_ST_SYMDIFFERENCE_H_ +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" +#include "observer/omt/ob_tenant_srs.h" +namespace oceanbase +{ +namespace sql +{ +class ObExprSTSymDifference : public ObFuncExprOperator +{ +public: + explicit ObExprSTSymDifference(common::ObIAllocator &alloc); + virtual ~ObExprSTSymDifference(); + virtual int calc_result_type2(ObExprResType &type, ObExprResType &type1, ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_st_symdifference(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; +private: + static int process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, + ObGeometry *&geo1, ObGeometry *&geo2, bool &is_null_res, const ObSrsItem *&srs); + DISALLOW_COPY_AND_ASSIGN(ObExprSTSymDifference); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_SYMDIFFERENCE_H_ diff --git a/src/sql/engine/expr/ob_expr_st_transform.cpp b/src/sql/engine/expr/ob_expr_st_transform.cpp index 8d0190b54c..3f9357e584 100644 --- a/src/sql/engine/expr/ob_expr_st_transform.cpp +++ b/src/sql/engine/expr/ob_expr_st_transform.cpp @@ -118,7 +118,8 @@ int ObExprSTTransform::eval_st_transform(const ObExpr &expr, ObEvalCtx &ctx, ObD if (OB_SUCC(ret)) { if (dest_srid == src_srid) { // return src geo directly ObString res_wkb; - if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb, src_geo, src_srs_item, N_ST_TRANSFORM, false, false, false))) { + if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb, src_geo, src_srs_item, N_ST_TRANSFORM, + ObGeoBuildFlag::GEO_ALLOW_3D))) { LOG_WARN("fail to create geo", K(ret), K(wkb)); } else if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*src_geo, expr, ctx, src_srs_item, res_wkb))) { LOG_WARN("failed to write geometry to wkb", K(ret)); @@ -181,7 +182,7 @@ int ObExprSTTransform::eval_st_transform(const ObExpr &expr, ObEvalCtx &ctx, ObD ret = OB_ERR_TRANSFORM_TARGET_SRS_NOT_SUPPORTED; LOG_USER_ERROR(OB_ERR_TRANSFORM_TARGET_SRS_NOT_SUPPORTED, dest_srid); } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb, src_geo, - src_srs_item, N_ST_TRANSFORM))) { + src_srs_item, N_ST_TRANSFORM, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("failed to parse wkb", K(ret)); } else if (OB_FAIL(correct_context.append_geo_arg(src_geo))) { LOG_WARN("failed to append geo arg to gis context", K(ret), K(correct_context.get_geo_count())); diff --git a/src/sql/engine/expr/ob_expr_st_union.cpp b/src/sql/engine/expr/ob_expr_st_union.cpp new file mode 100644 index 0000000000..4a07bf5802 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_union.cpp @@ -0,0 +1,275 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_union. + */ + +#define USING_LOG_PREFIX SQL_ENG + +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_ibin.h" +#include "sql/engine/ob_exec_context.h" +#include "ob_expr_st_union.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" +#include "lib/geo/ob_geo_elevation_visitor.h" +#include "lib/geo/ob_geo_func_utils.h" + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ + +ObExprSTUnion::ObExprSTUnion(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_ST_UNION, N_ST_UNION, 2, + VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{} + +ObExprSTUnion::~ObExprSTUnion() +{} + +int ObExprSTUnion::calc_result_type2(ObExprResType &type, ObExprResType &type1, + ObExprResType &type2, common::ObExprTypeCtx &type_ctx) const +{ + UNUSED(type_ctx); + INIT_SUCC(ret); + if (type1.get_type() == ObNullType) { + } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { + type1.set_calc_type(ObVarcharType); + type1.set_calc_collation_type(CS_TYPE_BINARY); + } + if (type2.get_type() == ObNullType) { + } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { + type2.set_calc_type(ObVarcharType); + type2.set_calc_collation_type(CS_TYPE_BINARY); + } + type.set_geometry(); + type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); + return ret; +} + +int ObExprSTUnion::process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, + ObIAllocator &allocator, ObGeometry *&geo1, ObGeometry *&geo2, bool &is_null_res, + const ObSrsItem *&srs) +{ + int ret = OB_SUCCESS; + ObDatum *gis_datum1 = nullptr; + ObDatum *gis_datum2 = nullptr; + ObExpr *gis_arg1 = expr.args_[0]; + ObExpr *gis_arg2 = expr.args_[1]; + ObObjType input_type1 = gis_arg1->datum_meta_.type_; + ObObjType input_type2 = gis_arg2->datum_meta_.type_; + is_null_res = false; + if (OB_FAIL(gis_arg1->eval(ctx, gis_datum1)) || OB_FAIL(gis_arg2->eval(ctx, gis_datum2))) { + LOG_WARN("eval geo args failed", K(ret)); + } else if (gis_datum1->is_null() || gis_datum2->is_null()) { + is_null_res = true; + } else { + ObGeoType type1; + ObGeoType type2; + uint32_t srid1; + uint32_t srid2; + ObString wkb1 = gis_datum1->get_string(); + ObString wkb2 = gis_datum2->get_string(); + bool is_geo1_valid = false; + bool is_geo2_valid = false; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum1, + gis_arg1->datum_meta_, + gis_arg1->obj_meta_.has_lob_header(), + wkb1))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb1)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum2, + gis_arg2->datum_meta_, + gis_arg2->obj_meta_.has_lob_header(), + wkb2))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb2)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb1, type1, srid1))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_UNION); + } + LOG_WARN("get type and srid from wkb failed", K(wkb1), K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb2, type2, srid2))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_UNION); + } + LOG_WARN("get type and srid from wkb failed", K(wkb2), K(ret)); + } else if (srid1 != srid2) { + ret = OB_ERR_GIS_DIFFERENT_SRIDS; + LOG_WARN("srid not the same", K(ret), K(srid1), K(srid2)); + LOG_USER_ERROR(OB_ERR_GIS_DIFFERENT_SRIDS, N_ST_UNION, srid1, srid2); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb1, srs, true, N_ST_UNION))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb1)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(allocator, + wkb1, + geo1, + srs, + N_ST_UNION, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT | GEO_RESERVE_3D))) { + LOG_WARN("get first geo by wkb failed", K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(allocator, + wkb2, + geo2, + srs, + N_ST_UNION, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT | GEO_RESERVE_3D))) { + LOG_WARN("get second geo by wkb failed", K(ret)); + } + } + return ret; +} + +int ObExprSTUnion::eval_st_union(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + int ret = OB_SUCCESS; + bool is_geo1_empty = false; + bool is_geo2_empty = false; + ObGeometry *geo1_3d = nullptr; + ObGeometry *geo2_3d = nullptr; + bool is_null_res = false; + omt::ObSrsCacheGuard srs_guard; + const ObSrsItem *srs = nullptr; + ObEvalCtx::TempAllocGuard tmp_alloc_g(ctx); + common::ObArenaAllocator &temp_allocator = tmp_alloc_g.get_allocator(); + ObGeometry *union_res = nullptr; + bool is_empty_res = false; + if (OB_FAIL( + process_input_geometry(srs_guard, expr, ctx, temp_allocator, geo1_3d, geo2_3d, is_null_res, srs))) { + LOG_WARN("fail to process input geometry", K(ret)); + } else if (!is_null_res) { + ObGeometry *geo1 = nullptr; + ObGeometry *geo2 = nullptr; + bool is_3d_geo1 = ObGeoTypeUtil::is_3d_geo_type(geo1_3d->type()); + bool is_3d_geo2 = ObGeoTypeUtil::is_3d_geo_type(geo2_3d->type()); + if ((is_3d_geo1 && !is_3d_geo2) || (!is_3d_geo1 && is_3d_geo2)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("mixed dimension geometries", K(ret), K(is_3d_geo1), K(is_3d_geo2)); + } else if (is_3d_geo1) { + if (OB_FAIL(ObGeoTypeUtil::convert_geometry_3D_to_2D( + srs, temp_allocator, geo1_3d, ObGeoBuildFlag::GEO_DEFAULT, geo1))) { + LOG_WARN("fail to convert 3D geometry to 2D", K(ret)); + } + } else { + geo1 = geo1_3d; + } + if (OB_FAIL(ret)) { + } else if (is_3d_geo2) { + if (OB_FAIL(ObGeoTypeUtil::convert_geometry_3D_to_2D( + srs, temp_allocator, geo2_3d, ObGeoBuildFlag::GEO_DEFAULT, geo2))) { + LOG_WARN("fail to convert 3D geometry to 2D", K(ret)); + } + } else { + geo2 = geo2_3d; + } + if (OB_FAIL(ret)) { + } else { + ObGeoEvalCtx gis_context(&temp_allocator, srs); + if (OB_FAIL(gis_context.append_geo_arg(geo1)) || OB_FAIL(gis_context.append_geo_arg(geo2))) { + LOG_WARN("build gis context failed", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL( + ObGeoFunc::geo_func::eval(gis_context, union_res))) { + LOG_WARN("eval st union failed", K(ret)); + ObGeoExprUtils::geo_func_error_handle(ret, N_ST_UNION); + } else if (OB_FAIL(ObGeoExprUtils::check_empty(union_res, is_empty_res))) { + LOG_WARN("check geo empty failed", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (is_empty_res) { + // 2D return GEOMETRYCOLLECTION EMPTY, 3D return GEOMETRYCOLLECTION Z EMPTY + if (OB_FAIL(ObGeoExprUtils::create_3D_empty_collection(temp_allocator, geo1->get_srid(), is_3d_geo1, + geo1->crs() == ObGeoCRS::Geographic, union_res))) { + LOG_WARN("fail to create 3D empty collection", K(ret)); + } + } else { + if ((!is_3d_geo1)) { + if (geo1->crs() == ObGeoCRS::Cartesian) { + if (OB_FAIL(ObGeoFuncUtils::remove_duplicate_multi_geo( + union_res, temp_allocator, srs))) { + // should not do simplify in symdifference functor, it may affect + // ObGeoFuncUtils::ob_geo_gc_union + LOG_WARN("fail to remove_duplicate_multi_geo", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::simplify_geo_collection( + union_res, temp_allocator, srs))) { + LOG_WARN("fail to simplify_geo_collection", K(ret)); + } + } else if (geo1->crs() == ObGeoCRS::Geographic) { + if (OB_FAIL(ObGeoFuncUtils::remove_duplicate_multi_geo( + union_res, temp_allocator, srs))) { + // should not do simplify in symdifference functor, it may affect + // ObGeoFuncUtils::ob_geo_gc_union + LOG_WARN("fail to remove_duplicate_multi_geo", K(ret)); + } else if (OB_FAIL(ObGeoFuncUtils::simplify_geo_collection( + union_res, temp_allocator, srs))) { + LOG_WARN("fail to simplify_geo_collection", K(ret)); + } + } + } else { + // 3D + if (geo1->crs() == ObGeoCRS::Cartesian + && OB_FAIL(ObGeoFuncUtils::remove_duplicate_multi_geo( + union_res, temp_allocator, srs))) { + // should not do simplify in symdifference functor, it may affect + // ObGeoFuncUtils::ob_geo_gc_union + LOG_WARN("fail to simplify result", K(ret)); + } else if (geo1->crs() == ObGeoCRS::Geographic + && OB_FAIL(ObGeoFuncUtils::remove_duplicate_multi_geo( + union_res, temp_allocator, srs))) { + // should not do simplify in symdifference functor, it may affect + // ObGeoFuncUtils::ob_geo_gc_union + LOG_WARN("fail to simplify result", K(ret)); + } else { + // populate Z coordinates + ObGeoElevationVisitor visitor(temp_allocator, srs); + ObGeometry *union_res_bin = nullptr; + if (OB_FAIL(visitor.init(*geo1_3d, *geo2_3d))) { + LOG_WARN("fail to init elevation visitor", K(ret)); + } else if (OB_FAIL(ObGeoTypeUtil::tree_to_bin(temp_allocator, union_res, union_res_bin, srs))) { + LOG_WARN("fail to do tree to bin", K(ret)); + } else if (OB_FAIL(union_res_bin->do_visit(visitor))) { + LOG_WARN("fail to do elevation visitor", K(ret)); + } else if (OB_FAIL(visitor.get_geometry_3D(union_res))) { + LOG_WARN("failed get geometry 3D", K(ret)); + } + } + } + } + } + + if (OB_FAIL(ret)) { + } else if (is_null_res) { + res.set_null(); + } else { + ObString res_wkb; + if (OB_FAIL(ObGeoExprUtils::geo_to_wkb(*union_res, expr, ctx, srs, res_wkb))) { + LOG_WARN("failed to write geometry to wkb", K(ret)); + } else { + res.set_string(res_wkb); + } + } + return ret; +} + +int ObExprSTUnion::cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_st_union; + return OB_SUCCESS; +} + +} // namespace sql +} // namespace oceanbase diff --git a/src/sql/engine/expr/ob_expr_st_union.h b/src/sql/engine/expr/ob_expr_st_union.h new file mode 100644 index 0000000000..eca5e069a0 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_st_union.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file contains implementation for eval_st_union. + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_ST_UNION_H_ +#define OCEANBASE_SQL_OB_EXPR_ST_UNION_H_ + +#include "sql/engine/expr/ob_expr_operator.h" +#include "lib/geo/ob_geo_utils.h" +#include "observer/omt/ob_tenant_srs.h" + +namespace oceanbase +{ +namespace sql +{ +class ObExprSTUnion : public ObFuncExprOperator +{ +public: + explicit ObExprSTUnion(common::ObIAllocator &alloc); + virtual ~ObExprSTUnion(); + virtual int calc_result_type2(ObExprResType &type, ObExprResType &type1, ObExprResType &type2, + common::ObExprTypeCtx &type_ctx) const override; + static int eval_st_union(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr( + ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + static int process_input_geometry(omt::ObSrsCacheGuard &srs_guard, const ObExpr &expr, ObEvalCtx &ctx, ObIAllocator &allocator, + ObGeometry *&geo1, ObGeometry *&geo2, bool &is_null_res, const ObSrsItem *&srs); + DISALLOW_COPY_AND_ASSIGN(ObExprSTUnion); +}; +} // namespace sql +} // namespace oceanbase +#endif // OCEANBASE_SQL_OB_EXPR_ST_UNION_H_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_st_within.cpp b/src/sql/engine/expr/ob_expr_st_within.cpp index 4cde437999..be72289b59 100644 --- a/src/sql/engine/expr/ob_expr_st_within.cpp +++ b/src/sql/engine/expr/ob_expr_st_within.cpp @@ -46,33 +46,19 @@ int ObExprSTWithin::calc_result_type2(ObExprResType &type, { UNUSED(type_ctx); INIT_SUCC(ret); - int unexpected_types = 0; - int null_types = 0; - if (type1.get_type() == ObNullType) { - null_types++; } else if (!ob_is_geometry(type1.get_type()) && !ob_is_string_type(type1.get_type())) { - unexpected_types++; - LOG_WARN("invalid type", K(type1.get_type())); + type1.set_calc_type(ObVarcharType); + type1.set_calc_collation_type(CS_TYPE_BINARY); } if (type2.get_type() == ObNullType) { - null_types++; } else if (!ob_is_geometry(type2.get_type()) && !ob_is_string_type(type2.get_type())) { - unexpected_types++; - LOG_WARN("invalid type", K(type2.get_type())); - } - // an invalid type and a null type will return null - // an invalid type and a valid type return error - if (null_types == 0 && unexpected_types > 0) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_WITHIN); - LOG_WARN("invalid type", K(ret)); - } - if (OB_SUCC(ret)) { - type.set_int32(); - type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); - type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); + type2.set_calc_type(ObVarcharType); + type2.set_calc_collation_type(CS_TYPE_BINARY); } + type.set_int32(); + type.set_scale(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].scale_); + type.set_precision(common::ObAccuracy::DDL_DEFAULT_ACCURACY[common::ObIntType].precision_); return ret; } @@ -116,15 +102,18 @@ int ObExprSTWithin::eval_st_within(const ObExpr &expr, ObEvalCtx &ctx, ObDatum & } LOG_WARN("get type and srid from wkb failed", K(wkb1), K(ret)); } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb2, type2, srid2))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, N_ST_WITHIN); + } LOG_WARN("get type and srid from wkb failed", K(wkb2), K(ret)); } else if (srid1 != srid2) { LOG_WARN("srid not the same", K(srid1), K(srid2)); ret = OB_ERR_GIS_DIFFERENT_SRIDS; } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb1, srs, true))) { LOG_WARN("fail to get srs item", K(ret), K(wkb1)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_ST_WITHIN))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb1, geo1, srs, N_ST_WITHIN, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("get first geo by wkb failed", K(ret)); - } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_ST_WITHIN))) { + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb2, geo2, srs, N_ST_WITHIN, ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { LOG_WARN("get second geo by wkb failed", K(ret)); } else if (OB_FAIL(ObGeoExprUtils::check_empty(geo1, is_geo1_empty)) || OB_FAIL(ObGeoExprUtils::check_empty(geo2, is_geo2_empty))) { diff --git a/src/sql/engine/expr/ob_expr_st_x.cpp b/src/sql/engine/expr/ob_expr_st_x.cpp index b82917bc5c..1018fa4821 100644 --- a/src/sql/engine/expr/ob_expr_st_x.cpp +++ b/src/sql/engine/expr/ob_expr_st_x.cpp @@ -59,9 +59,7 @@ int ObExprSTCoordinate::calc_result_typeN(ObExprResType& type, if (param_num == 1) { type.set_double(); } else if (param_num == 2) { - type.set_type(ObGeometryType); - type.set_collation_level(common::CS_LEVEL_COERCIBLE); - type.set_collation_type(CS_TYPE_BINARY); + type.set_geometry(); type.set_length((ObAccuracy::DDL_DEFAULT_ACCURACY[ObGeometryType]).get_length()); } } @@ -104,7 +102,7 @@ int ObExprSTCoordinate::eval_common(const ObExpr &expr, } else if (OB_FAIL(ObGeoExprUtils::get_srs_item(ctx, srs_guard, wkb, srs, true, func_name))) { LOG_WARN("fail to get srs item", K(ret), K(wkb)); } else if (OB_FAIL(ObGeoExprUtils::build_geometry(temp_allocator, wkb, - geo, srs, func_name, false))) { + geo, srs, func_name, ObGeoBuildFlag::GEO_CORRECT | ObGeoBuildFlag::GEO_CHECK_RANGE))) { LOG_WARN("failed to create geometry object with raw wkb", K(ret)); } else if (ObGeoType::POINT != geo->type()) { ret = OB_ERR_UNEXPECTED_GEOMETRY_TYPE; diff --git a/src/sql/engine/expr/ob_expr_sum_result_type.map b/src/sql/engine/expr/ob_expr_sum_result_type.map index d228bf065d..e18bc9dd87 100644 --- a/src/sql/engine/expr/ob_expr_sum_result_type.map +++ b/src/sql/engine/expr/ob_expr_sum_result_type.map @@ -51,6 +51,7 @@ static constexpr ObObjType SUM_RESULT_TYPE[ObMaxType] = ObMaxType, /* ObGeometryType */ ObMaxType, /* ObUserDefinedSQLType */ ObMaxType, /* ObDecimalIntType */ + ObMaxType, /* ObCollectionSQLType */ }; static_assert(is_array_fully_initialized(SUM_RESULT_TYPE), "SUM_RESULT_TYPE is partially initlized"); \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_xml_element.cpp b/src/sql/engine/expr/ob_expr_xml_element.cpp index a87be1f3a7..02fa0936a6 100644 --- a/src/sql/engine/expr/ob_expr_xml_element.cpp +++ b/src/sql/engine/expr/ob_expr_xml_element.cpp @@ -178,7 +178,7 @@ int ObExprXmlElement::eval_xml_element(const ObExpr &expr, ObEvalCtx &ctx, ObDat if (val_type == ObUserDefinedSQLType) { // xmltype if (OB_FAIL(ObTextStringHelper::read_real_string_data(&tmp_allocator, ObObjType::ObLongTextType, - xml_arg->datum_meta_.cs_type_, + ObCollationType::CS_TYPE_BINARY, true, xml_value_data))) { LOG_WARN("fail to get real data.", K(ret), K(xml_value_data)); // } else if (OB_FAIL(ObXMLExprHelper::check_xml_document_unparsed(mem_ctx, xml_value_data, validity))) { diff --git a/src/sql/engine/expr/ob_expr_xml_func_helper.cpp b/src/sql/engine/expr/ob_expr_xml_func_helper.cpp new file mode 100644 index 0000000000..2803ac5e38 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_xml_func_helper.cpp @@ -0,0 +1,870 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file is for implement of func xml expr helper + */ + +#define USING_LOG_PREFIX SQL_ENG +#include "lib/ob_errno.h" +#include "sql/engine/expr/ob_expr_xml_func_helper.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#ifdef OB_BUILD_ORACLE_XML +#include "lib/xml/ob_xpath.h" +#include "lib/xml/ob_xml_bin.h" +#include "lib/xml/ob_xml_util.h" +#include "lib/xml/ob_xml_parser.h" +#endif // OB_BUILD_ORACLE_XML +#include "sql/engine/expr/ob_expr_sql_udt_utils.h" +#include "sql/session/ob_sql_session_info.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/ob_result_set.h" +#include "sql/ob_spi.h" +#ifdef OB_BUILD_ORACLE_PL +#include "pl/sys_package/ob_sdo_geometry.h" +#endif + +using namespace oceanbase::common; +using namespace oceanbase::sql; + +namespace oceanbase +{ +namespace sql +{ +#ifdef OB_BUILD_ORACLE_XML +uint64_t ObXMLExprHelper::get_tenant_id(ObSQLSessionInfo *session) +{ + uint64_t tenant_id = 0; + if (OB_ISNULL(session)) { + } else if (session->get_ddl_info().is_ddl_check_default_value()) { + tenant_id = OB_SERVER_TENANT_ID; + } else { + tenant_id = session->get_effective_tenant_id(); + } + return tenant_id; +} + +int ObXMLExprHelper::add_binary_to_element(ObMulModeMemCtx* mem_ctx, ObString binary_value, ObXmlElement &element) +{ + INIT_SUCC(ret); + ObXmlDocument *xml_doc = NULL; + ObIMulModeBase *node = NULL; + ObXmlDocument *doc_node = NULL; + ObMulModeNodeType node_type = M_MAX_TYPE; + bool is_unparsed = false; + if (binary_value.empty()) { + if (OB_ISNULL(xml_doc = OB_NEWx(ObXmlDocument, (mem_ctx->allocator_), + ObMulModeNodeType::M_CONTENT, + (mem_ctx)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create an empty xml content node", K(ret), K(binary_value)); + } else { + node = xml_doc; + } + } else if (OB_FAIL(ObXmlUtil::xml_bin_type(binary_value, node_type))) { + LOG_WARN("xml bin type failed", K(ret)); + } else if (node_type == M_UNPARSED) { + ObStringBuffer* buffer = nullptr; + ObXmlDocument *x_doc = nullptr; + ObString xml_text; + ObXmlBin bin(binary_value, mem_ctx); + if (OB_ISNULL(buffer = OB_NEWx(ObStringBuffer, mem_ctx->allocator_, (mem_ctx->allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate buffer", K(ret)); + } else if (OB_FAIL(bin.parse())) { + LOG_WARN("fail to parse binary.", K(ret)); + } else if (OB_FAIL(bin.print_xml(*buffer, ObXmlFormatType::NO_FORMAT, 0, 0))) { + LOG_WARN("fail to print xml", K(ret)); + } else if (FALSE_IT(xml_text.assign_ptr(buffer->ptr(), buffer->length()))) { + } else if (OB_FAIL(ObXmlParserUtils::parse_content_text(mem_ctx, xml_text, x_doc))) { + LOG_DEBUG("fail to parse unparse", K(ret)); + ret = OB_SUCCESS; + if (OB_FAIL(bin.to_tree(node))) { + LOG_WARN("fail to tree", K(ret)); + } + is_unparsed = true; + } else { + node = x_doc; + } + } else if (OB_FAIL(ObMulModeFactory::get_xml_base(mem_ctx, binary_value, + ObNodeMemType::BINARY_TYPE, + ObNodeMemType::TREE_TYPE, + node))) { + LOG_WARN("fail to get xml base", K(ret), K(binary_value), K(node_type)); + } + + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(node)) { + ret = OB_BAD_NULL_ERROR; + LOG_WARN("node cast to xmldocument failed", K(ret), K(node)); + } else if (ObMulModeNodeType::M_DOCUMENT == node->type() || + ObMulModeNodeType::M_CONTENT == node->type() || + ObMulModeNodeType::M_UNPARSED == node->type()) { + if (OB_ISNULL(doc_node = static_cast(node))) { + ret = OB_BAD_NULL_ERROR; + LOG_WARN("node cast to xmldocument failed", K(ret), K(node)); + } + for (int32_t j = 0; OB_SUCC(ret) && j < doc_node->size(); j++) { + ObXmlNode *xml_node = doc_node->at(j); + if (OB_ISNULL(xml_node)) { + ret = OB_BAD_NULL_ERROR; + LOG_WARN("doc node get null", K(ret), K(j)); + } else if (OB_XML_TYPE != xml_node->data_type()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("xml node date type unexpect", K(ret), K(j), K(xml_node->data_type())); + } else if (OB_FAIL(element.add_element(xml_node))) { + LOG_WARN("add element failed", K(ret), K(j), K(xml_node)); + } + } + if (OB_SUCC(ret) && is_unparsed) { + // if the binary is unparsed and parsed fail, set the element is unparsed + element.set_unparse(1); + } + } + return ret; +} + +int ObXMLExprHelper::get_xml_base(ObMulModeMemCtx *ctx, + ObDatum *xml_datum, + ObCollationType cs_type, + ObNodeMemType expect_type, + ObIMulModeBase *&node) +{ + ObMulModeNodeType node_type = M_MAX_TYPE; + return get_xml_base(ctx, xml_datum, cs_type, expect_type, node, node_type, false); +} +int ObXMLExprHelper::get_xml_base(ObMulModeMemCtx *ctx, + ObDatum *xml_datum, + ObCollationType cs_type, + ObNodeMemType expect_type, + ObIMulModeBase *&node, + ObMulModeNodeType &node_type, + bool is_reparse) +{ + int ret = OB_SUCCESS; + // temporary use until xml binary ready + ObString xml_text; + ObDatumMeta xml_meta; + xml_meta.type_ = ObLongTextType; + xml_meta.cs_type_ = CS_TYPE_UTF8MB4_BIN; + ObXmlDocument *xml_doc = NULL; + if (OB_ISNULL(xml_datum)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("xml datum is NULL", K(ret)); + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(*ctx->allocator_, *xml_datum, xml_meta, true, xml_text))) { + LOG_WARN("fail to get real data.", K(ret), K(xml_text)); + } else if (xml_text.empty()) { + // create an empty xml node + if (OB_ISNULL(xml_doc = OB_NEWx(ObXmlDocument, (ctx->allocator_), ObMulModeNodeType::M_CONTENT, ctx))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to create an empty xml content node", K(ret), K(xml_text)); + } else { + node = xml_doc; + } + } else if (OB_FAIL(ObXmlUtil::xml_bin_type(xml_text, node_type))) { + LOG_WARN("failed to get bin header.", K(ret)); + } else if (is_reparse) { + ObStringBuffer *buff = nullptr; + ParamPrint param_list; + if (OB_ISNULL(buff = OB_NEWx(ObStringBuffer, ctx->allocator_, (ctx->allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("create obstrinbuffer failed", K(ret)); + } else if (OB_FAIL(ObMulModeFactory::get_xml_base(ctx, xml_text, + ObNodeMemType::BINARY_TYPE, + ObNodeMemType::BINARY_TYPE, + node))) { + LOG_WARN("fail to get xml base", K(ret)); + } else if (node_type == M_UNPARESED_DOC && OB_FALSE_IT(node_type = M_DOCUMENT)) { + } else if (node_type == M_UNPARSED) { + } else if (node_type == M_DOCUMENT && OB_FAIL(node->print_document(*buff, CS_TYPE_INVALID, ObXmlFormatType::NO_FORMAT, 0))) { + LOG_WARN("failed to convert xml binary to xml text", K(ret)); + } else if (node_type == M_CONTENT && OB_FAIL(node->print_content(*buff, false, false, ObXmlFormatType::NO_FORMAT, param_list))) { + LOG_WARN("failed to convert xml binary to xml text", K(ret)); + } else { + xml_text.assign_ptr(buff->ptr(), buff->length()); + if (node_type != ObMulModeNodeType::M_DOCUMENT && OB_FAIL(ObXmlParserUtils::parse_content_text(ctx, xml_text, xml_doc))) { + LOG_WARN("fail to get xml content tree", K(ret), K(node_type)); + } else if (node_type == ObMulModeNodeType::M_DOCUMENT && OB_FAIL(ObXmlParserUtils::parse_document_text(ctx, xml_text, xml_doc))) { + LOG_WARN("fail to get xml tree", K(ret), K(node_type)); + } else { + xml_doc->set_xml_type(node_type); + node = xml_doc; + } + } + } else if (OB_FAIL(ObMulModeFactory::get_xml_base(ctx, xml_text, + ObNodeMemType::BINARY_TYPE, + expect_type, + node))) { + LOG_WARN("fail to get xml base", K(ret)); + } + + if (OB_FAIL(ret)) { + } else if (node->get_unparse() || node->type() == M_UNPARSED) { // unparse try to pasre + if (OB_FAIL(try_to_parse_unparse_binary(ctx, cs_type, node, expect_type, node))) { + LOG_WARN("fail to parse unparse binary", K(ret), K(xml_text)); + } + } + + return ret; +} + +int ObXMLExprHelper::try_to_parse_unparse_binary(ObMulModeMemCtx* mem_ctx, + ObCollationType cs_type, + ObIMulModeBase *input_node, + ObNodeMemType expect_type, + ObIMulModeBase *&res_node) +{ + int ret = OB_SUCCESS; + // serialzie unparese string + ObString unparse_str; + ObXmlDocument *xml_doc = nullptr; + ObStringBuffer *buff = nullptr; + + if (OB_ISNULL(input_node) || !(input_node->type() == M_DOCUMENT || input_node->type() == M_UNPARSED)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unparse node is NULL or not M_DOCUMENT", K(input_node)); + } else if (OB_ISNULL(buff = OB_NEWx(ObStringBuffer, mem_ctx->allocator_, (mem_ctx->allocator_)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("create obstrinbuffer failed", K(input_node)); + } else { + if (OB_FAIL(input_node->print_document(*buff, cs_type, ObXmlFormatType::NO_FORMAT, 0))) { + LOG_WARN("fail to serialize unparse string", K(ret)); + } else { + unparse_str.assign_ptr(buff->ptr(), buff->length()); + } + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObXmlParserUtils::parse_document_text(mem_ctx, unparse_str, xml_doc))) { + if (ret == OB_ERR_PARSER_SYNTAX) { + if (OB_FAIL(ObXmlParserUtils::parse_content_text(mem_ctx, unparse_str, xml_doc))) { + if (ret == OB_ERR_PARSER_SYNTAX) { + ret = OB_ERR_XML_PARSE; + LOG_USER_ERROR(OB_ERR_XML_PARSE); + } + LOG_WARN("fail to parse xml doc", K(unparse_str), K(ret)); + } + } + LOG_WARN("fail to parse xml doc", K(unparse_str), K(ret)); + } + + if (OB_SUCC(ret)) { + if (expect_type == BINARY_TYPE) { + ObXmlBin* bin = nullptr; + if (OB_ISNULL(bin = OB_NEWx(ObXmlBin, mem_ctx->allocator_, (mem_ctx)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc binary", K(ret)); + } else if (OB_FAIL(bin->parse_tree(xml_doc))) { + LOG_WARN("fail to serialize tree.", K(ret)); + } else { + res_node = bin; + } + } else { + res_node = xml_doc; + } + } + + return ret; +} + +int ObXMLExprHelper::pack_xml_res(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res, ObXmlDocument* doc, + ObMulModeMemCtx* mem_ctx, ObMulModeNodeType node_type, + ObString &plain_text) +{ + int ret = OB_SUCCESS; + ObString blob_locator; + ObExprStrResAlloc expr_res_alloc(expr, ctx); + ObTextStringResult blob_res(ObLongTextType, true, &expr_res_alloc); + ObString binary_str; + ObIMulModeBase *xml_base; + if (OB_ISNULL(doc)) { + if (plain_text.length() == 0) { + res.set_string(NULL, 0); + } else if (OB_FAIL(ObMulModeFactory::get_xml_base(mem_ctx, plain_text, + ObNodeMemType::TREE_TYPE, ObNodeMemType::BINARY_TYPE, xml_base, + node_type))) { + LOG_WARN("get xml base failed", K(ret), K(node_type)); + } else if (OB_FAIL(xml_base->get_raw_binary(binary_str, mem_ctx->allocator_))) { + LOG_WARN("get raw binary failed", K(ret)); + } + } else if (FALSE_IT(doc->set_xml_type(node_type))) { + } else if (OB_FAIL(doc->get_raw_binary(binary_str, mem_ctx->allocator_))) { + LOG_WARN("get raw binary failed", K(ret)); + } + + if (OB_FAIL(ret)) { + } else if (OB_FAIL(pack_binary_res(expr, ctx, binary_str, blob_locator))) { + LOG_WARN("pack binary res failed", K(ret)); + } else { + res.set_string(blob_locator.ptr(), blob_locator.length()); + } + return ret; +} + +int ObXMLExprHelper::pack_binary_res(const ObExpr &expr, ObEvalCtx &ctx, ObString binary_str, ObString &blob_locator) +{ + INIT_SUCC(ret); + ObExprStrResAlloc expr_res_alloc(expr, ctx); + ObTextStringResult blob_res(ObLongTextType, true, &expr_res_alloc); + int64_t total_length = binary_str.length(); + if (OB_FAIL(ret)) { + } else if (OB_FAIL(blob_res.init(total_length))) { + LOG_WARN("failed to init blob res", K(ret), K(blob_res), K(total_length)); + } else if (OB_FAIL(blob_res.append(binary_str))) { + LOG_WARN("failed to append xml binary data", K(ret), K(blob_res)); + } else { + blob_res.get_result_buffer(blob_locator); + } + return ret; +} + +int ObXMLExprHelper::parse_namespace_str(ObString &ns_str, ObString &prefix, ObString &uri) +{ + int ret = OB_SUCCESS; + const char *str = ns_str.ptr(); + int64_t str_len = ns_str.length(); + int64_t idx = 0; + const char *prefix_start = NULL; + int64_t prefix_len = 0; + const char *uri_start = NULL; + int64_t uri_len = 0; + if (idx + 4 < str_len && + str[idx] == 'x' && + str[idx+1] == 'm' && + str[idx+2] == 'l' && + str[idx+3] == 'n' && + str[idx+4] == 's') { + idx += 5; + if (str[idx] == ':') { + // parse prefix name + int64_t start = idx + 1; + while (idx < str_len && str[idx] != '=') ++idx; + if (idx < str_len && str[idx] == '=') { + prefix_start = str + start; + prefix_len = idx - start; + } + } + if (idx < str_len && str[idx] == '=') { + // parse uri value + idx += 1; + if (idx < str_len && str[idx] == '"') { + // "xxx" + int start = ++idx; + while(idx < str_len && str[idx] != '"') ++idx; + if (idx < str_len && str[idx] == '"') { + uri_start = str + start; + uri_len = idx - start; + idx += 1; + } else { + ret = OB_ERR_INVALID_XPATH_EXPRESSION; + LOG_WARN("not invalid xml namespace string", K(ret), K(ns_str), K(idx)); + } + } else { + ret = OB_ERR_INVALID_XPATH_EXPRESSION; + LOG_WARN("not invalid xml namespace string", K(ret), K(ns_str), K(idx)); + } + } else { + ret = OB_ERR_INVALID_XPATH_EXPRESSION; + LOG_WARN("not invalid xml namespace string", K(ret), K(ns_str), K(idx)); + } + } else { + ret = OB_ERR_INVALID_XPATH_EXPRESSION; + LOG_WARN("not invalid xml namespace string", K(ret), K(ns_str), K(idx)); + } + + if (OB_SUCC(ret)) { + if (prefix_len > 0) { + prefix.assign_ptr(prefix_start, prefix_len); + } + uri.assign_ptr(uri_start, uri_len); + } + return ret; +} + +int ObXMLExprHelper::construct_namespace_params(ObString &namespace_str, + ObString &default_ns, + ObPathVarObject &prefix_ns, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + ObSEArray namespace_arr; + ObString trim_str = namespace_str.trim_space_only(); + if (trim_str.empty()) { + /* nothing */ + } else if (OB_FAIL(split_on(trim_str, ' ', namespace_arr))) { + LOG_WARN("fail to split on trim string", K(ret), K(trim_str)); + } else { + for (int64_t i = 0; i < namespace_arr.count() && OB_SUCC(ret); i++) { + ObString prefix; + ObString uri; + if (OB_FAIL(parse_namespace_str(namespace_arr.at(i), prefix, uri))) { + LOG_WARN("fail to parse namespace str", K(ret), K(i), K(namespace_arr.at(i))); + } else if (prefix.empty()) { + default_ns = uri; + } else { + if (uri.empty()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("uri is not allow to empty", K(ret), K(prefix)); + } else if (OB_FAIL(add_ns_to_container_node(prefix_ns, prefix, uri, allocator))) { + LOG_WARN("fail to add prefix namespace node", K(ret), K(prefix), K(uri)); + } + } + } // end for + } + return ret; +} + +int ObXMLExprHelper::add_ns_to_container_node(ObPathVarObject &container, + ObString &prefix, + ObString &uri, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + ObDatum *datum; + if (OB_ISNULL(datum = OB_NEWx(ObDatum, (&allocator)))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to alloc datum", K(ret)); + } else if (FALSE_IT(datum->set_string(uri))) { + } else if (OB_FAIL(container.add(prefix, datum))) { + LOG_WARN("fail to add prefix namespace to ObPathVarObject", K(ret), K(*datum)); + } + return ret; +} + +int ObXMLExprHelper::set_string_result(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res, ObString &res_str) +{ + int ret = OB_SUCCESS; + ObTextStringDatumResult text_result(expr.datum_meta_.type_, &expr, &ctx, &res); + int64_t res_len = res_str.length(); + if (OB_FAIL(text_result.init(res_len))) { + LOG_WARN("fail to init string result length", K(ret), K(text_result), K(res_len)); + } else if (OB_FAIL(text_result.append(res_str))) { + LOG_WARN("fail to append xml format string", K(ret), K(res_str), K(text_result)); + } else { + text_result.set_result(); + } + return ret; +} + +int ObXMLExprHelper::get_str_from_expr(const ObExpr *expr, + ObEvalCtx &ctx, + ObString &res, + ObIAllocator &allocator) +{ + int ret = OB_SUCCESS; + ObDatum *datum = NULL; + ObObjType val_type = expr->datum_meta_.type_; + uint16_t sub_schema_id = expr->obj_meta_.get_subschema_id(); + if (OB_FAIL(expr->eval(ctx, datum))) { + LOG_WARN("eval xml arg failed", K(ret)); + } else if (!ob_is_string_type(val_type)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("input type error", K(val_type)); + } else if (FALSE_IT(res = datum->get_string())) { + } else if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, *datum, + expr->datum_meta_, expr->obj_meta_.has_lob_header(), res))) { + LOG_WARN("fail to get real data.", K(ret), K(res)); + } + return ret; +} + +int ObXMLExprHelper::parse_xml_str(ObMulModeMemCtx *ctx, const ObString &xml_text, ObXmlDocument *&xml_doc) +{ + int ret = OB_SUCCESS; + if(ObXmlParserUtils::has_xml_decl(xml_text)) { + if (OB_FAIL(ObXmlParserUtils::parse_document_text(ctx, xml_text, xml_doc))) { + if (ret == OB_ERR_PARSER_SYNTAX) { + ret = OB_ERR_XML_PARSE; + LOG_USER_ERROR(OB_ERR_XML_PARSE); + } + LOG_WARN("fail to parse xml doc", K(xml_text), K(ret)); + } + } else if(OB_FAIL(ObXmlParserUtils::parse_content_text(ctx, xml_text, xml_doc))) { + if (ret == OB_ERR_PARSER_SYNTAX) { + ret = OB_ERR_XML_PARSE; + LOG_USER_ERROR(OB_ERR_XML_PARSE); + } + LOG_WARN("fail to parse xml doc", K(xml_text), K(ret)); + } + return ret; +} + +int ObXMLExprHelper::get_xmltype_from_expr(const ObExpr *expr, + ObEvalCtx &ctx, + ObDatum *&xml_datum) +{ + int ret = OB_SUCCESS; + ObObjType val_type = expr->datum_meta_.type_; + uint16_t sub_schema_id = expr->obj_meta_.get_subschema_id(); + if (!ob_is_xml_sql_type(val_type, sub_schema_id)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_USER_ERROR(OB_ERR_INVALID_TYPE_FOR_OP, "-", "-"); + LOG_WARN("inconsistent datatypes", K(ret), K(ob_obj_type_str(val_type))); + } else if (OB_FAIL(expr->eval(ctx, xml_datum))) { + LOG_WARN("eval xml arg failed", K(ret)); + } + return ret; +} + +bool ObXMLExprHelper::is_xml_leaf_node(ObMulModeNodeType node_type) +{ + return node_type == ObMulModeNodeType::M_ATTRIBUTE || + node_type == ObMulModeNodeType::M_NAMESPACE || + node_type == ObMulModeNodeType::M_CDATA || + node_type == ObMulModeNodeType::M_TEXT; +} + +bool ObXMLExprHelper::is_xml_text_node(ObMulModeNodeType node_type) +{ + return node_type == ObMulModeNodeType::M_CDATA || + node_type == ObMulModeNodeType::M_TEXT; +} + +bool ObXMLExprHelper::is_xml_attribute_node(ObMulModeNodeType node_type) +{ + return node_type == ObMulModeNodeType::M_ATTRIBUTE || + node_type == ObMulModeNodeType::M_NAMESPACE; +} + +bool ObXMLExprHelper::is_xml_element_node(ObMulModeNodeType node_type) +{ + return node_type == ObMulModeNodeType::M_ELEMENT || + node_type == ObMulModeNodeType::M_DOCUMENT || + node_type == ObMulModeNodeType::M_CONTENT; +} + +bool ObXMLExprHelper::is_xml_root_node(ObMulModeNodeType node_type) +{ + return node_type == ObMulModeNodeType::M_DOCUMENT || + node_type == ObMulModeNodeType::M_CONTENT; +} + +void ObXMLExprHelper::replace_xpath_ret_code(int &ret) +{ + if (ret == OB_OP_NOT_ALLOW) { + ret = OB_XPATH_EXPRESSION_UNSUPPORTED; + } else if (ret == OB_ERR_PARSER_SYNTAX) { + ret = OB_ERR_XML_PARSE; + } else if (ret == OB_ALLOCATE_MEMORY_FAILED) { + // do nothing + } else if (ret == OB_ERR_WRONG_VALUE) { + ret = OB_ERR_INVALID_INPUT; + } else { + ret = OB_ERR_INVALID_XPATH_EXPRESSION; + } +} + +int ObXMLExprHelper::check_xml_document_unparsed(ObMulModeMemCtx* mem_ctx, ObString binary_str, bool &validity) +{ + INIT_SUCC(ret); + ObMulModeNodeType node_type = M_MAX_TYPE; + if (OB_FAIL(ObXmlUtil::xml_bin_type(binary_str, node_type))) { + LOG_WARN("get xml bin type failed", K(ret)); + } else { + ObXmlParser parser(mem_ctx); + parser.set_only_syntax_check(); + if (node_type == M_UNPARESED_DOC && OB_FAIL(parser.parse_document(binary_str))) { + ret = OB_SUCCESS; + validity = false; + } else { + validity = true; + } + } + return ret; +} + +int ObXMLExprHelper::parse_xml_document_unparsed(ObMulModeMemCtx* mem_ctx, ObString binary_str, ObString &res_str, ObXmlDocument* &res_doc) +{ + INIT_SUCC(ret); + ObMulModeNodeType node_type = M_MAX_TYPE; + ObXmlDocument* doc = nullptr; + ObXmlBin bin(mem_ctx); + ObIMulModeBase* tree = nullptr; + ObXmlParser parser(mem_ctx); + ObStringBuffer buff(mem_ctx->allocator_); + if (OB_FAIL(ObXmlUtil::xml_bin_type(binary_str, node_type))) { + LOG_WARN("get xml bin type failed", K(ret)); + } else if (node_type == ObMulModeNodeType::M_UNPARESED_DOC) { + if (OB_FAIL(ObXmlParserUtils::parse_document_text(mem_ctx, binary_str, doc))) { + LOG_WARN("parse document text failed", K(ret)); + } else if (FALSE_IT(tree = doc)) { + } else if (OB_FAIL(bin.parse_tree(tree))) { + LOG_WARN("parse tree failed", K(ret)); + } else if (OB_FAIL(bin.print_document(buff, CS_TYPE_UTF8MB4_GENERAL_CI, ObXmlFormatType::NO_FORMAT))) { + LOG_WARN("print document failed"); + } else if (OB_FAIL(parser.parse_document(buff.string()))) { + ret = OB_ERR_XML_PARSE; + LOG_USER_ERROR(OB_ERR_XML_PARSE); + LOG_WARN("parse xml plain text as document failed.", K(ret)); + } else { + res_str = buff.string(); + res_doc = parser.document(); + } + } + return ret; +} + +int ObXMLExprHelper::content_unparsed_binary_check_doc(ObMulModeMemCtx* mem_ctx, ObString binary_str, ObString &res_str) { + INIT_SUCC(ret); + ObMulModeNodeType node_type = M_MAX_TYPE; + ObXmlDocument* doc = nullptr; + ObXmlBin bin(mem_ctx); + ObIMulModeBase* tree = nullptr; + ObXmlParser parser(mem_ctx); + ObStringBuffer buff(mem_ctx->allocator_); + ObXmlDocument* new_doc = nullptr; + ParamPrint param_list; // unused + if (OB_FAIL(ObXmlUtil::xml_bin_type(binary_str, node_type))) { + LOG_WARN("get xml bin type failed", K(ret)); + } else if (node_type == ObMulModeNodeType::M_UNPARSED) { + if (OB_FAIL(ObXmlParserUtils::parse_content_text(mem_ctx, binary_str, doc))) { + LOG_WARN("parse document text failed", K(ret)); + } else if (FALSE_IT(tree = doc)) { + } else if (OB_FAIL(bin.parse_tree(tree))) { + LOG_WARN("parse tree failed", K(ret)); + } else if (OB_FAIL(bin.print_content(buff, false, false, ObXmlFormatType::NO_FORMAT, param_list))) { + LOG_WARN("print document failed"); + } else if (OB_FAIL(parser.parse_document(buff.string()))) { + // try to parse content intto document, if it fails, leave the content unchanged + ret = OB_SUCCESS; + res_str = binary_str; + } else if (FALSE_IT(new_doc = parser.document())) { + } else if (OB_FAIL(new_doc->get_raw_binary(res_str, mem_ctx->allocator_))) { + LOG_WARN("get raw binary failed", K(ret)); + } + } + return ret; +} + +int ObXMLExprHelper::check_element_validity(ObMulModeMemCtx* mem_ctx, ObXmlElement *in_ele, ObXmlElement *&out_ele, bool &validity) { + INIT_SUCC(ret); + ObXmlParser parser(mem_ctx); + ObStringBuffer buff(mem_ctx->allocator_); + if (OB_ISNULL(in_ele)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("in_ele is NULL", K(ret)); + } else { + in_ele->set_unparse(1); + if (OB_FAIL(in_ele->print_element(buff, 0, ObXmlFormatType::NO_FORMAT))) { + LOG_WARN("print document failed"); + } else if (OB_FAIL(parser.parse_document(buff.string()))) { + ret = OB_SUCCESS; + validity = false; + } else { + validity = true; + in_ele->set_unparse(0); + ObXmlDocument* doc = parser.document(); + if (OB_NOT_NULL(doc) && doc->size() > 0){ + out_ele = static_cast(doc->at(0)); + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get valid xml element", K(ret)); + } + } + } + return ret; +} + +int ObXMLExprHelper::check_doc_validity(ObMulModeMemCtx* mem_ctx, ObXmlDocument *&doc, bool &validity) { + INIT_SUCC(ret); + ObXmlParser parser(mem_ctx); + ObStringBuffer buff(mem_ctx->allocator_); + if (OB_FAIL(doc->print_document(buff, CS_TYPE_UTF8MB4_GENERAL_CI, ObXmlFormatType::NO_FORMAT))) { + LOG_WARN("print document failed"); + } else if (OB_FAIL(parser.parse_document(buff.string()))) { + ret = OB_SUCCESS; + validity = false; + } else if (OB_ISNULL(doc = parser.document())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("parser document return NULL", K(ret)); + } else { + validity = true; + } + return ret; +} +#endif // OB_BUILD_ORACLE_XML +// not all udts sql types based on lobs, so not handle xml in process_lob_locator_results +int ObXMLExprHelper::process_sql_udt_results(ObObj& value, sql::ObResultSet &result) +{ + int ret = OB_SUCCESS; + ObArenaAllocator *allocator = NULL; + sql::ObSQLSessionInfo *session_info = &result.get_session(); + if (OB_FAIL(result.get_exec_context().get_convert_charset_allocator(allocator))) { + LOG_WARN("fail to get convert charset allocator", K(ret)); + } else if (OB_ISNULL(allocator)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("lob fake allocator is null.", K(ret), K(value)); + } else if (OB_FAIL(process_sql_udt_results(value, + allocator, + &result.get_session(), + &result.get_exec_context(), + result.is_ps_protocol()))) { + LOG_WARN("convert udt to client format failed.", K(ret), K(value)); + } else { /* do nothing */ } + return ret; +} + +int ObXMLExprHelper::process_sql_udt_results(common::ObObj& value, + common::ObIAllocator *allocator, + sql::ObSQLSessionInfo *session_info, + sql::ObExecContext *exec_context, + bool is_ps_protocol, + const ColumnsFieldIArray *fields, + ObSchemaGetterGuard *schema_guard) // need fields and schema guard +{ + int ret = OB_SUCCESS; + if (!value.is_user_defined_sql_type() && !value.is_collection_sql_type() && !value.is_geometry()) { + ret = OB_NOT_SUPPORTED; + OB_LOG(WARN, "not supported udt type", K(ret), + K(value.get_type()), K(value.get_udt_subschema_id())); +#ifdef OB_BUILD_ORACLE_XML + } else if (value.is_xml_sql_type()) { + bool is_client_support_binary_xml = false; // client receive xml as json, like json + if (value.is_null() || value.is_nop_value()) { + // do nothing + } else if (is_client_support_binary_xml) { + // convert to udt client format + } else { + ObString data; + ObLobLocatorV2 loc(value.get_string(), true); + ObString converted_str; + if (!loc.is_null()) { + ObTextStringIter instr_iter(ObLongTextType, CS_TYPE_BINARY, value.get_string(), true); + if (OB_FAIL(instr_iter.init(0, session_info, allocator))) { + LOG_WARN("init lob str inter failed", K(ret), K(value)); + } else if (OB_FAIL(instr_iter.get_full_data(data))) { + LOG_WARN("get xml full data failed", K(value)); + } else { + ObMulModeNodeType node_type = M_MAX_TYPE; + ObStringBuffer* jbuf = nullptr; + ParamPrint param_list; + param_list.indent = 2; + ObIMulModeBase *node = nullptr; + ObMulModeMemCtx* ctx = nullptr; + + if (OB_FAIL(ObXmlUtil::create_mulmode_tree_context(allocator, ctx))) { + LOG_WARN("fail to create tree memory context", K(ret)); + } else if (OB_ISNULL(allocator)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid input args", K(ret), KP(allocator)); + } else if (data.length() == 0) { + } else if (OB_FAIL(ObXmlUtil::xml_bin_type(data, node_type))) { + LOG_WARN("xml bin type failed", K(ret)); + } else if (OB_FAIL(ObMulModeFactory::get_xml_base(ctx, data, + ObNodeMemType::BINARY_TYPE, + ObNodeMemType::BINARY_TYPE, + node))) { + LOG_WARN("fail to get xml base", K(ret), K(data.length())); + } + + ObCollationType cs_type = session_info->get_local_collation_connection(); + + if (OB_FAIL(ret) || data.length() == 0) { + } else if (OB_ISNULL(jbuf = OB_NEWx(ObStringBuffer, allocator, (allocator)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to construct buffer", K(ret)); + } else if ((ObMulModeNodeType::M_DOCUMENT == node_type || + ObMulModeNodeType::M_UNPARESED_DOC == node_type) // /Although it is judged here that node_type=M_UNPARESED_DOC, it can actually go here, and the label has been replaced with DOCUMENT + && OB_FAIL(node->print_document(*jbuf, cs_type, ObXmlFormatType::WITH_FORMAT))) { + LOG_WARN("print document failed", K(ret)); + } else if ((ObMulModeNodeType::M_CONTENT == node_type || + ObMulModeNodeType::M_UNPARSED == node_type) && + OB_FAIL(node->print_content(*jbuf, false, false, ObXmlFormatType::WITH_FORMAT, param_list))) { + LOG_WARN("print content failed", K(ret)); + } else { + data.assign_ptr(jbuf->ptr(), jbuf->length()); + } + + if (OB_SUCC(ret) && cs_type != CS_TYPE_UTF8MB4_BIN) { + if (OB_FAIL(ObCharset::charset_convert(*allocator, data, CS_TYPE_UTF8MB4_BIN, + cs_type, converted_str))) { + LOG_WARN("charset convertion failed", K(ret), K(data)); + } + } else { + converted_str = data; + } + + if (OB_SUCC(ret)) { + value.set_udt_value(converted_str.ptr(), converted_str.length()); + } + } + } + } +#endif // OB_BUILD_ORACLE_XML + } else if (value.is_geometry()) { + if (is_ps_protocol) { +#ifdef OB_BUILD_ORACLE_PL + ObObj result; + if (OB_ISNULL(exec_context)) { + ret = OB_BAD_NULL_ERROR; + } else if (OB_FAIL(pl::ObSdoGeometry::wkb_to_pl_extend(exec_context->get_allocator(), exec_context, value.get_string(), result))) { + LOG_WARN("failed to get geometry wkb from pl extend", K(ret)); + } else { + value = result; + } +#else + ret = OB_NOT_SUPPORTED; +#endif + } + } else { + if (OB_ISNULL(exec_context)) { + ret = OB_BAD_NULL_ERROR; + } else if (OB_ISNULL(exec_context->get_physical_plan_ctx())) { + // no physical plan, build new one + if (OB_ISNULL(fields)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("no fields to rebuild udt meta", K(ret), K(lbt())); + } else if (OB_FAIL(exec_context->create_physical_plan_ctx())) { + LOG_WARN("failed to create physical plan ctx of subschema id", K(ret), K(lbt())); + } else if (OB_FAIL(exec_context->get_physical_plan_ctx()->build_subschema_by_fields(fields, schema_guard))) { + LOG_WARN("failed to rebuild_subschema by fields", K(ret), K(*fields), K(lbt())); + } + } + if (OB_FAIL(ret)) { + } else { + const uint16_t subschema_id = value.get_meta().get_subschema_id(); + ObSqlUDTMeta udt_meta; + if (OB_ISNULL(exec_context->get_physical_plan_ctx())) { + // build temp subschema id + } else if (OB_FAIL(exec_context->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } + if (OB_FAIL(ret)) { + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_meta.udt_id_)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("not supported to get udt meta", K(ret), K(udt_meta.udt_id_)); + } else if (!is_ps_protocol) { + ObSqlUDT sql_udt; + sql_udt.set_udt_meta(udt_meta); + ObString res_str; + if (OB_FAIL(sql::ObSqlUdtUtils::convert_sql_udt_to_string(value, allocator, exec_context, + sql_udt, res_str))) { + LOG_WARN("failed to convert udt to string", K(ret), K(subschema_id)); + } else { + value.set_udt_value(res_str.ptr(), res_str.length()); + } + } else { + ObString udt_data = value.get_string(); + ObObj result; + if (OB_FAIL(ObSqlUdtUtils::cast_sql_record_to_pl_record(exec_context, + result, + udt_data, + udt_meta))) { + LOG_WARN("failed to cast sql collection to pl collection", K(ret), K(udt_meta.udt_id_)); + } else { + value = result; + } + } + } + } + return ret; +} + +} // sql +} // oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_xml_func_helper.h b/src/sql/engine/expr/ob_expr_xml_func_helper.h new file mode 100644 index 0000000000..2ee9767d34 --- /dev/null +++ b/src/sql/engine/expr/ob_expr_xml_func_helper.h @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + * This file is for define of func xml expr helper + */ + +#ifndef OCEANBASE_SQL_OB_EXPR_XML_FUNC_HELPER_H_ +#define OCEANBASE_SQL_OB_EXPR_XML_FUNC_HELPER_H_ + +#include "sql/engine/expr/ob_expr_util.h" +#include "sql/engine/expr/ob_expr_lob_utils.h" +#include "sql/engine/expr/ob_expr_result_type_util.h" +#ifdef OB_BUILD_ORACLE_XML +#include "lib/xml/ob_xml_parser.h" +#include "lib/xml/ob_xpath.h" +#include "lib/xml/ob_xml_tree.h" +#include "lib/xml/ob_xml_util.h" +#endif // OB_BUILD_ORACLE_XML + +using namespace oceanbase::common; + +namespace oceanbase +{ +namespace sql +{ + +class ObXMLExprHelper final +{ +public: +#ifdef OB_BUILD_ORACLE_XML + static int add_binary_to_element(ObMulModeMemCtx* mem_ctx, ObString bianry_value, ObXmlElement &element); + static int get_xml_base(ObMulModeMemCtx* mem_ctx, ObDatum *xml_datum, ObCollationType cs_type, + ObNodeMemType expect_type, ObIMulModeBase *&node); + static int get_xml_base(ObMulModeMemCtx* mem_ctx, ObDatum *xml_datum, ObCollationType cs_type, + ObNodeMemType expect_type, ObIMulModeBase *&node, ObMulModeNodeType &node_type, bool is_reparse = false); + static int try_to_parse_unparse_binary(ObMulModeMemCtx* mem_ctx, ObCollationType cs_type, + ObIMulModeBase *input_node, ObNodeMemType expect_type, + ObIMulModeBase *&res_node); + static int pack_binary_res(const ObExpr &expr, ObEvalCtx &ctx, + ObString binary_str, ObString &blob_locator); + static int pack_xml_res(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res, ObXmlDocument* doc, + ObMulModeMemCtx* mem_ctx, ObMulModeNodeType node_type, + ObString &plain_text); + // for namespace + static int construct_namespace_params(ObString &namespace_str, + ObString &default_ns, + ObPathVarObject &prefix_ns, + ObIAllocator &allocator); + static int parse_namespace_str(ObString &ns_str, ObString &prefix, ObString &uri); + // set string result + static int set_string_result(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res, ObString &res_str); + // get xmltype str from input expr + static int get_xmltype_from_expr(const ObExpr *expr, + ObEvalCtx &ctx, + ObDatum *&xml_datum); + static int get_str_from_expr(const ObExpr *expr, + ObEvalCtx &ctx, + ObString &res, + ObIAllocator &allocator); + static int parse_xml_str(ObMulModeMemCtx *ctx, const ObString &xml_text, ObXmlDocument *&xml_doc); + + // classify xml node type + static bool is_xml_leaf_node(ObMulModeNodeType node_type); + static bool is_xml_text_node(ObMulModeNodeType node_type); + static bool is_xml_element_node(ObMulModeNodeType node_type); + static bool is_xml_root_node(ObMulModeNodeType node_type); + static bool is_xml_attribute_node(ObMulModeNodeType node_type); + + static void replace_xpath_ret_code(int &ret); + static int check_xml_document_unparsed(ObMulModeMemCtx* mem_ctx, ObString binary_str, bool &validity); + static int parse_xml_document_unparsed(ObMulModeMemCtx* mem_ctx, ObString binary_str, ObString &res_str, ObXmlDocument* &res_doc); + static int content_unparsed_binary_check_doc(ObMulModeMemCtx* mem_ctx, ObString binary_str, ObString &res_str); + static int check_element_validity(ObMulModeMemCtx* mem_ctx, ObXmlElement *in_ele, ObXmlElement *&out_ele, bool &validity); + static int check_doc_validity(ObMulModeMemCtx* mem_ctx, ObXmlDocument *&doc, bool &validity); +#endif // OB_BUILD_ORACLE_XML + static int process_sql_udt_results(common::ObObj& value, sql::ObResultSet &result); + static int process_sql_udt_results(common::ObObj& value, + common::ObIAllocator *allocator, + sql::ObSQLSessionInfo *session_info, + sql::ObExecContext *exec_context, + bool is_ps_protocol, + const ColumnsFieldIArray *fields = NULL, + ObSchemaGetterGuard *schema_guard = NULL); + static uint64_t get_tenant_id(ObSQLSessionInfo *session); +#ifdef OB_BUILD_ORACLE_XML +private: + static int add_ns_to_container_node(ObPathVarObject &container, + ObString &prefix, + ObString &uri, + ObIAllocator &allocator); +#endif // OB_BUILD_ORACLE_XML +}; +} // sql +} // oceanbase + +#endif // OCEANBASE_SQL_OB_EXPR_XML_FUNC_HELPER_H_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_geo_expr_utils.cpp b/src/sql/engine/expr/ob_geo_expr_utils.cpp index 9379306c1f..47f955b669 100644 --- a/src/sql/engine/expr/ob_geo_expr_utils.cpp +++ b/src/sql/engine/expr/ob_geo_expr_utils.cpp @@ -26,7 +26,9 @@ #include "lib/geo/ob_geo_check_empty_visitor.h" #include "lib/geo/ob_geo_latlong_check_visitor.h" #include "lib/geo/ob_geo_zoom_in_visitor.h" - +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_3d.h" +#include "lib/geo/ob_geo_reverse_coordinate_visitor.h" using namespace oceanbase::common; namespace oceanbase { @@ -90,15 +92,12 @@ int ObGeoExprUtils::build_geometry(ObIAllocator &allocator, ObGeometry *&geo, const ObSrsItem *srs, const char *func_name, - const bool need_normlize /* = true */, - const bool need_check_ring /* = false */, - const bool need_correct /* = true */) + uint8_t build_flag) { int ret = OB_SUCCESS; ObGeoErrLogInfo log_info; - if (OB_FAIL(ObGeoTypeUtil::build_geometry(allocator, wkb, geo, srs, log_info, - need_normlize, need_check_ring, need_correct))) { + if (OB_FAIL(ObGeoTypeUtil::build_geometry(allocator, wkb, geo, srs, log_info, build_flag))) { if (OB_ERR_GIS_INVALID_DATA == ret && OB_NOT_NULL(func_name)) { LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); } else if (OB_ERR_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE == ret && OB_NOT_NULL(func_name)) { @@ -119,6 +118,7 @@ int ObGeoExprUtils::build_geometry(ObIAllocator &allocator, return ret; } +// 3d-wkb is allow, and will return ObGeometry3D obj int ObGeoExprUtils::construct_geometry(ObIAllocator &allocator, const ObString &wkb, omt::ObSrsCacheGuard &srs_guard, @@ -153,7 +153,7 @@ int ObGeoExprUtils::construct_geometry(ObIAllocator &allocator, if (OB_FAIL(ret)) { // do nothing } else if (OB_FAIL(ObGeoTypeUtil::construct_geometry(allocator, wkb, srs, geo, has_srid))) { - if (OB_ERR_GIS_INVALID_DATA == ret && OB_NOT_NULL(func_name)) { + if ((OB_ERR_GIS_INVALID_DATA == ret && OB_NOT_NULL(func_name))) { LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); } else if (OB_ERR_INVALID_GEOMETRY_TYPE == ret && OB_NOT_NULL(func_name)) { ret = OB_ERR_GIS_INVALID_DATA; @@ -235,14 +235,21 @@ int ObGeoExprUtils::correct_coordinate_range(const ObSrsItem *srs_item, const char *func_name) { int ret = OB_SUCCESS; - ObGeoLatlongCheckVisitor range_visitor(srs_item); + if (ObGeoTypeUtil::is_3d_geo_type(geo->type())) { + ObGeometry3D *geo_3d = reinterpret_cast(geo); + if (OB_FAIL(geo_3d->correct_lon_lat(srs_item))) { + LOG_WARN("fail to correct lon lat of 3D geometry", K(ret)); + } + } else { + ObGeoLatlongCheckVisitor range_visitor(srs_item); - if (OB_FAIL(geo->do_visit(range_visitor))) { - ret = OB_ERR_GIS_INVALID_DATA; - LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); - LOG_WARN("failed to reverse geometry coordinate", K(ret)); - } else if (range_visitor.has_changed()) { - LOG_WARN("Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY"); + if (OB_FAIL(geo->do_visit(range_visitor))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); + LOG_WARN("failed to reverse geometry coordinate", K(ret)); + } else if (range_visitor.has_changed()) { + LOG_WARN("Coordinate values were coerced into range [-180 -90, 180 90] for GEOGRAPHY"); + } } return ret; @@ -345,7 +352,9 @@ int ObGeoExprUtils::parse_axis_order(const ObString option_str, } if (OB_FAIL(ret)) { strncpy(err_str, axis_order_key.ptr(), axis_order_key.length() < STR_LEN_MAX ? axis_order_key.length() : STR_LEN_MAX); - LOG_USER_ERROR(OB_ERR_INVALID_OPTION_VALUE, axis_order_val.ptr(), err_str, func_name); + char val_err_str[STR_LEN_MAX] = {0}; // cstyle err string + strncpy(val_err_str, axis_order_val.ptr(), axis_order_val.length() < (STR_LEN_MAX - 1) ? axis_order_val.length() : (STR_LEN_MAX - 1)); + LOG_USER_ERROR(OB_ERR_INVALID_OPTION_VALUE, val_err_str, err_str, func_name); } } else if (ret == OB_INVALID_OPTION) { ret = OB_ERR_INVALID_OPTION_KEY_VALUE_PAIR; @@ -389,11 +398,18 @@ int ObGeoExprUtils::check_empty(ObGeometry *geo, { INIT_SUCC(ret); is_empty = false; - ObGeoCheckEmptyVisitor check_empty_visitor; - if (OB_FAIL(geo->do_visit(check_empty_visitor))) { - LOG_WARN("check empty geo failed", K(ret)); + if (ObGeoTypeUtil::is_3d_geo_type(geo->type())) { + ObGeometry3D *geo3D = reinterpret_cast(geo); + if (OB_FAIL(geo3D->check_empty(is_empty))) { + LOG_WARN("fail to check 3D geometry empty", K(ret)); + } } else { - is_empty = check_empty_visitor.get_result(); + ObGeoCheckEmptyVisitor check_empty_visitor; + if (OB_FAIL(geo->do_visit(check_empty_visitor))) { + LOG_WARN("check empty geo failed", K(ret)); + } else { + is_empty = check_empty_visitor.get_result(); + } } return ret; } @@ -489,7 +505,7 @@ int ObGeoExprUtils::get_box_bestsrid(ObGeogBox *geo_box1, } else { geo_box = *geo_box1; if (geo_box2 != NULL) { - ObGeoBoxUtil::box_uion(*geo_box2, geo_box); + ObGeoBoxUtil::box_union(*geo_box2, geo_box); } ObGeoBoxUtil::get_box_center(geo_box, center); width = 180.0 * ObGeoBoxUtil::caculate_box_angular_width(geo_box) / M_PI; @@ -543,22 +559,15 @@ int ObGeoExprUtils::normalize_wkb(const ObSrsItem *srs, if (OB_NOT_NULL(srs) && (srs->is_geographical_srs() || srs->is_lat_long_order())) { // points in geom need to be normalized - ObString calc_wkb; - char *calc_buf = (char *)allocator.alloc(wkb.length()); - if (OB_ISNULL(calc_buf)) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("allocate memory for normalize wkb failed", K(wkb.length()), K(ret)); + ObGeoNormalizeVisitor normalize_visitor(srs); + ObGeoErrLogInfo log_info; + if (OB_FAIL(ObGeoTypeUtil::build_geometry(allocator, wkb, geo, srs, log_info, ObGeoBuildFlag::GEO_ALLOW_3D))) { + LOG_WARN("fail to build geometry", K(ret)); + } else if (OB_FAIL(geo->do_visit(normalize_visitor))) { + LOG_WARN("normalize geo failed", K(ret)); } else { - MEMCPY(calc_buf, wkb.ptr(), wkb.length()); - calc_wkb.assign(calc_buf, wkb.length()); - ObGeoNormalizeVisitor normalize_visitor(srs); - if (OB_FAIL(ObGeoTypeUtil::create_geo_by_wkb(allocator, calc_wkb, srs, geo, false))) { - LOG_WARN("get geo by wkb failed", K(ret)); - } else if (OB_FAIL(geo->do_visit(normalize_visitor))) { - LOG_WARN("normalize geo failed", K(ret)); - } else { - // do nothing - } + // do nothing + ObString wkb(geo->length(), geo->val()); } } @@ -615,6 +624,26 @@ int ObGeoExprUtils::geo_to_wkb(ObGeometry &geo, const ObSrsItem *srs_item, ObString &res_wkb, uint32_t srs_id /* = 0 */) +{ + int ret = OB_SUCCESS; + if (ObGeoTypeUtil::is_3d_geo_type(geo.type())) { + if (OB_FAIL(geo_to_3d_wkb(geo, expr, ctx, srs_item, res_wkb, srs_id))) { + LOG_WARN("fail to write 3d geo to wkb", K(ret)); + } + } else { + if (OB_FAIL(geo_to_2d_wkb(geo, expr, ctx, srs_item, res_wkb, srs_id))) { + LOG_WARN("fail to write 2d geo to wkb", K(ret)); + } + } + return ret; +} + +int ObGeoExprUtils::geo_to_2d_wkb(ObGeometry &geo, + const ObExpr &expr, + ObEvalCtx &ctx, + const ObSrsItem *srs_item, + ObString &res_wkb, + uint32_t srs_id /* = 0 */) { int ret = OB_SUCCESS; ObGeoWkbSizeVisitor wkb_size_visitor; @@ -631,7 +660,7 @@ int ObGeoExprUtils::geo_to_wkb(ObGeometry &geo, if (OB_FAIL(str_result.init(res_size, nullptr))) { LOG_WARN("fail to init result", K(ret), K(res_size)); } else if (OB_FAIL(str_result.get_reserved_buffer(res_buf, res_buf_len))) { - LOG_WARN(""); + LOG_WARN("fail to get reserver buffer", K(ret)); } else if (res_buf_len < res_size) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); @@ -664,6 +693,48 @@ int ObGeoExprUtils::geo_to_wkb(ObGeometry &geo, return ObGeoTypeUtil::to_wkb(*expr_ctx.calc_buf_, geo, srs_item, res_wkb); } +int ObGeoExprUtils::geo_to_3d_wkb(common::ObGeometry &geo, + const ObExpr &expr, + ObEvalCtx &ctx, + const common::ObSrsItem *srs_item, + common::ObString &res_wkb, + uint32_t srs_id /*= 0 */) +{ + int ret = OB_SUCCESS; + if (!ObGeoTypeUtil::is_3d_geo_type(geo.type())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("geometry is not 3d type", K(ret), K(geo.type())); + } else { + ObString no_srid_wkb = geo.to_wkb(); + int64_t res_size = WKB_OFFSET + no_srid_wkb.length(); + ObDatum tmp_res; // not used + char *res_buf = nullptr; + int64_t res_buf_len = 0; + ObTextStringDatumResult str_result(expr.datum_meta_.type_, &expr, &ctx, &tmp_res); + if (OB_FAIL(str_result.init(res_size, nullptr))) { + LOG_WARN("fail to init result", K(ret), K(res_size)); + } else if (OB_FAIL(str_result.get_reserved_buffer(res_buf, res_buf_len))) { + LOG_WARN("fail to get reserved buffer", K(ret)); + } else if (res_buf_len < res_size) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get invalid res buf len", K(ret), K(res_buf_len), K(res_size)); + } else { + uint32_t srid = srs_item == NULL ? srs_id : srs_item->get_srid(); + ObGeoWkbByteOrderUtil::write(res_buf, srid); + uint8_t encode_ver = ENCODE_GEO_VERSION(geo.get_version()); + *(res_buf + WKB_GEO_SRID_SIZE) = encode_ver; + if (OB_FAIL(str_result.lseek(WKB_OFFSET, 0))) { + LOG_WARN("fail to lseek res", K(ret), K(str_result)); + } else if (OB_FAIL(str_result.append(no_srid_wkb))) { + LOG_WARN("fail to append wkb", K(ret)); + } else { + str_result.get_result_buffer(res_wkb); + } + } + } + return ret; +} + void ObGeoExprUtils::geo_func_error_handle(int error_ret, const char* func_name) { if (error_ret == OB_INVALID_ARGUMENT) { @@ -704,5 +775,309 @@ int ObGeoExprUtils::pack_geo_res(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &re return ret; } +int ObGeoExprUtils::reverse_coordinate(ObGeometry *geo, const char *func_name) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(geo)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null geo", K(ret)); + } else if (ObGeoTypeUtil::is_3d_geo_type(geo->type())) { + ObGeometry3D *geo_3d = static_cast(geo); + if (OB_FAIL(geo_3d->reverse_coordinate())) { + LOG_WARN("fail to reserver coordiante in geo 3d", K(ret)); + } + } else { + ObGeoReverseCoordinateVisitor rcoord_visitor; + if (OB_FAIL(geo->do_visit(rcoord_visitor))) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); + LOG_WARN("failed to reverse geometry coordinate", K(ret)); + } + } + return ret; +} + +int ObGeoExprUtils::ob_geo_find_unit(const ObGeoUnit *units, const ObString &name, double &factor) +{ + INIT_SUCC(ret); + int begin = 0; + int end = sizeof(OB_GEO_UNITS)/sizeof(ObGeoUnit) - 1; + bool is_found = false; + while (begin <= end && !is_found) { + int mid = begin + (end - begin) / 2; + const int cmp_len = MIN(strlen(units[mid].name), name.length()); + int cmp_res = strncasecmp(units[mid].name, name.ptr(), cmp_len); + if (cmp_res > 0) { + end = mid - 1; + } else if (cmp_res < 0) { + begin = mid + 1; + } else { + if (name.length() == strlen(units[mid].name)) { + is_found = true; + factor = units[mid].factor; + } else if (name.length() > strlen(units[mid].name)) { + begin = mid + 1; + } else { + end = mid - 1; + } + } + } + + if (!is_found) { + ret = OB_ERR_UNIT_NOT_FOUND; + char name_str[name.length() + 1]; + name_str[name.length()] = '\0'; + MEMCPY(name_str, name.ptr(), name.length()); + LOG_USER_ERROR(OB_ERR_UNIT_NOT_FOUND, name_str); + } + return ret; +} + +int ObGeoExprUtils::length_unit_conversion(const ObString &unit_str, const ObSrsItem *srs, + double in_num, double &out_num) +{ + int ret = OB_SUCCESS; + double factor = 0.0; + if (OB_ISNULL(srs) || srs->get_srid() == 0) { + ret = OB_ERR_GEOMETRY_IN_UNKNOWN_LENGTH_UNIT; + char name_str[unit_str.length() + 1]; + name_str[unit_str.length()] = '\0'; + MEMCPY(name_str, unit_str.ptr(), unit_str.length()); + LOG_USER_ERROR(OB_ERR_GEOMETRY_IN_UNKNOWN_LENGTH_UNIT, N_ST_DISTANCE, name_str); + } else if (OB_FAIL(ob_geo_find_unit(OB_GEO_UNITS, unit_str, factor))) { + LOG_WARN("invalid geo unit name", K(ret), K(unit_str)); + } else { + out_num = in_num * (srs->linear_uint() / factor); + } + return ret; +} + +int ObGeoExprUtils::get_input_geometry(ObIAllocator &allocator, ObDatum *gis_datum, ObEvalCtx &ctx, ObExpr *gis_arg, + omt::ObSrsCacheGuard &srs_guard, const char *func_name, + const ObSrsItem *&srs, ObGeometry *&geo) +{ + int ret = OB_SUCCESS; + ObString wkb = gis_datum->get_string(); + ObGeoType type = ObGeoType::GEOTYPEMAX; + uint32_t srid = -1; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator, + *gis_datum, + gis_arg->datum_meta_, + gis_arg->obj_meta_.has_lob_header(), + wkb))) { + LOG_WARN("fail to get real string data", K(ret), K(wkb)); + } else if (OB_FAIL(ObGeoTypeUtil::get_type_srid_from_wkb(wkb, type, srid))) { + if (ret == OB_ERR_GIS_INVALID_DATA) { + LOG_USER_ERROR(OB_ERR_GIS_INVALID_DATA, func_name); + } + LOG_WARN("get type and srid from wkb failed", K(wkb), K(ret)); + } else if (OB_FAIL(ObGeoExprUtils::get_srs_item( + ctx, srs_guard, wkb, srs, true, func_name))) { + LOG_WARN("fail to get srs item", K(ret), K(wkb)); + } else if (OB_FAIL(ObGeoExprUtils::build_geometry(allocator, + wkb, + geo, + srs, + func_name, + ObGeoBuildFlag::GEO_ALLOW_3D_DEFAULT))) { + LOG_WARN("get first geo by wkb failed", K(ret)); + } + return ret; +} + +int ObGeoExprUtils::union_polygons( + ObIAllocator &allocator, const ObGeometry &poly, ObGeometry *&polygons_union) +{ + int ret = OB_SUCCESS; + ObGeometry *union_res = nullptr; + ObGeoEvalCtx union_ctx(&allocator); + if (OB_FAIL(union_ctx.append_geo_arg(&poly))) { + LOG_WARN("failed to append geo arg to gis context", K(ret), K(union_ctx.get_geo_count())); + } else if (OB_FAIL(union_ctx.append_geo_arg(polygons_union))) { + LOG_WARN("failed to append geo arg to gis context", K(ret), K(union_ctx.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(union_ctx, union_res))) { + LOG_WARN("eval boost union failed", K(ret)); + } else { + allocator.free(polygons_union); + polygons_union = union_res; + } + return ret; +} + +int ObGeoExprUtils::make_valid_polygon(ObGeometry *poly, ObIAllocator &allocator, ObGeometry *&valid_poly) +{ + int ret = OB_SUCCESS; + ObGeoEvalCtx gis_context(&allocator); + int res_unused = 0; + if (OB_ISNULL(poly) + || (poly->type() != ObGeoType::POLYGON && poly->type() != ObGeoType::MULTIPOLYGON)) { + ret = OB_ERR_GIS_INVALID_DATA; + LOG_WARN("invalid geometry input", K(ret), K(poly)); + } else if (OB_FAIL(gis_context.append_geo_arg(poly))) { + LOG_WARN("failed to append geo arg to gis context", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval( + gis_context, res_unused))) { + LOG_WARN("eval boost dissolve polygon failed", K(ret)); + } else if (poly->type() == ObGeoType::POLYGON) { + if (OB_FAIL(make_valid_polygon_inner(static_cast(*poly), + allocator, valid_poly))) { + LOG_WARN("make polygon valid failed", K(ret)); + } + } else { + ObCartesianMultipolygon &mpy = *reinterpret_cast(poly); + for (uint32_t i = 0; OB_SUCC(ret) && i < mpy.size(); ++i) { + ObGeometry *valid_inner_poly = nullptr; + if (OB_FAIL(make_valid_polygon_inner(mpy[i], allocator, valid_inner_poly))) { + LOG_WARN("fail to make polygon valid", K(ret)); + } else if (OB_NOT_NULL(valid_inner_poly)) { + if (OB_ISNULL(valid_poly)) { + valid_poly = valid_inner_poly; + } else if (!valid_inner_poly->is_empty() + && OB_FAIL(union_polygons(allocator, *valid_inner_poly, valid_poly))) { + LOG_WARN("fail to union holes", K(ret)); + } else { + allocator.free(valid_inner_poly); + } + } + } + } + return ret; +} + +int ObGeoExprUtils::make_valid_polygon_inner( + ObCartesianPolygon &poly, ObIAllocator &allocator, ObGeometry *&valid_poly) +{ + int ret = OB_SUCCESS; + if (!poly.empty() && poly.inner_ring_size() != 0) { + ObCartesianPolygon tmp_ext_poly; + tmp_ext_poly.exterior_ring() = poly.exterior_ring(); + ObGeometry *holes_union = nullptr; + ObGeometry *shells_union = nullptr; + for (uint32_t i = 0; OB_SUCC(ret) && i < poly.inner_ring_size(); ++i) { + ObCartesianPolygon tmp_poly; + tmp_poly.exterior_ring() = poly.inner_ring(i); + bool is_intersects = false; + ObGeoEvalCtx correct_context(&allocator); + ObGeoEvalCtx intersects_ctx(&allocator); + int res_unused; + if (OB_FAIL(correct_context.append_geo_arg(&tmp_poly))) { + LOG_WARN("build geo gis context failed", K(ret)); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(correct_context, res_unused))) { + LOG_WARN("eval geo correct failed", K(ret)); + } else if (OB_FAIL(intersects_ctx.append_geo_arg(&tmp_ext_poly))) { + LOG_WARN("failed to append geo arg to gis context", + K(ret), + K(intersects_ctx.get_geo_count())); + } else if (OB_FAIL(intersects_ctx.append_geo_arg(&tmp_poly))) { + LOG_WARN("failed to append geo arg to gis context", + K(ret), + K(intersects_ctx.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval( + intersects_ctx, is_intersects))) { + LOG_WARN("eval boost intersects failed", K(ret)); + } else if (is_intersects) { + // holes + if (OB_ISNULL(holes_union)) { + ObCartesianPolygon *holes = OB_NEWx(ObCartesianPolygon, &allocator, tmp_poly); + if (OB_ISNULL(holes)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } else { + holes_union = holes; + } + } else if (OB_FAIL(union_polygons(allocator, *&tmp_poly, holes_union))) { + LOG_WARN("fail to union holes", K(ret)); + } + } else { + // shells + if (OB_ISNULL(shells_union)) { + ObCartesianPolygon *shells = OB_NEWx(ObCartesianPolygon, &allocator, tmp_poly); + if (OB_ISNULL(shells)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } else { + shells_union = shells; + } + } else if (OB_FAIL(union_polygons(allocator, *&tmp_poly, shells_union))) { + LOG_WARN("fail to union shells", K(ret)); + } + } + } + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(holes_union)) { + holes_union = &tmp_ext_poly; + } else { + ObGeoEvalCtx diff_ctx(&allocator); + ObGeometry *diff_holes = nullptr; + if (OB_FAIL(diff_ctx.append_geo_arg(&tmp_ext_poly))) { + LOG_WARN("failed to append geo arg to gis context", K(ret), K(diff_ctx.get_geo_count())); + } else if (OB_FAIL(diff_ctx.append_geo_arg(holes_union))) { + LOG_WARN("failed to append geo arg to gis context", K(ret), K(diff_ctx.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(diff_ctx, diff_holes))) { + LOG_WARN("eval boost intersects failed", K(ret)); + } else { + holes_union = diff_holes; + } + } + if (OB_FAIL(ret)) { + } else if (OB_NOT_NULL(shells_union) + && OB_FAIL(union_polygons(allocator, *shells_union, holes_union))) { + LOG_WARN("fail to union shells", K(ret)); + } else { + if (holes_union->type() == ObGeoType::MULTIPOLYGON + && static_cast(holes_union)->size() == 1) { + valid_poly = &static_cast(holes_union)->front(); + } else { + valid_poly = holes_union; + } + } + } else if (!poly.empty() && poly.inner_ring_size() == 0) { + ObGeoEvalCtx dissol_ctx(&allocator); + ObGeometry *diff_holes; + if (OB_FAIL(dissol_ctx.append_geo_arg(&poly))) { + LOG_WARN("failed to append geo arg to gis context", K(ret), K(dissol_ctx.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(dissol_ctx, diff_holes))) { + LOG_WARN("eval boost dissolve polygon failed", K(ret)); + } else { + ObGeoEvalCtx gis_context(&allocator); + int res_unused; + if (OB_FAIL(gis_context.append_geo_arg(diff_holes))) { + LOG_WARN("failed to append geo arg to gis context", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL(ObGeoFunc::geo_func::eval(gis_context, res_unused))) { + LOG_WARN("eval boost correct polygon failed", K(ret)); + } else { + valid_poly = diff_holes; + } + } + } else if (poly.empty()) { + valid_poly = &poly; + } else { + int unused = 0; + ObGeoEvalCtx gis_context(&allocator); + if (OB_FAIL(gis_context.append_geo_arg(&poly))) { + LOG_WARN("failed to append geo arg to gis context", K(ret), K(gis_context.get_geo_count())); + } else if (OB_FAIL( + ObGeoFunc::geo_func::eval(gis_context, unused))) { + LOG_WARN("eval boost correct failed", K(ret)); + } else { + valid_poly = &poly; + } + } + return ret; +} + +int ObGeoExprUtils::create_3D_empty_collection(ObIAllocator &allocator, uint32_t srid, bool is_3d, bool is_geog, ObGeometry *&geo) +{ + int ret = OB_SUCCESS; + ObString empty_wkt = is_3d ? "GEOMETRYCOLLECTION Z EMPTY" : "GEOMETRYCOLLECTION EMPTY"; + if (OB_FAIL(ObWktParser::parse_wkt(allocator, empty_wkt, geo, true, is_geog))) { + LOG_WARN("failed to parse wkt", K(ret)); + } else { + geo->set_srid(srid); + } + return ret; +} + + } // sql } // oceanbase diff --git a/src/sql/engine/expr/ob_geo_expr_utils.h b/src/sql/engine/expr/ob_geo_expr_utils.h index d460014bbc..a025c25060 100644 --- a/src/sql/engine/expr/ob_geo_expr_utils.h +++ b/src/sql/engine/expr/ob_geo_expr_utils.h @@ -30,6 +30,62 @@ namespace oceanbase { namespace sql { +struct ObGeoUnit +{ + const char *name; + double factor; +}; + +const ObGeoUnit OB_GEO_UNITS[] = { + // order by unit s, asc + { "British chain (Benoit 1895 A)", 20.1167824 }, + { "British chain (Benoit 1895 B)", 20.116782494375872 }, + { "British chain (Sears 1922 truncated)", 20.116756 }, + { "British chain (Sears 1922)", 20.116765121552632 }, + { "British foot (1865)", 0.30480083333333335 }, + { "British foot (1936)", 0.3048007491 }, + { "British foot (Benoit 1895 A)", 0.3047997333333333 }, + { "British foot (Benoit 1895 B)", 0.30479973476327077 }, + { "British foot (Sears 1922 truncated)", 0.30479933333333337 }, + { "British foot (Sears 1922)", 0.3047994715386762 }, + { "British link (Benoit 1895 A)", 0.201167824 }, + { "British link (Benoit 1895 B)", 0.2011678249437587 }, + { "British link (Sears 1922 truncated)", 0.20116756 }, + { "British link (Sears 1922)", 0.2011676512155263 }, + { "British yard (Benoit 1895 A)", 0.9143992 }, + { "British yard (Benoit 1895 B)", 0.9143992042898124 }, + { "British yard (Sears 1922 truncated)", 0.914398 }, + { "British yard (Sears 1922)", 0.9143984146160288 }, + { "centimetre", 0.01 }, + { "chain", 20.1168 }, + { "Clarke's chain", 20.1166195164 }, + { "Clarke's foot", 0.3047972654 }, + { "Clarke's link", 0.201166195164 }, + { "Clarke's yard", 0.9143917962 }, + { "fathom", 1.8288 }, + { "foot", 0.3048 }, + { "German legal metre", 1.0000135965 }, + { "Gold Coast foot", 0.3047997101815088 }, + { "Indian foot", 0.30479951024814694 }, + { "Indian foot (1937)", 0.30479841 }, + { "Indian foot (1962)", 0.3047996 }, + { "Indian foot (1975)", 0.3047995 }, + { "Indian yard", 0.9143985307444408 }, + { "Indian yard (1937)", 0.91439523 }, + { "Indian yard (1962)", 0.9143988 }, + { "Indian yard (1975)", 0.9143985 }, + { "kilometre", 1000 }, + { "link", 0.201168 }, + { "metre", 1 }, + { "millimetre", 0.001 }, + { "nautical mile", 1852 }, + { "Statute mile", 1609.344 }, + { "US survey chain", 20.11684023368047 }, + { "US survey foot", 0.30480060960121924 }, + { "US survey link", 0.2011684023368047 }, + { "US survey mile", 1609.3472186944375 }, + { "yard", 0.9144 } +}; enum class ObGeoAxisOrder { @@ -59,9 +115,7 @@ public: common::ObGeometry *&geo, const common::ObSrsItem *srs, const char *func_name, - const bool need_normlize = true, - const bool need_check_ring = false, - const bool need_correct = true); + uint8_t build_flag = ObGeoBuildFlag::GEO_DEFAULT); static int construct_geometry(common::ObIAllocator &allocator, const common::ObString &wkb, omt::ObSrsCacheGuard &srs_guard, @@ -108,11 +162,35 @@ public: const common::ObSrsItem *srs_item, common::ObString &res_wkb, uint32_t srs_id = 0); + static int geo_to_2d_wkb(common::ObGeometry &geo, + const ObExpr &expr, + ObEvalCtx &ctx, + const common::ObSrsItem *srs_item, + common::ObString &res_wkb, + uint32_t srs_id = 0); + static int geo_to_3d_wkb(common::ObGeometry &geo, + const ObExpr &expr, + ObEvalCtx &ctx, + const common::ObSrsItem *srs_item, + common::ObString &res_wkb, + uint32_t srs_id = 0); static void geo_func_error_handle(int ret, const char* func_name); static int zoom_in_geos_for_relation(common::ObGeometry &geo1, common::ObGeometry &geo2); static int pack_geo_res(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res, const ObString &str); - + static int reverse_coordinate(ObGeometry *geo, const char *func_name); + static int length_unit_conversion(const ObString &unit_str, const ObSrsItem *srs, double in_num, double &out_num); + static int get_input_geometry(ObIAllocator &allocator, ObDatum *gis_datum, ObEvalCtx &ctx, ObExpr *gis_arg, + omt::ObSrsCacheGuard &srs_guard, const char *func_name, + const ObSrsItem *&srs, ObGeometry *&geo); + static int make_valid_polygon_inner( + ObCartesianPolygon &poly, ObIAllocator &allocator, ObGeometry *&valid_poly); + static int union_polygons( + ObIAllocator &allocator, const ObGeometry &poly, ObGeometry *&polygons_union); + static int make_valid_polygon(ObGeometry *poly, ObIAllocator &allocator, ObGeometry *&valid_poly); + static int create_3D_empty_collection(ObIAllocator &allocator, uint32_t srid, bool is_3d, bool is_geog, ObGeometry *&geo); +private: + static int ob_geo_find_unit(const ObGeoUnit *units, const ObString &name, double &factor); }; } // sql diff --git a/src/sql/engine/ob_exec_context.cpp b/src/sql/engine/ob_exec_context.cpp index 5100763439..6c4356c5d5 100644 --- a/src/sql/engine/ob_exec_context.cpp +++ b/src/sql/engine/ob_exec_context.cpp @@ -140,9 +140,15 @@ ObExecContext::~ObExecContext() row_id_list_array_.reset(); destroy_eval_allocator(); reset_op_ctx(); - //对于后台线程, 需要调用析构 - if (NULL != phy_plan_ctx_ && !THIS_WORKER.has_req_flag()) { - phy_plan_ctx_->~ObPhysicalPlanCtx(); + + if (NULL != phy_plan_ctx_) { + if (!THIS_WORKER.has_req_flag()) { + //对于后台线程, 需要调用析构 + phy_plan_ctx_->~ObPhysicalPlanCtx(); + } else { + // free subschema map memory + phy_plan_ctx_->get_subschema_ctx().destroy(); + } } phy_plan_ctx_ = NULL; // destory gi task info map @@ -1034,5 +1040,37 @@ DEFINE_GET_SERIALIZE_SIZE(ObExecContext) } return len; } + +int ObExecContext::get_sqludt_meta_by_subschema_id(uint16_t subschema_id, ObSqlUDTMeta &udt_meta) +{ + int ret = OB_SUCCESS; + if (ob_is_reserved_subschema_id(subschema_id)) { + ret = ob_get_reserved_udt_meta(subschema_id, udt_meta); + } else if (OB_ISNULL(phy_plan_ctx_)) { + ret = OB_NOT_INIT; + SQL_ENG_LOG(WARN, "not phyical plan ctx for subschema mapping", K(ret), K(lbt())); + } else { + ret = phy_plan_ctx_->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta); + } + return ret; +} + +int ObExecContext::get_subschema_id_by_udt_id(uint64_t udt_type_id, + uint16_t &subschema_id, + share::schema::ObSchemaGetterGuard *schema_guard) +{ + int ret = OB_SUCCESS; + if (ob_is_reserved_udt_id(udt_type_id)) { + ret = ob_get_reserved_subschema(udt_type_id, subschema_id); + } else if (OB_ISNULL(phy_plan_ctx_)) { + ret = OB_NOT_INIT; + SQL_ENG_LOG(WARN, "not phyical plan ctx for reverse mapping", K(ret), K(lbt())); + } else { + schema_guard = OB_ISNULL(schema_guard) ? get_sql_ctx()->schema_guard_ : schema_guard; + ret = phy_plan_ctx_->get_subschema_id_by_udt_id(udt_type_id, subschema_id, schema_guard); + } + return ret; +} + } // namespace sql } // namespace oceanbase diff --git a/src/sql/engine/ob_exec_context.h b/src/sql/engine/ob_exec_context.h index fcfe8c67ee..60a6778ec5 100644 --- a/src/sql/engine/ob_exec_context.h +++ b/src/sql/engine/ob_exec_context.h @@ -28,6 +28,7 @@ #include "sql/das/ob_das_context.h" #include "sql/engine/cmd/ob_table_direct_insert_ctx.h" #include "pl/ob_pl_package_guard.h" +#include "lib/udt/ob_udt_type.h" #define GET_PHY_PLAN_CTX(ctx) ((ctx).get_physical_plan_ctx()) #define GET_MY_SESSION(ctx) ((ctx).get_my_session()) @@ -466,6 +467,11 @@ public: void set_errcode(const int errcode) { ATOMIC_STORE(&errcode_, errcode); } int get_errcode() const { return ATOMIC_LOAD(&errcode_); } hash::ObHashMap &get_dblink_snapshot_map() { return dblink_snapshot_map_; } + int get_sqludt_meta_by_subschema_id(uint16_t subschema_id, ObSqlUDTMeta &udt_meta); + int get_subschema_id_by_udt_id(uint64_t udt_type_id, + uint16_t &subschema_id, + share::schema::ObSchemaGetterGuard *schema_guard = NULL); + ObExecFeedbackInfo &get_feedback_info() { return fb_info_; }; void set_cur_rownum(int64_t cur_rownum) { cur_row_num_ = cur_rownum; } int64_t get_cur_rownum() { return cur_row_num_; } diff --git a/src/sql/engine/ob_physical_plan.cpp b/src/sql/engine/ob_physical_plan.cpp index 866c549297..6e6d8b0123 100644 --- a/src/sql/engine/ob_physical_plan.cpp +++ b/src/sql/engine/ob_physical_plan.cpp @@ -33,6 +33,7 @@ #include "share/ob_truncated_string.h" #include "sql/spm/ob_spm_evolution_plan.h" #include "sql/engine/ob_exec_feedback_info.h" +#include "sql/engine/expr/ob_expr_sql_udt_utils.h" namespace oceanbase { diff --git a/src/sql/engine/ob_physical_plan.h b/src/sql/engine/ob_physical_plan.h index fbab0c9809..fb591a14df 100644 --- a/src/sql/engine/ob_physical_plan.h +++ b/src/sql/engine/ob_physical_plan.h @@ -508,6 +508,8 @@ public: void set_enable_px_fast_reclaim(bool value) { is_enable_px_fast_reclaim_ = value; } bool is_enable_px_fast_reclaim() const { return is_enable_px_fast_reclaim_; } + ObSubSchemaCtx &get_subschema_ctx_for_update() { return subschema_ctx_; } + const ObSubSchemaCtx &get_subschema_ctx() const { return subschema_ctx_; } int set_all_local_session_vars(ObIArray *all_local_session_vars); ObIArray & get_all_local_session_vars() { return all_local_session_vars_; } public: diff --git a/src/sql/engine/ob_physical_plan_ctx.cpp b/src/sql/engine/ob_physical_plan_ctx.cpp index e3a6d8f779..97fbde0b98 100644 --- a/src/sql/engine/ob_physical_plan_ctx.cpp +++ b/src/sql/engine/ob_physical_plan_ctx.cpp @@ -22,6 +22,9 @@ #include "sql/engine/ob_physical_plan.h" #include "sql/engine/px/ob_dfo.h" #include "lib/utility/ob_print_utils.h" +#include "deps/oblib/src/lib/udt/ob_udt_type.h" +#include "sql/engine/expr/ob_expr_sql_udt_utils.h" + namespace oceanbase { using namespace common; @@ -1011,6 +1014,117 @@ int ObPhysicalPlanCtx::get_field(const int64_t idx, ObField &field) return ret; } +int ObPhysicalPlanCtx::get_sqludt_meta_by_subschema_id(uint16_t subschema_id, ObSqlUDTMeta &udt_meta) +{ + int ret = OB_SUCCESS; + ObSubSchemaValue value; + if (subschema_id == ObMaxSystemUDTSqlType || subschema_id >= UINT_MAX16) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema id", K(ret), K(subschema_id)); + } else if (OB_NOT_NULL(phy_plan_)) { // physical plan exist, use subschema ctx on phy plan + if (!phy_plan_->get_subschema_ctx().is_inited()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("plan with empty subschema mapping", K(ret), K(phy_plan_->get_subschema_ctx())); + } else if (OB_FAIL(phy_plan_->get_subschema_ctx().get_subschema(subschema_id, value))) { + if (OB_HASH_NOT_EXIST != ret) { + LOG_WARN("failed to get subschema by subschema id", K(ret), K(subschema_id)); + } else { + LOG_WARN("subschema not exist in subschema mapping", K(ret), K(subschema_id)); + } + } else { + udt_meta = *(reinterpret_cast(value.value_)); + } + } else if (!subschema_ctx_.is_inited()) { // no phy plan + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema id", K(ret), K(subschema_id), K(lbt())); + } else { + if (OB_FAIL(subschema_ctx_.get_subschema(subschema_id, value))) { + LOG_WARN("failed to get subschema", K(ret), K(subschema_id)); + } else if (value.type_ >= OB_SUBSCHEMA_MAX_TYPE) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid subschema type", K(ret), K(value)); + } else { // Notice: shallow copy + udt_meta = *(reinterpret_cast(value.value_)); + } + } + return ret; +} + +int ObPhysicalPlanCtx::get_subschema_id_by_udt_id(uint64_t udt_type_id, + uint16_t &subschema_id, + share::schema::ObSchemaGetterGuard *schema_guard) +{ + int ret = OB_SUCCESS; + uint16_t temp_subschema_id = ObMaxSystemUDTSqlType; + bool found = false; + if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_type_id)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("find udt id in query ctx failed", K(ret), K(udt_type_id)); + } else if (OB_NOT_NULL(phy_plan_)) { // physical plan exist, use subschema ctx on phy plan + if (!phy_plan_->get_subschema_ctx().is_inited()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("plan with empty subschema mapping", K(ret), K(phy_plan_->get_subschema_ctx())); + } else if (OB_FAIL(phy_plan_->get_subschema_ctx().get_subschema_id(udt_type_id, + OB_SUBSCHEMA_UDT_TYPE, + temp_subschema_id))) { + if (OB_HASH_NOT_EXIST != ret) { + LOG_WARN("failed to get subschema id by udt_id", K(ret), K(udt_type_id)); + } else { + LOG_WARN("udt_id not exist in subschema mapping", K(ret), K(udt_type_id)); + } + } else { + subschema_id = temp_subschema_id; + } + // no phy plan + } else if (!subschema_ctx_.is_inited() && OB_FAIL(subschema_ctx_.init())) { + LOG_WARN("subschema ctx init failed", K(ret), K(udt_type_id)); + } else if (OB_FAIL(subschema_ctx_.get_subschema_id(udt_type_id, + OB_SUBSCHEMA_UDT_TYPE, + temp_subschema_id))) { + if (OB_HASH_NOT_EXIST != ret) { + LOG_WARN("failed to get subschema id by udt_id", K(ret), K(udt_type_id)); + } else { // build new meta + ret = OB_SUCCESS; + uint16 new_subschema_id = ObMaxSystemUDTSqlType; + ObSqlUDTMeta *udt_meta = NULL; + ObSubSchemaValue value; + if (OB_ISNULL(schema_guard)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("No schema gurad to generate udt_meta", K(ret), K(udt_type_id)); + } else if (FALSE_IT(udt_meta = reinterpret_cast(allocator_.alloc(sizeof(ObSqlUDTMeta))))) { + } else if (OB_ISNULL(udt_meta)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("failed to alloc udt meta", K(ret), K(udt_type_id), K(sizeof(ObSqlUDTMeta))); + } else if (FALSE_IT(MEMSET(udt_meta, 0, sizeof(ObSqlUDTMeta)))) { + } else if (OB_FAIL(ObSqlUdtMetaUtils::generate_udt_meta_from_schema(schema_guard, + &subschema_ctx_, + allocator_, + get_tenant_id(), + udt_type_id, + *udt_meta))) { + LOG_WARN("generate udt_meta failed", K(ret), K(get_tenant_id()), K(udt_type_id)); + } else if (OB_FAIL(subschema_ctx_.get_subschema_id_from_fields(udt_type_id, new_subschema_id))) { + LOG_WARN("failed to get subschema id from result fields", K(ret), K(get_tenant_id()), K(udt_type_id)); + } else if (new_subschema_id == ObInvalidSqlType // not get from fields, generate new + && OB_FAIL(subschema_ctx_.get_new_subschema_id(new_subschema_id))) { + LOG_WARN("failed to get new subschema id", K(ret), K(get_tenant_id()), K(udt_type_id)); + } else { + value.type_ = OB_SUBSCHEMA_UDT_TYPE; + value.signature_ = udt_type_id; + value.value_ = static_cast(udt_meta); + if (OB_FAIL(subschema_ctx_.set_subschema(new_subschema_id, value))) { + LOG_WARN("failed to set new subschema", K(ret), K(new_subschema_id), K(udt_type_id), K(value)); + } else { + subschema_id = new_subschema_id; + } + } + } + } else { // success + subschema_id = temp_subschema_id; + } + return ret; +} + int ObPhysicalPlanCtx::set_all_local_session_vars(ObIArray &all_local_session_vars) { int ret = OB_SUCCESS; @@ -1031,6 +1145,68 @@ int ObPhysicalPlanCtx::set_all_local_session_vars(ObIArray &a return ret; } +// for ps protocal in jdbc, phy plan only exist in ObMPStmtExecute +// but udt meta needs to be used in ObMPStmtFetch, here rebuild subschema ctx by fields +// for sql udts, fields recorded both subschema id and udt id +int ObPhysicalPlanCtx::build_subschema_by_fields(const ColumnsFieldIArray *fields, + share::schema::ObSchemaGetterGuard *schema_guard) +{ + int ret = OB_SUCCESS; + if (OB_NOT_NULL(phy_plan_) || subschema_ctx_.get_subschema_count() > 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("physical plan exists, should not rebuild subschema", K(ret), K(*fields), K(subschema_ctx_)); + } else if (!subschema_ctx_.is_inited() && OB_FAIL(subschema_ctx_.init())) { + LOG_WARN("subschema ctx init failed", K(ret)); + } else { + subschema_ctx_.set_fields(fields); + + for (uint32_t i = 0; OB_SUCC(ret) && i < fields->count(); i++) { + if (fields->at(i).type_.is_user_defined_sql_type() + || fields->at(i).type_.is_collection_sql_type()) { + uint64_t udt_id = fields->at(i).accuracy_.get_accuracy(); + uint16_t subschema_id = 0; + if (udt_id != T_OBJ_XML + && OB_FAIL(get_subschema_id_by_udt_id(udt_id, subschema_id, schema_guard))) { + LOG_WARN("failed to get subschema id", K(ret), K(fields->at(i)), K(udt_id)); + } + } + } + } + return ret; +} + +// for ps with sql udt param without plan +int ObPhysicalPlanCtx::build_subschema_ctx_by_param_store(share::schema::ObSchemaGetterGuard *schema_guard) +{ + int ret = OB_SUCCESS; + ParamStore *param_store = &get_param_store_for_update(); + if (OB_NOT_NULL(phy_plan_) || subschema_ctx_.get_subschema_count() > 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("physical plan exists, should not build subschema ctx in plan ctx", + K(ret), K(subschema_ctx_)); + } + + for (uint32_t i = 0; OB_SUCC(ret) && i < param_store->count(); i++) { + ObObjParam ¶m = param_store->at(i); + if (param.is_user_defined_sql_type() || param.is_collection_sql_type()) { + uint64_t udt_id = param.get_accuracy().get_accuracy(); + uint16_t subschema_id = 0; + if (!ob_is_reserved_udt_id(udt_id)) { // is not reserved subschema id + if (!subschema_ctx_.is_inited() && OB_FAIL(subschema_ctx_.init())) { + LOG_WARN("subschema ctx init failed", K(ret)); + } else if(OB_FAIL(get_subschema_id_by_udt_id(udt_id, subschema_id, schema_guard))) { + LOG_WARN("failed to get subschema id", K(ret), K(param), K(udt_id)); + } else if (subschema_id == ObMaxSystemUDTSqlType) { + LOG_WARN("failed to get subschema id", K(ret), K(param), K(udt_id)); + } else { + param.set_subschema_id(subschema_id); + } + } + } + } + return ret; +} + int ObPhysicalPlanCtx::get_local_session_vars(int64_t local_var_array_id, const ObLocalSessionVar *&local_vars) { int ret = OB_SUCCESS; diff --git a/src/sql/engine/ob_physical_plan_ctx.h b/src/sql/engine/ob_physical_plan_ctx.h index eeda4dd287..f1c2bd0619 100644 --- a/src/sql/engine/ob_physical_plan_ctx.h +++ b/src/sql/engine/ob_physical_plan_ctx.h @@ -23,7 +23,9 @@ #include "sql/plan_cache/ob_plan_cache_util.h" #include "sql/engine/user_defined_function/ob_udf_ctx_mgr.h" #include "sql/engine/expr/ob_expr.h" +#include "lib/udt/ob_udt_type.h" #include "sql/engine/ob_subschema_ctx.h" + namespace oceanbase { namespace sql @@ -461,6 +463,15 @@ public: void set_spm_timeout_timestamp(const int64_t timeout) { spm_ts_timeout_us_ = timeout; } void set_rich_format(bool v) { enable_rich_format_ = v; } bool is_rich_format() const { return enable_rich_format_; } + + int get_sqludt_meta_by_subschema_id(uint16_t subschema_id, ObSqlUDTMeta &udt_meta); + int get_subschema_id_by_udt_id(uint64_t udt_type_id, + uint16_t &subschema_id, + share::schema::ObSchemaGetterGuard *schema_guard = NULL); + int build_subschema_by_fields(const ColumnsFieldIArray *fields, + share::schema::ObSchemaGetterGuard *schema_guard); + int build_subschema_ctx_by_param_store(share::schema::ObSchemaGetterGuard *schema_guard); + ObSubSchemaCtx &get_subschema_ctx() { return subschema_ctx_; } const ObIArray &get_array_param_groups() const { return array_param_groups_; } ObIArray &get_array_param_groups() { return array_param_groups_; } int set_all_local_session_vars(ObIArray &all_local_session_vars); diff --git a/src/sql/engine/ob_subschema_ctx.cpp b/src/sql/engine/ob_subschema_ctx.cpp index 339012602d..303a258152 100644 --- a/src/sql/engine/ob_subschema_ctx.cpp +++ b/src/sql/engine/ob_subschema_ctx.cpp @@ -346,8 +346,7 @@ int ObSubSchemaCtx::get_subschema_id_from_fields(uint64_t udt_id, uint16_t &subs if (OB_NOT_NULL(fields_)) { for (uint32_t i = 0; is_found == false && OB_SUCC(ret) && i < fields_->count(); i++) { if ((fields_->at(i).type_.is_user_defined_sql_type() - // || fields_->at(i).type_.is_collection_sql_type() - ) + || fields_->at(i).type_.is_collection_sql_type()) && fields_->at(i).accuracy_.get_accuracy() == udt_id) { subschema_id = fields_->at(i).type_.get_udt_subschema_id(); is_found = true; diff --git a/src/sql/engine/window_function/ob_window_function_op.cpp b/src/sql/engine/window_function/ob_window_function_op.cpp index 35c4bd5786..d864590c3a 100644 --- a/src/sql/engine/window_function/ob_window_function_op.cpp +++ b/src/sql/engine/window_function/ob_window_function_op.cpp @@ -1287,7 +1287,8 @@ int ObWindowFunctionOp::init() case T_FUN_JSON_OBJECTAGG: case T_FUN_ORA_JSON_ARRAYAGG: case T_FUN_ORA_JSON_OBJECTAGG: - case T_FUN_ORA_XMLAGG: { + case T_FUN_ORA_XMLAGG: + case T_FUN_SYS_ST_ASMVT: { void *tmp_ptr = local_allocator_.alloc(sizeof(AggrCell)); void *tmp_array = local_allocator_.alloc(sizeof(AggrInfoFixedArray)); ObIArray *aggr_infos = NULL; diff --git a/src/sql/ob_spi.cpp b/src/sql/ob_spi.cpp index 9136829ed1..b0090639e2 100644 --- a/src/sql/ob_spi.cpp +++ b/src/sql/ob_spi.cpp @@ -2282,9 +2282,33 @@ int ObSPIService::spi_build_record_type(common::ObIAllocator &allocator, OX (pl_type.set_user_type_id(user_type->get_type(), udt_id)); OX (pl_type.set_type_from(user_type->get_type_from())); } else { - ret = OB_NOT_SUPPORTED; - LOG_WARN("unsupported sql udt type", K(ret), K(columns->at(i).cname_), K(columns->at(i).type_)); + uint16_t subschema_id; + uint64_t udt_id = columns->at(i).accuracy_.accuracy_; + const ObUserDefinedType *user_type = NULL; + OZ (secondary_namespace->get_pl_data_type_by_id(udt_id, user_type)); + CK (OB_NOT_NULL(user_type)); + if (OB_FAIL(ret)) { + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_id)) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("inconsistent datatypes", K(ret), K(udt_id)); + } else if (OB_FAIL((const_cast(result_set.get_exec_context()).get_subschema_id_by_udt_id(udt_id, subschema_id)))) { + LOG_WARN("Failed to get subshcema_meta_info", K(ret), K(udt_id)); + } else if (subschema_id != columns->at(i).type_.get_udt_subschema_id()) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("inconsistent datatypes", K(ret), K(subschema_id), K(udt_id), K(columns->at(i).type_.get_udt_subschema_id())); + } else { + OX (pl_type.set_user_type_id(user_type->get_type(), udt_id)); + OX (pl_type.set_type_from(user_type->get_type_from())); + } } + } else if (columns->at(i).type_.is_geometry()) { + // cast geometry type to pl extend + uint64_t udt_id = T_OBJ_SDO_GEOMETRY; + const ObUserDefinedType *user_type = NULL; + OZ (secondary_namespace->get_pl_data_type_by_id(udt_id, user_type)); + CK (OB_NOT_NULL(user_type)); + OX (pl_type.set_user_type_id(user_type->get_type(), udt_id)); + OX (pl_type.set_type_from(user_type->get_type_from())); } else { ObDataType data_type; data_type.set_meta_type(columns->at(i).type_.get_meta()); @@ -2907,10 +2931,21 @@ int ObSPIService::spi_execute_immediate(ObPLExecCtx *ctx, if (!ob_is_xml_pl_type(params[i]->get_type(), params[i]->get_udt_id())) { OZ (pl::ObUserDefinedType::deep_copy_obj(allocator, *params[i], new_param, true)); } else { + uint64_t udt_id = params[i]->get_udt_id(); const ObDataTypeCastParams dtc_params = sql::ObBasicSessionInfo::create_dtc_params(ctx->exec_ctx_->get_my_session()); ObCastCtx cast_ctx(ctx->allocator_, &dtc_params, CM_NONE, ObCharset::get_system_collation()); - if (OB_FAIL(ObObjCaster::to_type(ObUserDefinedSQLType, cast_ctx, *params[i], new_param))) { + cast_ctx.exec_ctx_ = ctx->exec_ctx_; + uint16_t subschema_id = ObInvalidSqlType; + if (OB_FAIL(cast_ctx.exec_ctx_->get_subschema_id_by_udt_id(udt_id, + subschema_id, + &spi_result.get_scheme_guard()))) { + LOG_WARN("failed to get subschema id by udt_id", K(ret), K(params[i])); + } else if (FALSE_IT(new_param.set_subschema_id(subschema_id))) { + } else if (OB_FAIL(ObObjCaster::to_type(ObUserDefinedSQLType, cast_ctx, *params[i], new_param))) { LOG_WARN("failed to_type", K(ret), K(new_param)); + } else { // sql udt params need original udt id for plan choose + new_param.set_udt_id(udt_id); + new_param.set_param_meta(); // param meta also changed } } } @@ -7114,15 +7149,31 @@ int ObSPIService::get_result(ObPLExecCtx *ctx, column_count = fields->count(); actual_column_count = column_count - hidden_column_count; } + bool need_subschema_ctx = false; for (int64_t i = 0; OB_SUCC(ret) && i < actual_column_count; ++i) { ObDataType type; type.set_meta_type(fields->at(i).type_.get_meta()); type.set_accuracy(fields->at(i).accuracy_); + if (type.get_meta_type().is_user_defined_sql_type() + || type.get_meta_type().is_collection_sql_type()) { + // need subschema ctx to convert sql udt to pl types in convert obj + need_subschema_ctx = true; + } if (OB_FAIL(row_desc.push_back(type))) { LOG_WARN("push back error", K(i), K(fields->at(i).type_), K(fields->at(i).accuracy_), K(ret)); } } + if (OB_SUCC(ret) && need_subschema_ctx) { + CK (OB_NOT_NULL(exec_ctx->get_physical_plan_ctx())); + if (OB_SUCC(ret)) { + ObSubSchemaCtx & subschema_ctx = exec_ctx->get_physical_plan_ctx()->get_subschema_ctx(); + if (OB_FAIL(subschema_ctx.assgin( + static_cast(result_set)->get_physical_plan()->get_subschema_ctx()))) { + LOG_WARN("fail to assign subschema ctx", K(ret)); + } + } + } } // Step2: 检查类型匹配 if (OB_SUCC(ret)) { @@ -7537,7 +7588,12 @@ int ObSPIService::collect_cells(pl::ObPLExecCtx &ctx, for (int64_t i = 0; OB_SUCC(ret) && i < row.get_count() - hidden_column_count; ++i) { tmp_obj.reset(); ObObj &obj = row.get_cell(i); - obj.set_collation_level(result_types[i].get_collation_level()); + if (!obj.is_user_defined_sql_type()) { + obj.set_collation_level(result_types[i].get_collation_level()); + } + if (row_desc.at(i).get_udt_id() == T_OBJ_XML) { + obj.set_subschema_id(ObXMLSqlType); + } if (obj.is_pl_extend()) { // need deep copy immediately at bulk into scenes, because when fetch next row, current row will be free OZ (ObUserDefinedType::deep_copy_obj(*cast_ctxs.at(i).allocator_v2_, obj, tmp_obj, true)); @@ -7565,6 +7621,9 @@ int ObSPIService::collect_cells(pl::ObPLExecCtx &ctx, if ((result_type.is_blob() || result_type.is_blob_locator() || obj.is_blob() || obj.is_blob_locator()) && lib::is_oracle_mode()) { cast_ctxs.at(i).cast_mode_ |= CM_ENABLE_BLOB_CAST; } + if (OB_ISNULL(cast_ctxs.at(i).exec_ctx_)) { + cast_ctxs.at(i).exec_ctx_ = ctx.exec_ctx_; + } OZ (ObExprColumnConv::convert_with_null_check(tmp_obj, obj, result_type, is_strict, cast_ctxs.at(i))); if (OB_SUCC(ret) && tmp_obj.need_deep_copy() && obj.get_string_ptr() == tmp_obj.get_string_ptr()) { // obj may not deep copied in ObExprColumnConv::convert(), do deep copy it if needed. @@ -7642,7 +7701,12 @@ int ObSPIService::convert_obj(ObPLExecCtx *ctx, for (int i = 0; OB_SUCC(ret) && i < obj_array.count(); ++i) { ObObj &obj = obj_array.at(i); tmp_obj.reset(); - obj.set_collation_level(result_types[i].get_collation_level()); + if (!obj.is_user_defined_sql_type()) { + // collation/collation level is used as subschema id for sql udt + // but on field collation type, and collation level is set to other values for output + // so, ignore cs_type, cs_level setting here + obj.set_collation_level(result_types[i].get_collation_level()); + } LOG_DEBUG("column convert", K(obj.get_meta()), K(result_types[i].get_meta_type()), K(current_type.at(i)), K(result_types[i].get_accuracy())); if (obj.is_pl_extend()/* && pl::PL_RECORD_TYPE == obj.get_meta().get_extend_type()*/ @@ -7674,10 +7738,11 @@ int ObSPIService::convert_obj(ObPLExecCtx *ctx, } } else if (!(obj.is_pl_extend() || obj.is_user_defined_sql_type() + || obj.is_geometry() || (obj.is_null() && !current_type.at(i).get_meta_type().is_xml_sql_type())) && result_types[i].get_meta_type().is_ext() && !ob_is_xml_pl_type(result_types[i].get_obj_type(), result_types[i].get_udt_id())) { - // sql udt can cast to pl extend, null from sql udt type can cast to pl extend(xmltype) + // sql udt or oracle gis can cast to pl extend, null from sql udt type can cast to pl extend(xmltype) // but null may not cast to other pl extends (return error 4016 in store_datums) // support: select extract(xmlparse(document 'a'), '/b') into xml_data from dual; // not support: select null into xml_data from dual; @@ -7713,6 +7778,9 @@ int ObSPIService::convert_obj(ObPLExecCtx *ctx, && lib::is_oracle_mode()) { cast_ctx.cast_mode_ |= CM_ENABLE_BLOB_CAST; } + if (OB_SUCC(ret) && ((result_type.is_ext() && (obj.is_user_defined_sql_type() || obj.is_geometry())))) { + cast_ctx.exec_ctx_ = ctx->exec_ctx_; + } if (OB_FAIL(ret)) { } else if (result_type.is_null() || result_type.is_unknown()) { tmp_obj = obj; @@ -7726,9 +7794,11 @@ int ObSPIService::convert_obj(ObPLExecCtx *ctx, || ob_is_string_tc(result_type.get_type()))) || (!((obj.get_meta().is_ext()) || obj.get_meta().get_type() == ObUserDefinedSQLType + || obj.get_meta().is_geometry() || obj.is_null()) && (result_type.get_type() == ObExtendType - || ob_is_xml_sql_type(result_type.get_type(), result_type.get_subschema_id())))) { + || ob_is_xml_sql_type(result_type.get_type(), result_type.get_subschema_id()))) + || (obj.get_meta().is_geometry() && lib::is_oracle_mode() && result_type.get_type() != ObExtendType)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("xml type can not convert other type in pl", K(ret)); } else if (result_type.is_ext() @@ -7762,6 +7832,24 @@ int ObSPIService::convert_obj(ObPLExecCtx *ctx, return ret; } +bool ObSPIService::is_sql_type_into_pl(ObObj &dest_addr, ObIArray &obj_array) +{ + bool bret = false; + if (1 == obj_array.count()) { + // query result is oracle gis, will convert to pl extend type + if (dest_addr.is_pl_extend() && obj_array.at(0).is_pl_extend()) { + ObPLComposite *left = reinterpret_cast(dest_addr.get_ext()); + ObPLComposite *right = reinterpret_cast(obj_array.at(0).get_ext()); + if (OB_NOT_NULL(left) && OB_NOT_NULL(right) + && left->get_id() == right->get_id() + && ObObjUDTUtil::ob_is_supported_sql_udt(left->get_id())) { + bret = true; + } + } + } + return bret; +} + int ObSPIService::store_result(ObPLExecCtx *ctx, const ObSqlExpression *result_expr, const ObDataType *result_types, @@ -7877,7 +7965,7 @@ int ObSPIService::store_result(ObPLExecCtx *ctx, ObIAllocator *alloc = NULL != pkg_allocator ? pkg_allocator : cast_ctx.allocator_v2_; CK (OB_NOT_NULL(alloc)); // udt会在store datums深拷 - if (OB_SUCC(ret) && !is_schema_object) { + if (OB_SUCC(ret) && !is_schema_object && !is_sql_type_into_pl(result_address, *calc_array)) { for (int64_t i = 0; OB_SUCC(ret) && i < calc_array->count(); ++i) { ObObj tmp; if (calc_array->at(i).is_pl_extend()) { @@ -8181,17 +8269,14 @@ int ObSPIService::store_result(ObPLExecCtx *ctx, return ret; } -int ObSPIService::store_datums(ObObj &dest_addr, - ObIArray &obj_array, - ObIAllocator *alloc, - ObSQLSessionInfo *session_info, - bool is_schema_object) +int ObSPIService::store_datums(ObObj &dest_addr, ObIArray &obj_array, + ObIAllocator *alloc, ObSQLSessionInfo *session_info, bool is_schema_object) { int ret = OB_SUCCESS; if (obj_array.empty() || OB_ISNULL(alloc)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Argument passed in is NULL", K(dest_addr), K(obj_array), K(ret)); - } else if (is_schema_object) { + } else if (is_schema_object || is_sql_type_into_pl(dest_addr, obj_array)) { ObObj src; CK (dest_addr.is_pl_extend()); /* schema record只能作为单独的into variable存在 @@ -8234,7 +8319,7 @@ int ObSPIService::store_datums(ObObj &dest_addr, } else if (OB_ISNULL(record = static_cast(composite))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected record to store datum", KPC(record), KPC(composite), K(ret)); - } else if (record->get_count() != obj_array.count()) { + } else if (record->get_count() != obj_array.count() && record->get_id() != T_OBJ_SDO_GEOMETRY) { //Example: for idx (select obj(1,2) from dual) loop null; end loop; //which is not supported yet!!! Will fixed it later in OB 4.2 version. ret = OB_NOT_SUPPORTED; diff --git a/src/sql/ob_spi.h b/src/sql/ob_spi.h index 608a2f7565..724edd739f 100644 --- a/src/sql/ob_spi.h +++ b/src/sql/ob_spi.h @@ -1013,7 +1013,8 @@ private: bool is_type_record); static int store_datums(ObObj &dest_addr, ObIArray &result, - ObIAllocator *alloc, ObSQLSessionInfo *session_info, bool is_schema_object); + ObIAllocator *alloc, ObSQLSessionInfo *session_info, + bool is_schema_object); static int store_datum(int64_t ¤t_addr, const ObObj &obj, ObSQLSessionInfo *session_info); @@ -1100,6 +1101,7 @@ private: const int64_t *formal_param_idxs, const ObSqlExpression **actual_param_exprs, int64_t cursor_param_count); + static bool is_sql_type_into_pl(ObObj &dest_addr, ObIArray &obj_array); }; struct ObPLSubPLSqlTimeGuard diff --git a/src/sql/ob_sql.cpp b/src/sql/ob_sql.cpp index a54546f0fb..ab1ff77a40 100644 --- a/src/sql/ob_sql.cpp +++ b/src/sql/ob_sql.cpp @@ -778,16 +778,44 @@ int ObSql::fill_select_result_set(ObResultSet &result_set, ObSqlCtx *context, co } else if (ObNumberType == field.type_.get_type()) { field.type_.set_number(number); } - if (expr->get_result_type().is_user_defined_sql_type()) { - if (expr->get_result_type().is_xml_sql_type()) { - // ToDo : @gehao, need record sub schemid on ObField? - field.type_.set_collation_type(CS_TYPE_BINARY); - field.type_.set_collation_level(CS_LEVEL_IMPLICIT); + if (expr->get_result_type().is_user_defined_sql_type() || + expr->get_result_type().is_collection_sql_type() || + ((PC_PS_MODE == mode || PC_PL_MODE == mode) && expr->get_result_type().is_geometry() && lib::is_oracle_mode())) {//oracle gis ps protocol + uint16_t subschema_id = expr->get_result_type().get_subschema_id(); + uint16_t tmp_subschema_id = ObInvalidSqlType; + uint64_t udt_id = expr->get_result_type().get_udt_id(); + ObSqlUDTMeta udt_meta; + if (subschema_id == ObXMLSqlType) { + udt_id = T_OBJ_XML; + } + if (expr->get_result_type().is_geometry()) { + udt_id = T_OBJ_SDO_GEOMETRY; + field.type_.meta_.set_ext(); + field.accuracy_.set_accuracy(T_OBJ_SDO_GEOMETRY); + } + if (OB_FAIL(result_set.get_exec_context().get_subschema_id_by_udt_id(udt_id, tmp_subschema_id))) { + LOG_WARN("unsupported udt id", K(ret), K(subschema_id)); + } else if (OB_FAIL(result_set.get_exec_context().get_sqludt_meta_by_subschema_id(tmp_subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(tmp_subschema_id)); + } else if(ObObjUDTUtil::ob_is_supported_sql_udt(udt_meta.udt_id_)) { + // common udt constructors or functions set udt id , but xml exprs not + if (udt_meta.udt_id_ == T_OBJ_XML) { + field.accuracy_.set_accuracy(T_OBJ_XML); + } else if (udt_id != udt_meta.udt_id_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("udt id mismarch", K(ret), K(udt_id), K(udt_meta.udt_id_)); + } + field.type_.set_subschema_id(tmp_subschema_id); field.charsetnr_ = CS_TYPE_BINARY; - field.length_ = OB_MAX_LONGTEXT_LENGTH; // set MAX_ACCURACY? + field.length_ = OB_MAX_LONGTEXT_LENGTH; } else { ret = OB_NOT_SUPPORTED; - LOG_WARN("udt type not supported", K(ret), "subschema id",expr->get_result_type().get_subschema_id()); + LOG_WARN("udt type not supported", K(ret), K(tmp_subschema_id)); + } + if (OB_SUCC(ret)) { + if (OB_FAIL(ob_write_string(alloc, ObString(udt_meta.udt_name_len_, udt_meta.udt_name_), field.type_name_))) { + LOG_WARN("fail to alloc string", K(i), K(field), K(ret)); + } } } else if (!expr->get_result_type().is_ext() && OB_FAIL(expr->get_length_for_meta_in_bytes(field.length_))) { LOG_WARN("get length failed", K(ret), KPC(expr)); @@ -2885,8 +2913,10 @@ int ObSql::generate_stmt(ParseResult &parse_result, ObResolver resolver(resolver_ctx); NG_TRACE(resolve_begin); - - if (stmt::T_ANONYMOUS_BLOCK == context.stmt_type_ + if (OB_FAIL(plan_ctx->build_subschema_ctx_by_param_store(context.schema_guard_))) { + // only when param has sql udt types + SQL_LOG(WARN, "failed to build sbuschema ctx by param_store", K(ret)); + } else if (stmt::T_ANONYMOUS_BLOCK == context.stmt_type_ && context.is_prepare_protocol_ && !context.is_prepare_stage_ && !context.is_pre_execute_) { diff --git a/src/sql/ob_sql_context.h b/src/sql/ob_sql_context.h index 2422e26903..0332230f0f 100644 --- a/src/sql/ob_sql_context.h +++ b/src/sql/ob_sql_context.h @@ -554,6 +554,7 @@ public: // release dynamic allocated memory // void clear(); + public: ObMultiStmtItem multi_stmt_item_; ObSQLSessionInfo *session_info_; diff --git a/src/sql/ob_sql_utils.cpp b/src/sql/ob_sql_utils.cpp index d12b97fa56..63d9181c9b 100644 --- a/src/sql/ob_sql_utils.cpp +++ b/src/sql/ob_sql_utils.cpp @@ -434,6 +434,20 @@ int ObSQLUtils::calc_const_or_calculable_expr( } } else { is_valid = true; + if (result.is_pl_extend()) { + if (OB_ISNULL(exec_ctx->get_pl_ctx())) { + if (OB_FAIL(exec_ctx->init_pl_ctx())) { + LOG_WARN("failed to init pl ctx", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(exec_ctx->get_pl_ctx())) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("pl ctx is null", K(ret)); + } else if (OB_FAIL(exec_ctx->get_pl_ctx()->add(result))) { + LOG_WARN("failed to add pl obj to pl ctx", K(ret)); + } + } } if (OB_SUCC(ret) && !hit_cache) { if (OB_FAIL(store_result_to_ctx(*exec_ctx, raw_expr, result, is_valid))) { @@ -795,12 +809,19 @@ int ObSQLUtils::se_calc_const_expr(ObSQLSessionInfo *session, } else if (OB_UNLIKELY(org_obj_cnt + 1 != phy_plan_ctx.get_param_store().count())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unpected param store", K(phy_plan_ctx.get_param_store()), K(org_obj_cnt)); - } else if (OB_FAIL(deep_copy_obj(allocator, - phy_plan_ctx.get_param_store().at(org_obj_cnt), - result))) { - LOG_WARN("failed to deep copy obj", K(ret)); } else { - // do nothing + const ObObj &tmp_result = phy_plan_ctx.get_param_store().at(org_obj_cnt); + if (!tmp_result.is_ext()) { + if (OB_FAIL(deep_copy_obj(allocator, tmp_result, result))) { + LOG_WARN("failed to deep copy obj", K(ret)); + } + } else { + // res is_ext, data in obj may be destructed when the temp exec ctx destruct at the end. + // e.g. eval_collection_construct is called + if (OB_FAIL(pl::ObUserDefinedType::deep_copy_obj(allocator, tmp_result, result))) { + LOG_WARN("failed to deep copy pl extend obj", K(ret), K(tmp_result)); + } + } } } } @@ -5068,7 +5089,10 @@ int ObSQLUtils::store_result_to_ctx(ObExecContext &exec_ctx, } else { key = reinterpret_cast(expr); if (is_valid) { - if (OB_FAIL(ob_write_obj(exec_ctx.get_allocator(), result, val))) { + if (result.is_pl_extend()) { + // pl extend type is already deep copied in se_calc_const_expr + val = result; + } else if (OB_FAIL(ob_write_obj(exec_ctx.get_allocator(), result, val))) { LOG_WARN("failed to write obj", K(result), K(ret)); } } else { diff --git a/src/sql/optimizer/ob_join_order.cpp b/src/sql/optimizer/ob_join_order.cpp index 723c40c83c..f7da907b2d 100644 --- a/src/sql/optimizer/ob_join_order.cpp +++ b/src/sql/optimizer/ob_join_order.cpp @@ -1659,12 +1659,12 @@ int ObJoinOrder::will_use_das(const uint64_t table_id, //contain nested sql(pl udf or in nested sql) //trigger or foreign key in the top sql not force to use DAS TSC //has function table - if (force_das_tsc) { - create_das_path = true; - create_basic_path = false; - } else if (is_sample_stmt || is_online_ddl_insert) { + if (is_sample_stmt || is_online_ddl_insert) { create_das_path = false; create_basic_path = true; + } else if (force_das_tsc) { + create_das_path = true; + create_basic_path = false; } else if (OB_FAIL(get_plan()->get_log_plan_hint().check_use_das(table_id, hint_force_das, hint_force_no_das))) { LOG_WARN("table_item is null", K(ret), K(table_id)); @@ -4549,8 +4549,9 @@ int ObJoinOrder::generate_const_predicates_from_view(const ObDMLStmt *stmt, if (OB_ISNULL(sel_expr = child_stmt->get_select_item(idx).expr_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected expr", K(ret), K(idx), K(sel_expr)); - } else if (!sel_expr->is_const_expr() || sel_expr->get_result_type().is_lob() || - ob_is_xml_sql_type(sel_expr->get_result_type().get_type(), sel_expr->get_result_type().get_subschema_id())) { + } else if (!sel_expr->is_const_expr() || sel_expr->get_result_type().is_lob() + || ob_is_xml_sql_type(sel_expr->get_result_type().get_type(), sel_expr->get_result_type().get_subschema_id()) + || ob_is_geometry(sel_expr->get_result_type().get_type())) { //do nothing } else if (OB_FAIL(ObTransformUtils::is_expr_not_null(not_null_ctx, sel_expr, diff --git a/src/sql/optimizer/ob_opt_est_parameter_normal.h b/src/sql/optimizer/ob_opt_est_parameter_normal.h index 24eb14f94a..c79764ddf9 100644 --- a/src/sql/optimizer/ob_opt_est_parameter_normal.h +++ b/src/sql/optimizer/ob_opt_est_parameter_normal.h @@ -119,6 +119,7 @@ const static double comparison_params_normal[ObMaxTC+1] = { NORMAL_CMP_CHAR_COST, // geometry NORMAL_CMP_CHAR_COST, // user defined type NORMAL_CMP_NUMBER_COST, // ObDecimalIntTC + NORMAL_CMP_CHAR_COST, // collection sql type }; const static double hash_params_normal[ObMaxTC+1] = { @@ -148,6 +149,7 @@ const static double hash_params_normal[ObMaxTC+1] = { NORMAL_HASH_CHAR_COST, // geometry NORMAL_HASH_CHAR_COST, // user defined type NORMAL_HASH_NUMBER_COST, // ObDecimalIntTC + NORMAL_HASH_CHAR_COST, // collection sql type }; const static double project_params_normal[2][2][MAX_PROJECT_TYPE] = { diff --git a/src/sql/optimizer/ob_opt_est_parameter_vector.h b/src/sql/optimizer/ob_opt_est_parameter_vector.h index 7acf2855c8..c6f47ff63a 100644 --- a/src/sql/optimizer/ob_opt_est_parameter_vector.h +++ b/src/sql/optimizer/ob_opt_est_parameter_vector.h @@ -118,6 +118,7 @@ const static double comparison_params_vector[ObMaxTC+1] = { VECTOR_CMP_CHAR_COST, // geometry VECTOR_CMP_CHAR_COST, // user defined type VECTOR_CMP_NUMBER_COST, // ObDecimalIntTC + VECTOR_CMP_CHAR_COST, // collection sql type }; const static double hash_params_vector[ObMaxTC+1] = { @@ -147,6 +148,7 @@ const static double hash_params_vector[ObMaxTC+1] = { VECTOR_HASH_CHAR_COST, // geometry VECTOR_HASH_CHAR_COST, // user defined type VECTOR_HASH_NUMBER_COST, // ObDecimalIntTC + VECTOR_HASH_CHAR_COST, // collection sql type }; const static double project_params_vector[2][2][MAX_PROJECT_TYPE] = { diff --git a/src/sql/optimizer/ob_optimizer_util.cpp b/src/sql/optimizer/ob_optimizer_util.cpp index dc6e131e2f..62b5ce1246 100644 --- a/src/sql/optimizer/ob_optimizer_util.cpp +++ b/src/sql/optimizer/ob_optimizer_util.cpp @@ -6557,6 +6557,7 @@ int ObOptimizerUtil::try_add_cast_to_set_child_list(ObIAllocator *allocator, && (ob_is_oracle_temporal_type(right_type.get_type()))) || (left_type.is_urowid() && right_type.is_urowid()) || (is_oracle_mode() && left_type.is_lob() && right_type.is_lob() && left_type.get_collation_type() == right_type.get_collation_type()) + || (is_oracle_mode() && left_type.is_geometry() && right_type.is_geometry()) || (is_oracle_mode() && left_type.is_lob_locator() && right_type.is_lob_locator() && left_type.get_collation_type() == right_type.get_collation_type()) || (is_oracle_mode() && (ob_is_user_defined_sql_type(left_type.get_type()) || ob_is_user_defined_pl_type(left_type.get_type())) && (ob_is_user_defined_sql_type(right_type.get_type()) || ob_is_user_defined_pl_type(right_type.get_type()))))) { @@ -6588,6 +6589,10 @@ int ObOptimizerUtil::try_add_cast_to_set_child_list(ObIAllocator *allocator, LOG_WARN("character set mismatch", K(ret), K(left_cs), K(right_cs)); } } + } else if (lib::is_oracle_mode() && is_distinct + && (right_type.is_geometry() || left_type.is_geometry())) { + ret = OB_ERR_COMPARE_VARRAY_LOB_ATTR; + LOG_WARN("column type incompatible", K(ret), K(left_type), K(right_type)); } LOG_DEBUG("data type check for each select item in set operator", K(left_type), K(right_type)); @@ -6646,6 +6651,9 @@ int ObOptimizerUtil::try_add_cast_to_set_child_list(ObIAllocator *allocator, } else if (lib::is_oracle_mode() && is_distinct && right_type.is_json()) { ret = OB_ERR_INVALID_CMP_OP; LOG_WARN("column type incompatible", K(ret), K(left_type), K(right_type)); + } else if (lib::is_oracle_mode() && is_distinct && right_type.is_geometry()) { + ret = OB_ERR_COMPARE_VARRAY_LOB_ATTR; + LOG_WARN("column type incompatible", K(ret), K(left_type), K(right_type)); } else { res_type = left_type; } diff --git a/src/sql/parser/non_reserved_keywords_mysql_mode.c b/src/sql/parser/non_reserved_keywords_mysql_mode.c index 77f4929654..888255415c 100644 --- a/src/sql/parser/non_reserved_keywords_mysql_mode.c +++ b/src/sql/parser/non_reserved_keywords_mysql_mode.c @@ -1019,6 +1019,7 @@ static const NonReservedKeyword Mysql_none_reserved_keywords[] = {"kv_attributes", KV_ATTRIBUTES}, {"RESOURCE_POOL", RESOURCE_POOL}, {"clone", CLONE}, + {"_st_asmvt", _ST_ASMVT}, }; /** https://dev.mysql.com/doc/refman/5.7/en/sql-syntax-prepared-statements.html diff --git a/src/sql/parser/sql_parser_mysql_mode.y b/src/sql/parser/sql_parser_mysql_mode.y index 6ab6a59448..88223b12fe 100644 --- a/src/sql/parser/sql_parser_mysql_mode.y +++ b/src/sql/parser/sql_parser_mysql_mode.y @@ -343,7 +343,7 @@ END_P SET_VAR DELIMITER SET_TP SHARE SHUTDOWN SIGNED SIMPLE SKIP_INDEX SLAVE SLOW SLOT_IDX SNAPSHOT SOCKET SOME SONAME SOUNDS SOURCE SPFILE SPLIT SQL_AFTER_GTIDS SQL_AFTER_MTS_GAPS SQL_BEFORE_GTIDS SQL_BUFFER_RESULT SQL_CACHE SQL_NO_CACHE SQL_ID SCHEMA_ID SQL_THREAD SQL_TSI_DAY SQL_TSI_HOUR SQL_TSI_MINUTE SQL_TSI_MONTH - SQL_TSI_QUARTER SQL_TSI_SECOND SQL_TSI_WEEK SQL_TSI_YEAR SRID STANDBY STAT START STARTS STATS_AUTO_RECALC + SQL_TSI_QUARTER SQL_TSI_SECOND SQL_TSI_WEEK SQL_TSI_YEAR SRID STANDBY _ST_ASMVT STAT START STARTS STATS_AUTO_RECALC STATS_PERSISTENT STATS_SAMPLE_PAGES STATUS STATEMENTS STATISTICS STD STDDEV STDDEV_POP STDDEV_SAMP STRONG SYNCHRONIZATION SYNCHRONOUS STOP STORAGE STORAGE_FORMAT_VERSION STORE STORING STRING SUBCLASS_ORIGIN SUBDATE SUBJECT SUBPARTITION SUBPARTITIONS SUBSTR SUBSTRING SUCCESSFUL SUM @@ -520,7 +520,7 @@ END_P SET_VAR DELIMITER %type on_empty on_error json_on_response opt_returning_type opt_on_empty_or_error json_value_expr opt_ascii opt_truncate_clause %type ws_nweights opt_ws_as_char opt_ws_levels ws_level_flag_desc ws_level_flag_reverse ws_level_flags ws_level_list ws_level_list_item ws_level_number ws_level_range ws_level_list_or_range %type get_diagnostics_stmt get_statement_diagnostics_stmt get_condition_diagnostics_stmt statement_information_item_list condition_information_item_list statement_information_item condition_information_item statement_information_item_name condition_information_item_name condition_arg -%type method_opt method_list method extension +%type method_opt method_list method extension mvt_param %type opt_storage_name opt_calibration_list calibration_info_list %type switchover_tenant_stmt switchover_clause opt_verify %type recover_tenant_stmt recover_point_clause @@ -534,6 +534,7 @@ END_P SET_VAR DELIMITER %type table_values_caluse table_values_caluse_with_order_by_and_limit values_row_list row_value %type create_tenant_snapshot_stmt snapshot_name drop_tenant_snapshot_stmt clone_tenant_stmt clone_snapshot_option clone_tenant_option clone_tenant_option_list %type transfer_partition_stmt transfer_partition_clause part_info cancel_transfer_partition_clause +%type geometry_collection %type ttl_definition ttl_expr ttl_unit %type id_dot_id id_dot_id_dot_id %start sql_stmt @@ -2362,6 +2363,11 @@ ALL { | /*empty*/{ $$ = NULL; } ; +geometry_collection: +GEOMETRYCOLLECTION { $$ = NULL; } +| GEOMCOLLECTION { $$ = NULL; } +; + func_expr: MOD '(' expr ',' expr ')' { @@ -3025,25 +3031,42 @@ MOD '(' expr ',' expr ')' merge_nodes(expr_list, result, T_EXPR_LIST, $3); malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_MULTIPOLYGON, 1, expr_list); } -| GEOMETRYCOLLECTION '(' expr_list ')' +| geometry_collection '(' expr_list ')' { + UNUSED($1); ParseNode *expr_list = NULL; merge_nodes(expr_list, result, T_EXPR_LIST, $3); malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_GEOMCOLLECTION, 1, expr_list); } -| GEOMETRYCOLLECTION '(' ')' +| geometry_collection '(' ')' { + UNUSED($1); malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_GEOMCOLLECTION, 1, NULL); } -| GEOMCOLLECTION '(' expr_list ')' +| _ST_ASMVT '(' column_ref ')' { - ParseNode *expr_list = NULL; - merge_nodes(expr_list, result, T_EXPR_LIST, $3); - malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_GEOMCOLLECTION, 1, expr_list); + malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_ST_ASMVT, 1, $3); + $$->reserved_ = 0; } -| GEOMCOLLECTION '(' ')' +| _ST_ASMVT '(' column_ref ',' mvt_param ')' { - malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_GEOMCOLLECTION, 1, NULL); + malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_ST_ASMVT, 2, $3, $5); + $$->reserved_ = 0; +} +| _ST_ASMVT '(' column_ref ',' mvt_param ',' mvt_param ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_ST_ASMVT, 3, $3, $5, $7); + $$->reserved_ = 0; +} +| _ST_ASMVT '(' column_ref ',' mvt_param ',' mvt_param ',' mvt_param ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_ST_ASMVT, 4, $3, $5, $7, $9); + $$->reserved_ = 0; +} +| _ST_ASMVT '(' column_ref ',' mvt_param ',' mvt_param ',' mvt_param ',' mvt_param ')' +{ + malloc_non_terminal_node($$, result->malloc_pool_, T_FUN_SYS_ST_ASMVT, 5, $3, $5, $7, $9, $11); + $$->reserved_ = 0; } | SUM_OPNSIZE '(' expr ')' { @@ -3051,6 +3074,18 @@ MOD '(' expr ',' expr ')' } ; +mvt_param: +STRING_VALUE { $$ = $1; } +| INTNUM { $$ = $1; } +| '-' INTNUM +{ + $2->value_ = -$2->value_; + $$ = $2; +} +| NULLX { $$ = $1; } +| column_ref { $$ = $1; } +; + sys_interval_func: INTERVAL '(' expr ',' expr ')' { @@ -5613,8 +5648,9 @@ BINARY opt_string_length_i_v2 $$->param_num_ = 0; $$->sql_str_off_ = @1.first_column; } -| GEOMETRYCOLLECTION +| geometry_collection { + UNUSED($1); malloc_terminal_node($$, result->malloc_pool_, T_CAST_ARGUMENT); $$->value_ = 0; $$->int16_values_[OB_NODE_CAST_TYPE_IDX] = T_GEOMETRY; /* data type */ @@ -6045,8 +6081,9 @@ int_type_i opt_int_length_i opt_unsigned_i opt_zerofill_i $$->int32_values_[0] = 0; /* length */ $$->int32_values_[1] = 6; /* multipolygon, geometry uses collation type value convey sub geometry type. */ } -| GEOMETRYCOLLECTION +| geometry_collection { + UNUSED($1); malloc_terminal_node($$, result->malloc_pool_, T_GEOMETRY); $$->int32_values_[0] = 0; /* length */ $$->int32_values_[1] = 7; /* geometrycollection, geometry uses collation type value convey sub geometry type. */ @@ -20426,6 +20463,7 @@ ACCOUNT | SQL_TSI_WEEK | SQL_TSI_YEAR | SRID +| _ST_ASMVT | STACKED | STANDBY | START diff --git a/src/sql/plan_cache/ob_cache_object.cpp b/src/sql/plan_cache/ob_cache_object.cpp index 8964b35ec5..66652d48fc 100644 --- a/src/sql/plan_cache/ob_cache_object.cpp +++ b/src/sql/plan_cache/ob_cache_object.cpp @@ -97,6 +97,11 @@ int ObPlanCacheObject::set_params_info(const ParamStore ¶ms) param_info.scale_ = data_type.get_scale(); } LOG_DEBUG("ext params info", K(data_type), K(param_info), K(params.at(i))); + } else if (params.at(i).is_user_defined_sql_type() || params.at(i).is_collection_sql_type()) { + param_info.scale_ = 0; + uint64_t udt_id = params.at(i).get_accuracy().get_accuracy(); + *(reinterpret_cast(¶m_info.ext_real_type_)) = (udt_id >> 32) & UINT_MAX32; + *(reinterpret_cast(¶m_info.col_type_)) = (udt_id) & UINT_MAX32; } else { param_info.scale_ = params.at(i).get_scale(); param_info.precision_ = params.at(i).get_precision(); diff --git a/src/sql/plan_cache/ob_cache_object.h b/src/sql/plan_cache/ob_cache_object.h index d702e96109..1f462cbc8b 100644 --- a/src/sql/plan_cache/ob_cache_object.h +++ b/src/sql/plan_cache/ob_cache_object.h @@ -127,7 +127,7 @@ struct ObParamInfo common::ParamFlag flag_; common::ObScale scale_; common::ObObjType type_; - common::ObObjType ext_real_type_; + common::ObObjType ext_real_type_; // use as high 4 bytes of udt id if type is sql udt //处理Oracle模式空串在plan_cache中的匹配 bool is_oracle_empty_string_; common::ObCollationType col_type_; diff --git a/src/sql/plan_cache/ob_plan_set.cpp b/src/sql/plan_cache/ob_plan_set.cpp index e86f8e2a71..17f4be5f1d 100644 --- a/src/sql/plan_cache/ob_plan_set.cpp +++ b/src/sql/plan_cache/ob_plan_set.cpp @@ -251,10 +251,16 @@ int ObPlanSet::match_param_info(const ObParamInfo ¶m_info, K(param.get_type())); } - if (param.get_collation_type() != param_info.col_type_) { + if (param.get_collation_type() != param_info.col_type_ + && !(param.is_user_defined_sql_type() || param.is_collection_sql_type())) { is_same = false; } else if (param.get_param_meta().get_type() != param_info.type_) { is_same = false; + } else if (param.is_user_defined_sql_type() || param.is_collection_sql_type()) { + uint64_t udt_id_param = param.get_accuracy().get_accuracy(); + uint64_t udt_id_info = static_cast(param_info.ext_real_type_) << 32 + | static_cast(param_info.col_type_); + is_same = (udt_id_info == udt_id_param) ? true : false; } else if (param.is_ext()) { ObDataType data_type; if (!param_info.flag_.need_to_check_extend_type_) { diff --git a/src/sql/printer/ob_raw_expr_printer.cpp b/src/sql/printer/ob_raw_expr_printer.cpp index 42bc492880..be58a08e3d 100644 --- a/src/sql/printer/ob_raw_expr_printer.cpp +++ b/src/sql/printer/ob_raw_expr_printer.cpp @@ -20,6 +20,7 @@ #include "lib/worker.h" #include "pl/ob_pl_user_type.h" #include "pl/ob_pl_stmt.h" +#include "lib/geo/ob_sdo_geo_object.h" namespace oceanbase { @@ -1172,6 +1173,12 @@ int ObRawExprPrinter::print(ObAggFunRawExpr *expr) } break; } + case T_FUN_SYS_ST_ASMVT: { + if (OB_FAIL(print_st_asmvt(expr))) { + LOG_WARN("fail to print st asmvt.", K(ret)); + } + break; + } case T_FUN_GROUP_RANK: SET_SYMBOL_IF_EMPTY("rank"); case T_FUN_GROUP_DENSE_RANK: @@ -1600,6 +1607,38 @@ int ObRawExprPrinter::print_json_return_type(ObRawExpr *expr) return ret; } +int ObRawExprPrinter::print_st_asmvt(ObAggFunRawExpr *expr) +{ + INIT_SUCC(ret); + DATA_PRINTF("_st_asmvt("); + size_t param_count = expr->get_param_count(); + if (param_count < 3) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param count", K(param_count), K(ret)); + } else { + int64_t extra_param_cnt = static_cast(expr->get_param_expr(0))->get_value().get_int() + 1; + if (extra_param_cnt >= param_count) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected extra param cnt", K(param_count), K(ret), K(extra_param_cnt)); + } else if (expr->get_param_expr(extra_param_cnt)->get_expr_type() != T_REF_COLUMN) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param type", K(param_count), K(ret), K(extra_param_cnt), K(expr->get_param_expr(extra_param_cnt)->get_expr_type())); + } else { + ObColumnRefRawExpr *col_expr = static_cast(expr->get_param_expr(extra_param_cnt)); + PRINT_IDENT_WITH_QUOT(col_expr->get_database_name()); + DATA_PRINTF("."); + PRINT_IDENT_WITH_QUOT(col_expr->get_table_name()); + DATA_PRINTF(".*"); + } + for (size_t i = 1; i < extra_param_cnt && OB_SUCC(ret); i++) { + DATA_PRINTF(" ,"); + PRINT_EXPR(expr->get_param_expr(i)); + } + DATA_PRINTF(")"); + } + return ret; +} + int ObRawExprPrinter::print_json_mergepatch(ObSysFunRawExpr *expr) { INIT_SUCC(ret); @@ -3263,6 +3302,15 @@ int ObRawExprPrinter::print(ObSysFunRawExpr *expr) PRINT_EXPR(expr->get_param_expr(2)); break; } + // for bugfix: 52438113/52226266 + case T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT: { + OZ(print_sql_udt_construct(expr)); + break; + } + case T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS: { + OZ(print_sql_udt_attr_access(expr)); + break; + } default: { DATA_PRINTF("%.*s", LEN_AND_PTR(func_name)); OZ(inner_print_fun_params(*expr)); @@ -4822,5 +4870,91 @@ int ObRawExprPrinter::print_xml_attributes_expr(ObSysFunRawExpr *expr) return ret; } +int ObRawExprPrinter::print_sql_udt_attr_access(ObSysFunRawExpr *expr) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(expr) || (expr->get_param_count() != 2)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param count of expr", K(ret), KPC(expr)); + } else if (!static_cast(expr->get_param_expr(1))->get_value().is_int()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("doc type value isn't int value"); + } else { + PRINT_EXPR(expr->get_param_expr(0)); + DATA_PRINTF("."); + int64_t attr_idx = static_cast(expr->get_param_expr(1))->get_value().get_int(); + switch (static_cast(attr_idx)) { + case ObSdoGeoAttrIdx::ObGtype: { + PRINT_IDENT_WITH_QUOT("SDO_GTYPE"); + break; + } + case ObSdoGeoAttrIdx::ObSrid: { + PRINT_IDENT_WITH_QUOT("SDO_SRID"); + break; + } + case ObSdoGeoAttrIdx::ObPointX: { + DATA_PRINTF("\"SDO_POINT\".\"X\""); + break; + } + case ObSdoGeoAttrIdx::ObPointY: { + DATA_PRINTF("\"SDO_POINT\".\"Y\""); + break; + } + case ObSdoGeoAttrIdx::ObPointZ: { + DATA_PRINTF("\"SDO_POINT\".\"Z\""); + break; + } + case ObSdoGeoAttrIdx::ObElemArray: { + PRINT_IDENT_WITH_QUOT("SDO_ELEM_INFO"); + break; + } + case ObSdoGeoAttrIdx::ObOrdArray: { + PRINT_IDENT_WITH_QUOT("SDO_ORDINATES"); + break; + } + default: { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid format type value", K(attr_idx), K(ret)); + } + } + } + return ret; +} +int ObRawExprPrinter::print_sql_udt_construct(ObSysFunRawExpr *expr) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(expr) || (expr->get_param_count() != 2)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param count of expr", K(ret), KPC(expr)); + } else if (!static_cast(expr->get_param_expr(1))->get_value().is_int()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("doc type value isn't int value"); + } else { + PRINT_EXPR(expr->get_param_expr(0)); + DATA_PRINTF("."); + int64_t udt_id = static_cast(expr->get_param_expr(1))->get_value().get_int(); + switch (static_cast(udt_id)) { + case ObUDTType::T_OBJ_SDO_POINT: { + PRINT_IDENT_WITH_QUOT("SDO_POINT"); + break; + } + case ObUDTType::T_OBJ_SDO_ELEMINFO_ARRAY: { + PRINT_IDENT_WITH_QUOT("SDO_ELEM_INFO"); + break; + } + case ObUDTType::T_OBJ_SDO_ORDINATE_ARRAY: { + PRINT_IDENT_WITH_QUOT("SDO_ORDINATES"); + break; + } + default: { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid format type value", K(udt_id), K(ret)); + } + } + } + return ret; +} + + } //end of namespace sql } //end of namespace oceanbase diff --git a/src/sql/printer/ob_raw_expr_printer.h b/src/sql/printer/ob_raw_expr_printer.h index 57121e9ebd..276dc1fb51 100644 --- a/src/sql/printer/ob_raw_expr_printer.h +++ b/src/sql/printer/ob_raw_expr_printer.h @@ -157,6 +157,9 @@ private: int print_xml_attributes_expr(ObSysFunRawExpr *expr); int print_xml_agg_expr(ObAggFunRawExpr *expr); int print_xml_serialize_expr(ObSysFunRawExpr *expr); + int print_sql_udt_attr_access(ObSysFunRawExpr *expr); + int print_sql_udt_construct(ObSysFunRawExpr *expr); + int print_st_asmvt(ObAggFunRawExpr *expr); int print_type(const ObExprResType &dst_type); diff --git a/src/sql/resolver/ddl/ob_alter_table_resolver.cpp b/src/sql/resolver/ddl/ob_alter_table_resolver.cpp index efadf10c70..31a9cfe757 100644 --- a/src/sql/resolver/ddl/ob_alter_table_resolver.cpp +++ b/src/sql/resolver/ddl/ob_alter_table_resolver.cpp @@ -23,6 +23,7 @@ #include "sql/resolver/ob_resolver_utils.h" #include "sql/resolver/dml/ob_delete_resolver.h" #include "share/ob_index_builder_util.h" +#include "sql/engine/expr/ob_expr_sql_udt_utils.h" #include "sql/engine/expr/ob_expr_lob_utils.h" #ifdef OB_BUILD_ORACLE_XML #include "lib/xml/ob_xml_parser.h" @@ -4672,6 +4673,53 @@ int ObAlterTableResolver::process_timestamp_column(ObColumnResolveStat &stat, return ret; } +int ObAlterTableResolver::check_sdo_geom_default_value(ObAlterTableStmt *alter_table_stmt, + AlterColumnSchema &column_schema) +{ + int ret = OB_SUCCESS; + if (lib::is_oracle_mode() && column_schema.is_geometry()) { + ObObj orig_default_value; + uint64_t tenant_data_version = 0; + if (OB_FAIL(GET_MIN_DATA_VERSION(session_info_->get_effective_tenant_id(), tenant_data_version))) { + LOG_WARN("get tenant data version failed", K(ret)); + } else if (tenant_data_version < DATA_VERSION_4_2_2_0 + || (tenant_data_version >= DATA_VERSION_4_3_0_0 && tenant_data_version < DATA_VERSION_4_3_1_0)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("sdo_geometry is not supported when data version is below 4.2.2.0 or data_version is above 4.3.0.0 but below 4.3.1.0", K(ret), K(tenant_data_version), K(column_schema)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "tenant data version is less than 4.2.2 or data_version is above 4.3.0.0 but below 4.3.1.0, sdo_geometry"); + } else if (OB_ISNULL(alter_table_stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("alter table stmt not exist", K(ret)); + } else if (column_schema.get_cur_default_value().is_null()) { + } else if (OB_FAIL(get_udt_column_default_values(column_schema.get_cur_default_value(), + session_info_->get_tz_info_wrap(), + *allocator_, + column_schema, + session_info_->get_sql_mode(), + session_info_, + schema_checker_, + orig_default_value, + alter_table_stmt->get_ddl_arg()))) { + LOG_WARN("fail to calc xmltype default value expr", K(ret)); + } else if (orig_default_value.is_null()) { + } else { + // get rid of lob header + ObObj default_val; + ObString swkb; + if (OB_FAIL(ObTextStringHelper::read_real_string_data(allocator_, orig_default_value, swkb))) { + LOG_WARN("fail to get real data.", K(ret)); + } else { + default_val.set_common_value(swkb); + default_val.set_meta_type(column_schema.get_meta_type()); + if (OB_FAIL(column_schema.set_orig_default_value(default_val))) { + LOG_WARN("fail to set orig default value", K(default_val), K(ret)); + } + } + } + } + return ret; +} + int ObAlterTableResolver::add_udt_hidden_column(ObAlterTableStmt *alter_table_stmt, AlterColumnSchema &column_schema) { @@ -4704,7 +4752,6 @@ int ObAlterTableResolver::add_udt_hidden_column(ObAlterTableStmt *alter_table_st } else if (column_schema.get_cur_default_value().is_null()) { } else if (OB_FAIL(get_udt_column_default_values(column_schema.get_cur_default_value(), session_info_->get_tz_info_wrap(), - nls_formats_str, *allocator_, column_schema, session_info_->get_sql_mode(), @@ -4854,7 +4901,9 @@ int ObAlterTableResolver::resolve_add_column(const ParseNode &node) } //add column if (OB_SUCC(ret)) { - if (OB_FAIL(alter_table_stmt->add_column(alter_column_schema))) { + if (OB_FAIL(check_sdo_geom_default_value(alter_table_stmt, alter_column_schema))) { + SQL_RESV_LOG(WARN, "check sdo geometry default value failed!", K(ret)); + } else if (OB_FAIL(alter_table_stmt->add_column(alter_column_schema))) { SQL_RESV_LOG(WARN, "Add alter column schema failed!", K(ret)); } else if (OB_FAIL(add_udt_hidden_column(alter_table_stmt, alter_column_schema))) { SQL_RESV_LOG(WARN, "Add alter udt hidden column schema failed!", K(ret)); @@ -5346,9 +5395,12 @@ int ObAlterTableResolver::resolve_change_column(const ParseNode &node) ret = OB_ERR_PRIMARY_CANT_HAVE_NULL; LOG_WARN("can't set primary key nullable", K(ret)); } else if (ObGeometryType == origin_col_schema->get_data_type() + && ObGeometryType == alter_column_schema.get_data_type() + && alter_column_schema.get_geo_type() != common::ObGeoType::GEOMETRY + && origin_col_schema->get_geo_type() != common::ObGeoType::GEOMETRY && origin_col_schema->get_geo_type() != alter_column_schema.get_geo_type()) { - ret = OB_NOT_SUPPORTED; - LOG_USER_ERROR(OB_NOT_SUPPORTED, "Change geometry type"); + ret = OB_ERR_CANT_CREATE_GEOMETRY_OBJECT; + LOG_USER_ERROR(OB_ERR_CANT_CREATE_GEOMETRY_OBJECT); LOG_WARN("can't not change geometry type", K(ret), K(origin_col_schema->get_geo_type()), K(alter_column_schema.get_geo_type())); } else if (ObGeometryType == origin_col_schema->get_data_type() @@ -5597,6 +5649,22 @@ int ObAlterTableResolver::resolve_modify_column(const ParseNode &node, SQL_RESV_LOG(WARN, "check column in part key failed", K(ret)); } } + if (OB_SUCC(ret) && alter_column_schema.is_udt_related_column(lib::is_oracle_mode())) { + ObString tmp_str; + if (OB_FAIL(ObDDLResolver::check_udt_default_value(alter_column_schema.get_cur_default_value(), + session_info_->get_tz_info_wrap(), + &tmp_str, // useless + *allocator_, + *const_cast(table_schema_), + alter_column_schema, + session_info_->get_sql_mode(), + session_info_, + schema_checker_, + alter_table_stmt->get_ddl_arg()))) { + SQL_RESV_LOG(WARN, "check udt column default value failed in alter table modify stmt", + K(ret), K(alter_column_schema.get_cur_default_value())); + } + } if (OB_SUCC(ret)) { if (OB_FAIL(alter_table_stmt->add_column(alter_column_schema))) { SQL_RESV_LOG(WARN, "Add alter column schema failed!", K(ret)); @@ -5613,9 +5681,12 @@ int ObAlterTableResolver::resolve_modify_column(const ParseNode &node, ret = OB_ERR_PRIMARY_CANT_HAVE_NULL; LOG_WARN("can't set primary key nullable", K(ret)); } else if (ObGeometryType == origin_col_schema->get_data_type() + && ObGeometryType == alter_column_schema.get_data_type() + && alter_column_schema.get_geo_type() != common::ObGeoType::GEOMETRY + && origin_col_schema->get_geo_type() != common::ObGeoType::GEOMETRY && origin_col_schema->get_geo_type() != alter_column_schema.get_geo_type()) { - ret = OB_NOT_SUPPORTED; - LOG_USER_ERROR(OB_NOT_SUPPORTED, "Modify geometry type"); + ret = OB_ERR_CANT_CREATE_GEOMETRY_OBJECT; + LOG_USER_ERROR(OB_ERR_CANT_CREATE_GEOMETRY_OBJECT); LOG_WARN("can't not modify geometry type", K(ret), K(origin_col_schema->get_geo_type()), K(alter_column_schema.get_geo_type())); } else if (ObGeometryType == origin_col_schema->get_data_type() diff --git a/src/sql/resolver/ddl/ob_alter_table_resolver.h b/src/sql/resolver/ddl/ob_alter_table_resolver.h index ca770d1f45..3968de15f8 100644 --- a/src/sql/resolver/ddl/ob_alter_table_resolver.h +++ b/src/sql/resolver/ddl/ob_alter_table_resolver.h @@ -84,6 +84,7 @@ public: int resolve_set_interval(ObAlterTableStmt *stmt, const ParseNode &node); int add_udt_hidden_column(ObAlterTableStmt *alter_table_stmt, AlterColumnSchema &column_schema); + int check_sdo_geom_default_value(ObAlterTableStmt *alter_table_stmt, AlterColumnSchema &column_schema); int add_new_indexkey_for_oracle_temp_table(obrpc::ObCreateIndexArg &index_arg); diff --git a/src/sql/resolver/ddl/ob_create_table_resolver.cpp b/src/sql/resolver/ddl/ob_create_table_resolver.cpp index c7389bedac..25de434a62 100644 --- a/src/sql/resolver/ddl/ob_create_table_resolver.cpp +++ b/src/sql/resolver/ddl/ob_create_table_resolver.cpp @@ -233,12 +233,17 @@ int ObCreateTableResolver::add_hidden_external_table_pk_col() return ret; } -int ObCreateTableResolver::add_generated_hidden_column_for_udt(ObTableSchema &table_schema, - ObSEArray &resolved_cols, - ObColumnSchemaV2 &udt_column) +int ObCreateTableResolver::add_udt_hidden_column(ObTableSchema &table_schema, + ObSEArray &resolved_cols, + ObColumnSchemaV2 &udt_column) { int ret = OB_SUCCESS; - if (udt_column.is_xmltype()) { + uint64_t tenant_data_version = 0; + ObString tmp_str; + ObCreateTableStmt *create_table_stmt = static_cast(stmt_); + if (OB_FAIL(GET_MIN_DATA_VERSION(session_info_->get_effective_tenant_id(), tenant_data_version))) { + LOG_WARN("failed to get data version", K(ret)); + } else if (udt_column.is_xmltype()) { ObColumnSchemaV2 hidden_blob; ObSEArray gen_col_expr_arr; ObString tmp_str; @@ -271,12 +276,35 @@ int ObCreateTableResolver::add_generated_hidden_column_for_udt(ObTableSchema &ta } else if (OB_FAIL(resolved_cols.push_back(hidden_blob))) { SQL_RESV_LOG(WARN, "add column to table_schema failed", K(ret), K(hidden_blob)); } + } else if (udt_column.is_geometry() && lib::is_oracle_mode()) { + // oracle sdo_geometry type + if (tenant_data_version < DATA_VERSION_4_2_2_0 + || (tenant_data_version >= DATA_VERSION_4_3_0_0 && tenant_data_version < DATA_VERSION_4_3_1_0)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("sdo_geometry is not supported when data_version is below 4.2.2.0 or data_version is above 4.3.0.0 but below 4.3.1.0.", K(ret), K(tenant_data_version), K(udt_column)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "tenant data version is less than 4.2.2 or data_version is above 4.3.0.0 but below 4.3.1.0, sdo_geometry"); + } else if (OB_ISNULL(create_table_stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null create table stmt", K(ret)); + } else if (OB_FAIL(check_udt_default_value(udt_column.get_cur_default_value(), + session_info_->get_tz_info_wrap(), + &tmp_str, // useless + *allocator_, + table_schema, + udt_column, + session_info_->get_sql_mode(), + session_info_, + schema_checker_, + create_table_stmt->get_ddl_arg()))) { + SQL_RESV_LOG(WARN, "check udt column default value failed", K(ret), K(udt_column.get_cur_default_value())); + } + } return ret; } -int ObCreateTableResolver::add_generated_hidden_column_for_udt(ObTableSchema &table_schema, - ObColumnSchemaV2 &udt_column) +int ObCreateTableResolver::add_udt_hidden_column(ObTableSchema &table_schema, + ObColumnSchemaV2 &udt_column) { int ret = OB_SUCCESS; if (udt_column.is_xmltype()) { @@ -1268,7 +1296,7 @@ int ObCreateTableResolver::resolve_table_elements(const ParseNode *node, is_create_table_as, table_schema.is_external_table()))) { SQL_RESV_LOG(WARN, "resolve column definition failed", K(ret)); - } else if (!column.is_xmltype() && // xmltype will check after hidden column generated + } else if (!column.is_udt_related_column(lib::is_oracle_mode()) && // udt column will check after hidden column generated OB_FAIL(check_default_value(column.get_cur_default_value(), session_info_->get_tz_info_wrap(), tmp_str, @@ -1426,7 +1454,7 @@ int ObCreateTableResolver::resolve_table_elements(const ParseNode *node, has_visible_col = true; } // column from resolved_cols may be invalid - if (OB_FAIL(add_generated_hidden_column_for_udt(table_schema, resolved_cols, column))) { + if (OB_FAIL(add_udt_hidden_column(table_schema, resolved_cols, column))) { LOG_WARN("generate hidden column for udt failed"); } } @@ -1856,20 +1884,6 @@ int ObCreateTableResolver::resolve_table_elements_from_select(const ParseNode &p //can not create a column which meta type is tinyint in oracle mode ret = OB_ERR_INVALID_DATATYPE; LOG_USER_ERROR(OB_ERR_INVALID_DATATYPE); - } else if (lib::is_oracle_mode() && expr->get_result_type().is_user_defined_sql_type()) { - if (expr->get_result_type().get_subschema_id() == ObXMLSqlType) { - ObObjMeta xml_meta; - xml_meta.set_type(ObUserDefinedSQLType); - xml_meta.set_collation_type(CS_TYPE_BINARY); - column.set_meta_type(xml_meta); - column.set_sub_data_type(T_OBJ_XML); - // udt column is varbinary used for null bitmap - column.set_udt_set_id(gen_udt_set_id()); - } else { - ret = OB_ERR_INVALID_DATATYPE; - LOG_WARN("invalid data type", K(ret), K(*expr)); - LOG_USER_ERROR(OB_ERR_INVALID_DATATYPE); - } } else { ObObjMeta column_meta = expr->get_result_type().get_obj_meta(); if (column_meta.is_lob_locator()) { @@ -1886,6 +1900,23 @@ int ObCreateTableResolver::resolve_table_elements_from_select(const ParseNode &p column.set_accuracy(expr->get_accuracy()); column.set_zero_fill(expr->get_result_flag() & ZEROFILL_FLAG); OZ (adjust_number_decimal_column_accuracy_within_max(column, lib::is_oracle_mode())); + if (OB_SUCC(ret) && lib::is_oracle_mode() && expr->get_result_type().is_user_defined_sql_type()) { + // udt column is varbinary used for null bitmap + column.set_collation_type(CS_TYPE_BINARY); + column.set_udt_set_id(gen_udt_set_id()); + if (expr->get_result_type().get_subschema_id() == ObXMLSqlType) { + column.set_sub_data_type(T_OBJ_XML); + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(expr->get_result_type().get_udt_id())) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported udt type for sql udt", + K(ret), K(expr->get_result_type()), K(expr->get_result_type().get_udt_id())); + } else { + column.set_sub_data_type(expr->get_result_type().get_udt_id()); + } + } + if (OB_SUCC(ret) && lib::is_mysql_mode() && ob_is_geometry(expr->get_result_type().get_type())) { + column.set_geo_type(static_cast(expr->get_geo_expr_result_type())); + } OZ (adjust_string_column_length_within_max(column, lib::is_oracle_mode())); LOG_DEBUG("column expr debug", K(*expr)); } @@ -1931,7 +1962,7 @@ int ObCreateTableResolver::resolve_table_elements_from_select(const ParseNode &p org_column->set_sub_data_type(T_OBJ_XML); // udt column is varbinary used for null bitmap org_column->set_udt_set_id(gen_udt_set_id()); - if (OB_FAIL(add_generated_hidden_column_for_udt(table_schema, *org_column))) { + if (OB_FAIL(add_udt_hidden_column(table_schema, *org_column))) { LOG_WARN("add udt hidden column to table_schema failed", K(ret), K(column)); } } @@ -1997,8 +2028,8 @@ int ObCreateTableResolver::resolve_table_elements_from_select(const ParseNode &p //do nothing ... } else if (OB_FAIL(table_schema.add_column(column))) { LOG_WARN("add column to table_schema failed", K(ret), K(column)); - } else if (is_oracle_mode() && column.is_xmltype() && - OB_FAIL(add_generated_hidden_column_for_udt(table_schema, column))) { + } else if (is_oracle_mode() && column.is_extend() && + OB_FAIL(add_udt_hidden_column(table_schema, column))) { LOG_WARN("add udt hidden column to table_schema failed", K(ret), K(column)); } else { ObColumnNameHashWrapper name_key(column.get_column_name_str()); diff --git a/src/sql/resolver/ddl/ob_create_table_resolver.h b/src/sql/resolver/ddl/ob_create_table_resolver.h index 3eae6e1df8..0705a357db 100644 --- a/src/sql/resolver/ddl/ob_create_table_resolver.h +++ b/src/sql/resolver/ddl/ob_create_table_resolver.h @@ -73,11 +73,11 @@ private: int add_hidden_tablet_seq_col(); int add_hidden_external_table_pk_col(); - int add_generated_hidden_column_for_udt(ObTableSchema &table_schema, - ObSEArray &resolved_cols, - ObColumnSchemaV2 &udt_column); - int add_generated_hidden_column_for_udt(ObTableSchema &table_schema, - ObColumnSchemaV2 &udt_column); + int add_udt_hidden_column(ObTableSchema &table_schema, + ObSEArray &resolved_cols, + ObColumnSchemaV2 &udt_column); + int add_udt_hidden_column(ObTableSchema &table_schema, + ObColumnSchemaV2 &udt_column); int check_column_name_duplicate(const ParseNode *node); int resolve_primary_key_node(const ParseNode &pk_node, common::ObArray &stats); int resolve_table_elements(const ParseNode *node, diff --git a/src/sql/resolver/ddl/ob_ddl_resolver.cpp b/src/sql/resolver/ddl/ob_ddl_resolver.cpp index 04c5e390fe..766d787593 100644 --- a/src/sql/resolver/ddl/ob_ddl_resolver.cpp +++ b/src/sql/resolver/ddl/ob_ddl_resolver.cpp @@ -5456,6 +5456,7 @@ int ObDDLResolver::init_empty_session(const common::ObTimeZoneInfoWrap &tz_info_ is_oracle_compat_mode ? ObCompatibilityMode::ORACLE_MODE : ObCompatibilityMode::MYSQL_MODE); empty_session.set_sql_mode(sql_mode); empty_session.set_default_database(db_schema->get_database_name_str()); + empty_session.set_database_id(table_schema.get_database_id()); } if (OB_SUCC(ret) && NULL != local_session_var) { if (OB_FAIL(local_session_var->update_session_vars_with_local(empty_session))) { @@ -5668,6 +5669,15 @@ int ObDDLResolver::check_default_value(ObObj &default_value, } else if (OB_FAIL(ObSQLUtils::calc_simple_expr_without_row( params.session_info_, expr, tmp_default_value, params.param_list_, allocator))) { LOG_WARN("Failed to get simple expr value", K(ret)); + } else if (column.is_xmltype()) { + if (expr->get_result_type().is_string_type()) { + data_type = expr->get_result_type().get_type(); + collation_type = CS_TYPE_UTF8MB4_BIN; + } else { + data_type = ObUserDefinedSQLType; + tmp_dest_obj.set_type(data_type); + tmp_dest_obj.set_subschema_id(ObXMLSqlType); + } } else if (lib::is_oracle_mode() && column.is_xmltype() && expr->get_result_type().is_xml_sql_type()) { data_type = ObUserDefinedSQLType; @@ -5725,7 +5735,7 @@ int ObDDLResolver::check_default_value(ObObj &default_value, ObColumnSchemaV2 &column, ObIArray &gen_col_expr_arr, const ObSQLMode sql_mode, - ObSQLSessionInfo *session_info, + ObSQLSessionInfo *session_info, bool allow_sequence, ObSchemaChecker *schema_checker, bool coltype_not_defined) @@ -5741,6 +5751,7 @@ int ObDDLResolver::check_default_value(ObObj &default_value, return ret; } +// called on rs, will not used to calc udt defaults int ObDDLResolver::calc_default_value(share::schema::ObColumnSchemaV2 &column, common::ObObj &default_value, const common::ObTimeZoneInfoWrap &tz_info_wrap, @@ -5868,6 +5879,24 @@ int ObDDLResolver::calc_default_value(share::schema::ObColumnSchemaV2 &column, } +// check default value for udt, do not call this function on rs +int ObDDLResolver::check_udt_default_value(ObObj &default_value, + const common::ObTimeZoneInfoWrap &tz_info_wrap, + const common::ObString *nls_formats, + ObIAllocator &allocator, + ObTableSchema &table_schema, + ObColumnSchemaV2 &column, + const ObSQLMode sql_mode, + ObSQLSessionInfo *session_info, + ObSchemaChecker *schema_checker, + ObDDLArg &ddl_arg) +{ + ObObj extend_result; + return get_udt_column_default_values(default_value, tz_info_wrap, allocator, + column, sql_mode, session_info, schema_checker, + extend_result, ddl_arg); +} + int ObDDLResolver::ob_udt_check_and_add_ddl_dependency(const uint64_t schema_id, const ObSchemaType schema_type, const int64_t schema_version, @@ -6000,7 +6029,6 @@ int ObDDLResolver::add_udt_default_dependency(ObRawExpr *expr, // check & calc udt default_value, do not call this function on RS int ObDDLResolver::get_udt_column_default_values(const ObObj &default_value, const common::ObTimeZoneInfoWrap &tz_info_wrap, - const common::ObString *nls_formats, ObIAllocator &allocator, ObColumnSchemaV2 &column, const ObSQLMode sql_mode, @@ -6014,10 +6042,10 @@ int ObDDLResolver::get_udt_column_default_values(const ObObj &default_value, if (OB_ISNULL(session_info)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is null", K(ret)); - } else if (!(column.is_extend())) { + } else if (!(column.is_extend()) && !(lib::is_oracle_mode() && column.is_geometry())) { // do nothing } else if (column.is_identity_column() || column.is_generated_column()) { - ret = OB_ERR_UNEXPECTED; + ret = OB_ERR_INVALID_VIRTUAL_COLUMN_TYPE; LOG_WARN("udt columns cannot be generated column or identity column", K(ret), K(column), K(default_value)); } else if (default_value.is_null()) { @@ -6082,7 +6110,9 @@ int ObDDLResolver::get_udt_column_default_values(const ObObj &default_value, } else if (column.is_xmltype() && (ob_is_numeric_type(tmp_default_value.get_type()) || is_lob(tmp_default_value.get_type()))) { ret = OB_ERR_INVALID_XML_DATATYPE; LOG_WARN("incorrect cmp type with xml arguments",K(tmp_default_value.get_type()), K(ret)); - } else if (lib::is_oracle_mode() && column.get_meta_type().is_blob() && ob_is_numeric_type(tmp_default_value.get_type())) { + } else if (lib::is_oracle_mode() + && ((column.get_meta_type().is_blob() && ob_is_numeric_type(tmp_default_value.get_type())) + || (column.get_meta_type().is_geometry() && !ob_is_extend(tmp_default_value.get_type()) && !expr->get_result_type().is_null()))) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("inconsistent datatypes", "expected", data_type, "got", tmp_default_value.get_type(), K(ret)); } else if(OB_FAIL(ObObjCaster::to_type(data_type, cast_ctx, tmp_default_value, tmp_dest_obj, tmp_res_obj))) { @@ -6108,6 +6138,9 @@ int ObDDLResolver::get_udt_column_default_values(const ObObj &default_value, } LOG_DEBUG("finish check udt default value", K(input_default_value), K(expr_str), K(tmp_default_value), K(tmp_dest_obj), K(tmp_dest_obj_null), KPC(expr), K(ret)); + if (OB_SUCC(ret) && tmp_default_value.is_pl_extend()) { + OZ (pl::ObUserDefinedType::destruct_obj(tmp_default_value, session_info)); + } } return ret; } @@ -6323,8 +6356,6 @@ int ObDDLResolver::resolve_spatial_index_constraint( LOG_WARN("unexpected null", K(ret), K(session_info_), K(allocator_)); } else if (OB_FAIL(table_schema.check_if_oracle_compat_mode(is_oracle_mode))) { LOG_WARN("check oracle compat mode failed", K(ret)); - } else if (is_oracle_mode) { - // oracle mode not support geometry } else if (is_func_index && is_mysql_mode()) { ObRawExprFactory expr_factory(*allocator_); ObRawExpr *expr = NULL; @@ -6350,17 +6381,27 @@ int ObDDLResolver::resolve_spatial_index_constraint( } else { //do nothing, check result type of expr on rootserver later } - } else if (OB_ISNULL(column_schema = table_schema.get_column_schema(column_name))) { - if (index_keyname_value != static_cast(INDEX_KEYNAME::SPATIAL_KEY)) { - // do nothing - } else { - ret = OB_ERR_KEY_COLUMN_DOES_NOT_EXITS; - LOG_USER_ERROR(OB_ERR_KEY_COLUMN_DOES_NOT_EXITS, column_name.length(), column_name.ptr()); + } else { + column_schema = table_schema.get_column_schema(column_name); + if (is_oracle_mode) { + if (OB_NOT_NULL(column_schema) && ob_is_geometry_tc(column_schema->get_data_type())) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("oracle spatial index not supported", K(ret)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "oracle spatial index"); + } else { + // do nothing + } + } else if (OB_ISNULL(column_schema)) { + if (index_keyname_value != static_cast(INDEX_KEYNAME::SPATIAL_KEY)) { + // do nothing + } else { + ret = OB_ERR_KEY_COLUMN_DOES_NOT_EXITS; + LOG_USER_ERROR(OB_ERR_KEY_COLUMN_DOES_NOT_EXITS, column_name.length(), column_name.ptr()); + } + } else if (OB_FAIL(resolve_spatial_index_constraint(*column_schema, column_num, + index_keyname_value, is_oracle_mode, is_explicit_order))) { + LOG_WARN("resolve spatial index constraint fail", K(ret), K(column_num), K(index_keyname_value)); } - - } else if (OB_FAIL(resolve_spatial_index_constraint(*column_schema, column_num, - index_keyname_value, is_oracle_mode, is_explicit_order))) { - LOG_WARN("resolve spatial index constraint fail", K(ret), K(column_num), K(index_keyname_value)); } return ret; @@ -6397,7 +6438,13 @@ int ObDDLResolver::resolve_spatial_index_constraint( uint64_t tenant_data_version = 0; if (is_oracle_mode) { - // oracle mode not support geometry + if (is_geo_column) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("oracle spatial index not supported", K(ret), K(is_geo_column), K(is_spatial_index)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "oracle spatial index"); + } else { + // do nothing + } } else if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, tenant_data_version))) { LOG_WARN("get tenant data version failed", K(ret)); } else if ((is_geo_column || is_spatial_index) && tenant_data_version < DATA_VERSION_4_1_0_0) { diff --git a/src/sql/resolver/ddl/ob_ddl_resolver.h b/src/sql/resolver/ddl/ob_ddl_resolver.h index de6fa98f00..001a12cb21 100644 --- a/src/sql/resolver/ddl/ob_ddl_resolver.h +++ b/src/sql/resolver/ddl/ob_ddl_resolver.h @@ -289,9 +289,18 @@ public: const common::ObTimeZoneInfoWrap &tz_info_wrap, const common::ObString *nls_formats, common::ObIAllocator &allocator); + static int check_udt_default_value(ObObj &default_value, + const common::ObTimeZoneInfoWrap &tz_info_wrap, + const common::ObString *nls_formats, + ObIAllocator &allocator, + ObTableSchema &table_schema, + ObColumnSchemaV2 &column, + const ObSQLMode sql_mode, + ObSQLSessionInfo *session_info, + ObSchemaChecker *schema_checker, + obrpc::ObDDLArg &ddl_arg); static int get_udt_column_default_values(const ObObj &default_value, const common::ObTimeZoneInfoWrap &tz_info_wrap, - const common::ObString *nls_formats, ObIAllocator &allocator, ObColumnSchemaV2 &column, const ObSQLMode sql_mode, diff --git a/src/sql/resolver/dml/ob_del_upd_resolver.cpp b/src/sql/resolver/dml/ob_del_upd_resolver.cpp index a31e00fad1..6a70619871 100644 --- a/src/sql/resolver/dml/ob_del_upd_resolver.cpp +++ b/src/sql/resolver/dml/ob_del_upd_resolver.cpp @@ -1531,8 +1531,8 @@ int ObDelUpdResolver::resolve_returning(const ParseNode *parse_tree) } } if (OB_SUCC(ret) - && (ob_is_user_defined_sql_type(expr->get_data_type()) - || ob_is_xml_pl_type(expr->get_data_type(), expr->get_udt_id()))) { + && (ob_is_xml_pl_type(expr->get_data_type(), expr->get_udt_id()) || + ob_is_xml_sql_type(expr->get_result_type().get_type(), expr->get_result_type().get_subschema_id()))) { // ORA-22816 returning clause is currently not object type columns // but this is success in ORA: execute immediate 'insert into t1 values(4,5) returning udt1(c1, c2) into :a' using out a; // xmltype is not allowed: execute immediate 'insert into t2 values(:b) returning xmltype(c1) into :a' using b, out a; @@ -2681,7 +2681,7 @@ int ObDelUpdResolver::generate_column_conv_function(ObInsertTableInfo &table_inf } else if (OB_FAIL(find_value_desc(table_info, column_id, column_ref))) { LOG_WARN("fail to check column is exists", K(ret), K(column_id)); } else if ((!session_info_->get_ddl_info().is_ddl() || OB_ISNULL(column_ref)) && - ( tbl_col->is_xml_column() || (tbl_col->is_udt_hidden_column()))) { + (tbl_col->is_xml_column() || (tbl_col->is_udt_hidden_column()))) { if (!tbl_col->is_xml_column()) { // do nothing, hidden column with build with xml column together } else if (OB_FAIL(build_column_conv_function_for_udt_column(table_info, i, column_ref))) { diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index 61a40dca22..bef680be55 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -59,6 +59,7 @@ #include "share/ob_lob_access_utils.h" #include "share/resource_manager/ob_resource_manager.h" #include "share/stat/ob_opt_ds_stat.h" +#include "lib/udt/ob_udt_type.h" #include "sql/resolver/dml/ob_insert_resolver.h" namespace oceanbase @@ -219,6 +220,7 @@ int ObDMLResolver::check_is_json_constraint(common::ObIAllocator &allocator, bool exist_fun = false; bool check_res = true; bool check_valid = false; + ObColumnRefRawExpr *col_expr = NULL; // unused if (OB_ISNULL(col_node)) { // do nothing } else if (OB_ISNULL(tmp_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { @@ -275,7 +277,7 @@ int ObDMLResolver::check_is_json_constraint(common::ObIAllocator &allocator, } } - if (OB_SUCC(ret) && check_valid && OB_FAIL(ObDMLResolver::check_column_json_type(tmp_node, is_json_cst, is_json_type, only_is_json))) { + if (OB_SUCC(ret) && check_valid && OB_FAIL(ObDMLResolver::check_column_json_type(tmp_node, is_json_cst, is_json_type, col_expr, only_is_json))) { LOG_WARN("fail to check is_json", K(ret)); } return ret; @@ -537,6 +539,7 @@ int ObDMLResolver::transform_dot_notation2_json_value(ParseNode &node, const ObS ParseNode *match_node = NULL; // mismatch node ParseNode *match_node_l = NULL; ParseNode *match_node_r = NULL; + ObColumnRefRawExpr *col_expr = NULL; // unused bool is_json_cst = false; bool is_json_type = false; @@ -573,7 +576,7 @@ int ObDMLResolver::transform_dot_notation2_json_value(ParseNode &node, const ObS param_vec[0] = tmp_node; } if (OB_FAIL(ret)) { - } else if (OB_FAIL(check_column_json_type(tmp_node, is_json_cst, is_json_type))) { + } else if (OB_FAIL(check_column_json_type(tmp_node, is_json_cst, is_json_type, col_expr))) { LOG_WARN("check column type failed", K(ret)); } else if (!(is_json_cst || is_json_type)) { ret = OB_WRONG_COLUMN_NAME; @@ -735,6 +738,175 @@ int ObDMLResolver::transform_dot_notation2_json_value(ParseNode &node, const ObS return ret; } +int ObDMLResolver::transform_udt_attrbute_name(const ObString &sql_str, ObIAllocator &allocator, ObString &attr_name) +{ + INIT_SUCC(ret); + const ObString::obstr_size_t len = sql_str.length(); + char *ptr = NULL; + if (OB_ISNULL(sql_str.ptr()) || OB_UNLIKELY(0 >= len)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sql string should not be null", K(ret)); + } else if (NULL == (ptr = static_cast(allocator.alloc(len)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret), K(len)); + } else { + const char *start = sql_str.ptr(); + const char *end = sql_str.ptr() + sql_str.length(); + int64_t pos = 0; + for (; start < end; start++) { + if ((*start) != '"') { + ptr[pos++] = *start; + } + } + attr_name.assign_ptr(ptr, pos > 0 ? pos - 1 : pos); + } + return ret; +} + +int ObDMLResolver::create_char_node(const ObString &value, ParseNode *&new_node) +{ + INIT_SUCC(ret); + ParseNode* value_node = NULL; + if (OB_ISNULL(value_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + value_node = new(value_node) ParseNode; + memset(value_node, 0, sizeof(ParseNode)); + if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(*allocator_, value, value_node, T_CHAR))) { + LOG_WARN("create path node failed", K(ret)); + } else { + new_node = value_node; + } + } + return ret; +} + +int ObDMLResolver::create_col_ref_node(ParseNode *table_node, const ObString &column_name, ParseNode *&new_node) +{ + INIT_SUCC(ret); + ParseNode* column_node = NULL; + if (OB_ISNULL(column_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + column_node = new(column_node) ParseNode; + if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(*allocator_, column_name, column_node, T_COLUMN_REF))) { + LOG_WARN("create json doc node fail", K(ret)); + } else { + column_node->children_[1] = table_node; + new_node = column_node; + } + } + return ret; +} + +int ObDMLResolver::create_int_val_node(ParseNode *table_node, const uint64_t value, ParseNode *&new_node) +{ + INIT_SUCC(ret); + ParseNode* value_node = NULL; + if (OB_ISNULL(value_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + value_node = new(value_node) ParseNode; + memset(value_node, 0, sizeof(ParseNode)); + if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(*allocator_, "", value_node, T_INT))) { + LOG_WARN("create path node failed", K(ret)); + } else { + value_node->value_ = value; + new_node = value_node; + } + } + return ret; +} + +int ObDMLResolver::transform_geo_dot_notation_attr(ParseNode &node, const ObString &sql_str, const ObColumnRefRawExpr &col_expr) +{ + INIT_SUCC(ret); + ObArenaAllocator tmp_allocator; + ObString raw_text; + ObString attr_name; + uint64_t udt_id = T_OBJ_SDO_GEOMETRY; + int64_t schema_version = OB_INVALID_VERSION; + uint64_t tenant_id = pl::get_tenant_id_by_object_id(udt_id); + ObArray udt_qualified_name; + ObString qualified_name; + ParseNode *table_node = NULL; + char *tmp = static_cast(tmp_allocator.alloc(OB_MAX_QUALIFIED_COLUMN_NAME_LENGTH)); + if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_4_2_2_0 + || (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_4_3_0_0 && GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_4_3_1_0)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("sdo_geometry attribute access is not supported when cluster_version is below 4.2.2.0 or cluster_version is above 4.3.0.0 but below 4.3.1.0", K(ret)); + } else if (OB_ISNULL(tmp)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to alloc qualified name buffer", K(ret)); + } else if (FALSE_IT(qualified_name.assign_buffer(tmp, OB_MAX_QUALIFIED_COLUMN_NAME_LENGTH))) { + } else if (qualified_name.write(col_expr.get_column_name().ptr(), + col_expr.get_column_name().length()) == 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("write qualified column name failed", K(ret), K(col_expr.get_column_name())); + } else if (OB_FAIL(schema_checker_->flatten_udt_attributes(tenant_id, udt_id, tmp_allocator, + qualified_name, schema_version, udt_qualified_name))) { + LOG_WARN("failed to flatten udt attributes", K(ret)); + } else if (OB_FAIL(transform_udt_attrbute_name(sql_str, tmp_allocator, attr_name))) { + LOG_WARN("failed to transform udt attributes name", K(ret)); + } else if (FALSE_IT(raw_text = attr_name.after('.'))) { + } else if (OB_ISNULL(table_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + table_node = new(table_node) ParseNode; + memset(table_node, 0, sizeof(ParseNode)); + table_node->type_ = T_VARCHAR; + table_node->str_value_ = node.children_[0]->str_value_; + table_node->raw_text_ = node.children_[0]->raw_text_; + table_node->str_len_ = node.children_[0]->str_len_; + table_node->text_len_ = node.children_[0]->text_len_; + + bool is_basic_attr = false; + ParseNode **param_vec = NULL; + uint32_t param_count = 4; + int64_t attr_idx = 0; + uint64_t sub_udt_id = OB_INVALID_ID; + for (; attr_idx + 2 < udt_qualified_name.count() && !is_basic_attr; attr_idx++) { + if (udt_qualified_name.at(attr_idx).case_compare(raw_text) == 0) { + is_basic_attr = true; + } + } + if (!is_basic_attr) { + ObString sub_name = raw_text.after(raw_text.reverse_find('.')); + uint64_t attr_pos = 0; + if (OB_FAIL(schema_checker_->get_udt_attribute_id(udt_id, sub_name, sub_udt_id, attr_pos))) { + LOG_WARN("fail to get tenant udt id", K(ret)); + } else if (sub_udt_id == OB_INVALID_ID || sub_udt_id <= ObMaxType) { + ret = OB_ERR_BAD_FIELD_ERROR; + LOG_WARN("type_node or stmt_ or datatype is invalid", K(ret), K(sub_name), K(sub_udt_id)); + } + } + + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(param_vec = static_cast(allocator_->alloc(param_count * sizeof(ParseNode *))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else if (OB_FAIL(create_col_ref_node(table_node, col_expr.get_column_name(), param_vec[0]))) { + LOG_WARN("fail to create column parse node", K(ret)); + } else if (OB_FAIL(create_int_val_node(table_node, udt_id, param_vec[1]))) { + LOG_WARN("fail to create value node", K(ret), K(udt_id), K(sub_udt_id)); + } else if (OB_FAIL(create_int_val_node(table_node, is_basic_attr ? attr_idx : sub_udt_id, param_vec[2]))) { + LOG_WARN("fail to create value node", K(ret), K(udt_id), K(sub_udt_id)); + } else if (OB_FAIL(create_int_val_node(table_node, schema_version, param_vec[3]))) { + LOG_WARN("fail to create value node", K(ret), K(udt_id), K(sub_udt_id)); + } else { + node.num_child_ = param_count; + node.type_ = is_basic_attr ? T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS : T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT; + node.children_ = param_vec; + } + } + + return ret; +} + /* JSON_QUERY '(' js_doc_expr ',' js_literal opt_js_query_returning_type opt_scalars opt_pretty opt_ascii opt_wrapper opt_query_on_error_or_empty_or_mismatch ')' */ @@ -749,6 +921,7 @@ int ObDMLResolver::transform_dot_notation2_json_query(ParseNode &node, const ObS ParseNode *path_node = NULL; // path node ParseNode *table_node = NULL; // table node ParseNode *tmp_node = NULL; // json doc node + ObColumnRefRawExpr *col_expr = NULL; bool is_json_cst = false; bool is_json_type = false; @@ -788,95 +961,99 @@ int ObDMLResolver::transform_dot_notation2_json_query(ParseNode &node, const ObS param_vec[0] = tmp_node; } if (OB_FAIL(ret)) { - } else if (OB_FAIL(check_column_json_type(tmp_node, is_json_cst, is_json_type))) { + } else if (OB_FAIL(check_column_json_type(tmp_node, is_json_cst, is_json_type, col_expr))) { LOG_WARN("check column type failed", K(ret)); + } else if (OB_NOT_NULL(col_expr) && ob_is_geometry(col_expr->get_result_type().get_type())) { + if (OB_FAIL(transform_geo_dot_notation_attr(node, sql_str, *col_expr))) { + LOG_WARN("transform dot notation udt attribute failed", K(ret)); + } } else if (!(is_json_cst || is_json_type)) { ret = OB_WRONG_COLUMN_NAME; LOG_USER_ERROR(OB_WRONG_COLUMN_NAME, static_cast(sql_str.length() - 1), sql_str.ptr()); LOG_WARN("column type not json", K(ret)); - } - // create path node - if (OB_FAIL(ret)) { - } else if (OB_ISNULL(node.children_[1]->children_[1])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("node transform fail"); - // do nothing - } else if (OB_ISNULL(path_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); } else { - path_node = new(path_node) ParseNode; - ParseNode *tmp_path = node.children_[1]->children_[1]; - ObJsonBuffer res_str(allocator_); - if (OB_FAIL(res_str.append("$"))) { - LOG_WARN("path symbol write fail", K(ret)); - } else { - while (OB_SUCC(ret) && OB_NOT_NULL(tmp_path)) { - if (OB_ISNULL(tmp_path->children_[0])) { - tmp_path = NULL; - // do nothing - } else { - if (OB_FAIL(print_json_path(tmp_path, res_str))) { - LOG_WARN("generate path fail", K(ret)); - } - } - } - if (OB_FAIL(ret)) { - } else if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(*allocator_, res_str.string(), path_node, T_CHAR))) { - LOG_WARN("create path node failed", K(ret)); - } else { - param_vec[1] = path_node; - } - } - } - // create return node - if (OB_FAIL(ret)) { - } else if (OB_ISNULL(ret_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); - } else { - ret_node = new(ret_node) ParseNode; - memset(ret_node, 0, sizeof(ParseNode)); - ret_node->type_ = T_NULL; - ret_node->is_hidden_const_ = 1; - param_vec[2] = ret_node; // return type pos is 2 in json value clause - } - // opt_scalars opt_pretty opt_ascii opt_wrapper opt_query_on_error_or_empty_or_mismatch 7 - for (int8_t i = 3; OB_SUCC(ret) && i < 11; i++) { - opt_node = NULL; - if (OB_ISNULL(opt_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { + // create path node + if (OB_ISNULL(node.children_[1]->children_[1])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node transform fail"); + // do nothing + } else if (OB_ISNULL(path_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); } else { - opt_node = new(opt_node) ParseNode; - memset(opt_node, 0, sizeof(ParseNode)); - if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(*allocator_, "", opt_node, T_INT))) { - LOG_WARN("create path node failed", K(ret)); + path_node = new(path_node) ParseNode; + ParseNode *tmp_path = node.children_[1]->children_[1]; + ObJsonBuffer res_str(allocator_); + if (OB_FAIL(res_str.append("$"))) { + LOG_WARN("path symbol write fail", K(ret)); } else { - int8_t val = 0; - if (i == 3) { - val = 0; - } else if (i == 4) { - val = 2; - } else if (i == 8) { - val = 1; - } else if (i == 9 || i == 7) { - val = 5; - } else if (i == 10) { - val = 3; // mismatch default is 3 from dot notation + while (OB_SUCC(ret) && OB_NOT_NULL(tmp_path)) { + if (OB_ISNULL(tmp_path->children_[0])) { + tmp_path = NULL; + // do nothing + } else { + if (OB_FAIL(print_json_path(tmp_path, res_str))) { + LOG_WARN("generate path fail", K(ret)); + } + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(*allocator_, res_str.string(), path_node, T_CHAR))) { + LOG_WARN("create path node failed", K(ret)); + } else { + param_vec[1] = path_node; } - opt_node->value_ = val; - opt_node->int32_values_[0] = val; - opt_node->int16_values_[0] = val; - param_vec[i] = opt_node; } } - } - // create json query node - if (OB_SUCC(ret)) { - node.num_child_ = 11; - node.type_ = T_FUN_SYS_JSON_QUERY; - node.children_ = param_vec; + // create return node + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(ret_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + ret_node = new(ret_node) ParseNode; + memset(ret_node, 0, sizeof(ParseNode)); + ret_node->type_ = T_NULL; + ret_node->is_hidden_const_ = 1; + param_vec[2] = ret_node; // return type pos is 2 in json value clause + } + // opt_scalars opt_pretty opt_ascii opt_wrapper opt_query_on_error_or_empty_or_mismatch 7 + for (int8_t i = 3; OB_SUCC(ret) && i < 11; i++) { + opt_node = NULL; + if (OB_ISNULL(opt_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + opt_node = new(opt_node) ParseNode; + memset(opt_node, 0, sizeof(ParseNode)); + if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(*allocator_, "", opt_node, T_INT))) { + LOG_WARN("create path node failed", K(ret)); + } else { + int8_t val = 0; + if (i == 3) { + val = 0; + } else if (i == 4) { + val = 2; + } else if (i == 8) { + val = 1; + } else if (i == 9 || i == 7) { + val = 5; + } else if (i == 10) { + val = 3; // mismatch default is 3 from dot notation + } + opt_node->value_ = val; + opt_node->int32_values_[0] = val; + opt_node->int16_values_[0] = val; + param_vec[i] = opt_node; + } + } + } + // create json query node + if (OB_SUCC(ret)) { + node.num_child_ = 11; + node.type_ = T_FUN_SYS_JSON_QUERY; + node.children_ = param_vec; + } } return ret; } @@ -937,7 +1114,7 @@ int ObDMLResolver::check_depth_obj_access_ref(ParseNode *node, int8_t &depth, bo cur_node = NULL; } } else if (cur_node->children_[0]->type_ == T_FUN_SYS) { - if (obj_check && ((depth == 3 && is_exist_array == true) || depth < 2)) { + if (obj_check && (depth == 3 && is_exist_array == true)) { ret = OB_ERR_NOT_OBJ_REF; LOG_WARN("not an object or REF", K(ret)); } else { @@ -1023,7 +1200,7 @@ int ObDMLResolver::check_size_obj_access_ref(ParseNode *node) // only_is_json == 1: when has is json constraint or json type, return true; // only_is_json == 0: when has is json constraint, return true // only_is_json == 2: when is json type, return true -int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_cst, bool &is_json_type, int8_t only_is_json) +int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_cst, bool &is_json_type, ObColumnRefRawExpr *&column_expr, int8_t only_is_json) { INIT_SUCC(ret); ObSEArray columns_list; @@ -1062,6 +1239,7 @@ int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_cst, if (OB_ISNULL(table_item)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get invalid table name", K(ret), K(tab_str)); + } else if (FALSE_IT(column_expr = the_col_item.get_expr())) { } else if (table_item->is_json_table() || table_item->is_temp_table() || table_item->is_generated_table() || table_item->is_function_table()) { if (only_is_json > 0) { @@ -1136,6 +1314,90 @@ int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_cst, return ret; } +int ObDMLResolver::pre_process_mvt_agg(ParseNode &node) +{ + INIT_SUCC(ret); + if (node.type_ == T_FUN_SYS_ST_ASMVT) { + int ori_param_num = node.num_child_; + if (ori_param_num < 1) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param number", K(ret), K(ori_param_num)); + } else if (node.reserved_) { + // already processed, do nothing + } else if (OB_ISNULL(node.children_[0])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr param is null", K(ret)); + } else if (node.children_[0]->type_ != T_COLUMN_REF) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid node type", K(ret), K(node.children_[0]->type_)); + } else if (OB_ISNULL(node.children_[0]->children_[2])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr param is null", K(ret)); + } else if (node.children_[0]->children_[2]->type_ != T_STAR) { + ret = OB_ERR_PARSER_SYNTAX; + LOG_WARN("parameter row cannot be other than a rowtype", K(ret)); + } else { + ObQualifiedName column_ref; + ObNameCaseMode case_mode = OB_NAME_CASE_INVALID; + TableItem *table_item = NULL; + bool tab_has_alias = false; + ObSEArray columns_list; + if (OB_FAIL(session_info_->get_name_case_mode(case_mode))) { + LOG_WARN("fail to get name case mode", K(ret)); + } else if (OB_FAIL(ObResolverUtils::resolve_column_ref(node.children_[0], case_mode, column_ref))) { + LOG_WARN("fail to resolve table name", K(ret)); + } else if (OB_FAIL(get_target_column_list(columns_list, column_ref.tbl_name_, false, tab_has_alias, table_item))) { + LOG_WARN("parse column fail", K(ret)); + } else if (columns_list.count() < 1) { + // do nothing, as_mvt might be in sub_stmt + } else { + ParseNode **param_vec = NULL; + uint32_t para_idx = 0; + // *(row) + other params = column_ref + column_name + other params + other params cnt + uint32_t param_count = columns_list.count() * 2 + ori_param_num; + ParseNode* param_cnt_node = NULL; + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(param_vec = static_cast(allocator_->alloc(param_count * sizeof(ParseNode *))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(columns_list.count())); + } else if (OB_FAIL(create_int_val_node(NULL, ori_param_num - 1, param_cnt_node))) { + LOG_WARN("fail to create int val node", K(ret)); + } else { + param_vec[para_idx++] = param_cnt_node; + for (int i = 1; i < ori_param_num; i++) { + param_vec[para_idx++] = node.children_[i]; + } + } + + for (int i = 0; i < columns_list.count() && OB_SUCC(ret); i++) { + ParseNode* column_node = NULL; + ParseNode* column_name = NULL; + if (OB_FAIL(create_col_ref_node(node.children_[0]->children_[1], columns_list.at(i).column_name_, column_node))) { + LOG_WARN("fail to create column parse node", K(ret)); + } else if (OB_FAIL(create_char_node(columns_list.at(i).column_name_, column_name))) { + LOG_WARN("fail to create column name parse node", K(ret)); + } else { + param_vec[para_idx++] = column_node; + param_vec[para_idx++] = column_name; + } + } + if (OB_SUCC(ret)) { + node.num_child_ = param_count; + node.children_ = param_vec; + node.reserved_ = 1; + } + } + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < node.num_child_; i++) { + if (OB_ISNULL(node.children_[i])) { + } else if (OB_FAIL(SMART_CALL(pre_process_mvt_agg(*node.children_[i])))) { + LOG_WARN("pre process dot notation failed", K(ret), K(i)); + } + } + return ret; +} + // pre check whether dot notation int ObDMLResolver::pre_check_dot_notation(ParseNode &node, int8_t& depth, bool& exist_fun, ObJsonBuffer& sql_str, bool &is_scalar) { @@ -1182,7 +1444,7 @@ int ObDMLResolver::pre_process_json_expr(ParseNode &node) } else if (OB_FAIL(pre_process_json_expr_constraint(&node, *allocator_))) { // check json expr with is json constraint LOG_WARN("fail to process json exor with json constraint", K(ret)); } - for (int64_t i = 0; OB_SUCC(ret) && i < node.num_child_; i++) { + for (int64_t i = 0; OB_SUCC(ret) && i < node.num_child_ && node.type_ != T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT; i++) { if (OB_ISNULL(node.children_[i])) { } else if (OB_FAIL(SMART_CALL(pre_process_json_expr(*node.children_[i])))) { LOG_WARN("pre process dot notation failed", K(ret), K(i)); @@ -1261,7 +1523,6 @@ int ObDMLResolver::check_column_scalar_type(ParseNode *root_node, bool &is_scala bool tab_has_alias = false; ObString tab_str; ObString col_str; - if (OB_ISNULL(root_node) || root_node->type_ != T_OBJ_ACCESS_REF || root_node->num_child_ != 2 @@ -1298,7 +1559,9 @@ int ObDMLResolver::check_column_scalar_type(ParseNode *root_node, bool &is_scala if (OB_ISNULL(col_expr)) { ret = OB_ERR_BAD_FIELD_ERROR; LOG_WARN("get invalid identifier name", K(ret), K(tab_str), K(col_str), K(tab_has_alias)); - } else if (!col_expr->get_result_type().is_user_defined_sql_type() && !col_expr->get_result_type().is_ext()) { + } else if (!col_expr->get_result_type().is_user_defined_sql_type() + && !col_expr->get_result_type().is_ext() + && !col_expr->get_result_type().is_geometry()) { if (!(col_expr->get_result_type().is_json() || col_expr->get_result_type().is_clob() || col_expr->get_result_type().is_blob())) { @@ -1311,7 +1574,6 @@ int ObDMLResolver::check_column_scalar_type(ParseNode *root_node, bool &is_scala } } } - return ret; } @@ -1442,6 +1704,9 @@ int ObDMLResolver::resolve_sql_expr(const ParseNode &node, ObRawExpr *&expr, if (OB_SUCC(ret) && lib::is_oracle_mode() && OB_FAIL(pre_process_json_expr(const_cast(node)))) { LOG_WARN("deal dot notation fail", K(ret)); } + if (OB_SUCC(ret) && !lib::is_oracle_mode() && OB_FAIL(pre_process_mvt_agg(const_cast(node)))) { + LOG_WARN("deal asmvt fail", K(ret)); + } if (OB_SUCC(ret)) { OC( (expr_resolver.resolve)(&node, expr, @@ -2102,11 +2367,24 @@ int ObDMLResolver::resolve_into_variables(const ParseNode *node, value_expr->get_collation_type(), into_pl_type.get_data_type()->get_obj_type(), into_pl_type.get_data_type()->get_collation_type())); - } else if (value_expr->get_data_type() == ObUserDefinedSQLType && into_pl_type.is_opaque_type()) { + } else if ((value_expr->get_data_type() == ObUserDefinedSQLType && into_pl_type.is_opaque_type()) || + (value_expr->get_data_type() == ObGeometryType && into_pl_type.is_record_type())) { // sql udt to pl extend, only support xmltype currently, dest collation type is not used OX (is_compatible = cast_supported(value_expr->get_data_type(), value_expr->get_collation_type(), ObExtendType, CS_TYPE_BINARY)); + } else if (value_expr->get_data_type() == ObUserDefinedSQLType) { + // sql udt to pl extend + uint16_t subschema_id = value_expr->get_subschema_id(); + ObSqlUDTMeta udt_meta; + if (OB_FAIL(session_info_->get_cur_exec_ctx()->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_meta.udt_id_)) { + LOG_WARN("udt not supported", K(ret), K(subschema_id)); + } + OX (is_compatible = cast_supported(value_expr->get_data_type(), + value_expr->get_collation_type(), + ObExtendType, CS_TYPE_BINARY)); } else if (value_expr->get_data_type() == ObExtendType && (!into_pl_type.is_obj_type() || (into_pl_type.get_data_type() != NULL && into_pl_type.get_data_type()->get_meta_type().is_ext()))) { @@ -2238,11 +2516,27 @@ int ObDMLResolver::resolve_into_variables(const ParseNode *node, value_expr->get_collation_type(), into_pl_type.get_data_type()->get_obj_type(), into_pl_type.get_data_type()->get_collation_type())); - } else if (value_expr->get_data_type() == ObUserDefinedSQLType && into_pl_type.is_opaque_type()) { - // sql udt to pl extend, only support xmltype currently, dest collation type is not used + } else if ((value_expr->get_data_type() == ObUserDefinedSQLType && into_pl_type.is_opaque_type()) || + (value_expr->get_data_type() == ObGeometryType && into_pl_type.is_record_type())) { + // oracle xml/gis to pl extend, dest collation type is not used OX (is_compatible = cast_supported(value_expr->get_data_type(), value_expr->get_collation_type(), ObExtendType, CS_TYPE_BINARY)); + } else if (value_expr->get_data_type() == ObUserDefinedSQLType) { + // sql udt to pl extend + uint16_t subschema_id = value_expr->get_subschema_id(); + ObSqlUDTMeta udt_meta; + if (OB_FAIL(session_info_->get_cur_exec_ctx()->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(subschema_id)); + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_meta.udt_id_)) { + LOG_WARN("udt not supported", K(ret), K(subschema_id)); + } else if (into_pl_type.is_udt_type() && into_pl_type.get_user_type_id() != udt_meta.udt_id_) { + is_compatible = false; + } else { + is_compatible = cast_supported(value_expr->get_data_type(), + value_expr->get_collation_type(), + ObExtendType, CS_TYPE_BINARY); + } } else if (value_expr->get_data_type() == ObExtendType && (!into_pl_type.is_obj_type() || (into_pl_type.get_data_type() != NULL && into_pl_type.get_data_type()->get_meta_type().is_ext()))) { @@ -2760,10 +3054,15 @@ int ObDMLResolver::resolve_qualified_identifier(ObQualifiedName &q_name, if (!params_.is_resolve_table_function_expr_) { //such as insert into tbl values(1,3, coll('a', 1)); if ((!stmt_->is_select_stmt() && params_.secondary_namespace_ == NULL && session_info_->get_pl_context() == NULL) - || (current_scope_ != T_FIELD_LIST_SCOPE && current_scope_ != T_INTO_SCOPE)) { - ret = OB_NOT_SUPPORTED; - LOG_WARN("dml with collection or record construction function is not supported", K(ret), K(current_scope_)); - LOG_USER_ERROR(OB_NOT_SUPPORTED, "dml with collection or record construction function is"); + || (current_scope_ != T_FIELD_LIST_SCOPE && current_scope_ != T_INTO_SCOPE)) { + if (ObObjUDTUtil::ob_is_supported_sql_udt(real_ref_expr->get_result_type().get_udt_id())) { + is_external = false; + } else { + // dml with udt supported + ret = OB_NOT_SUPPORTED; + LOG_WARN("dml with collection or record construction function is not supported", K(ret)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "dml with collection or record construction function is"); + } } else { is_external = false; } @@ -2773,9 +3072,13 @@ int ObDMLResolver::resolve_qualified_identifier(ObQualifiedName &q_name, } else if (T_FUN_PL_OBJECT_CONSTRUCT == real_ref_expr->get_expr_type()) { if ((current_scope_ != T_FIELD_LIST_SCOPE && current_scope_ != T_INTO_SCOPE) || (get_basic_stmt()->is_insert_stmt() && current_scope_ == T_INTO_SCOPE)) { - ret = OB_NOT_SUPPORTED; - LOG_WARN("dml with collection or record construction function is not supported", K(ret)); - LOG_USER_ERROR(OB_NOT_SUPPORTED, "dml with collection or record construction function is"); + if (ObObjUDTUtil::ob_is_supported_sql_udt(real_ref_expr->get_result_type().get_udt_id())) { + is_external = false; + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("dml with collection or record construction function is not supported", K(ret)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "dml with collection or record construction function is"); + } } else { is_external = false; } @@ -7606,22 +7909,19 @@ int ObDMLResolver::resolve_generated_column_expr(const ObString &expr_str, this, schema_checker_))) { LOG_WARN("build generated column expr failed", K(ret)); - } else if (!used_for_generated_column && !columns.empty()) { - for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); i++) { - bool is_all_sys_func = columns.at(i).is_sys_func(); - if (!is_all_sys_func) { - ret = OB_ERR_UNEXPECTED; - ret = update_errno_if_sequence_object(columns.at(i), ret); - LOG_WARN("no need referece other column, it should not happened", K(expr_str), K(ret)); - } - } } + bool is_default_udt_constructor = false; + ObArray udf_construct_exprs; for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); ++i) { ColumnItem *col_item = NULL; ObRawExpr *real_ref_expr = NULL; ObArray real_exprs; - if (columns.at(i).is_sys_func()) { + if (!used_for_generated_column && !(columns.at(i).is_sys_func() || columns.at(i).is_pl_udf())) { + ret = OB_ERR_UNEXPECTED; + ret = update_errno_if_sequence_object(columns.at(i), ret); + LOG_WARN("no need referece other column, it should not happened", K(expr_str), K(ret)); + } else if (columns.at(i).is_sys_func()) { if (OB_FAIL(resolve_qualified_identifier(columns.at(i), columns, real_exprs, real_ref_expr))) { LOG_WARN("resolve sysfunc expr failed", K(columns.at(i)), K(ret)); } else if (OB_ISNULL(real_ref_expr)) { @@ -7642,9 +7942,42 @@ int ObDMLResolver::resolve_generated_column_expr(const ObString &expr_str, } else if (OB_ISNULL(real_ref_expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("expr is NULL", K(ret)); - } else if (!real_ref_expr->is_udf_expr()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid exor", K(*real_ref_expr), K(ret)); + } else if (used_for_generated_column) { + if (!real_ref_expr->is_udf_expr()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid exor", K(*real_ref_expr), K(ret)); + } + } else { // !used_for_generated_column + if ((real_ref_expr->get_expr_type() != T_FUN_PL_OBJECT_CONSTRUCT) + && (real_ref_expr->get_expr_type() != T_FUN_PL_COLLECTION_CONSTRUCT)) { + ret = OB_ERR_UNEXPECTED; + ret = update_errno_if_sequence_object(columns.at(i), ret); + LOG_WARN("no need referece other column, it should not happened", K(expr_str), K(ret)); + } else { + is_default_udt_constructor = true; + // column_ref is replaced inside build_generated_column_expr with udf, + // here replace udf with object/collection constructor + if (OB_FAIL(udf_construct_exprs.push_back(real_ref_expr))) { + LOG_WARN("push back error", K(ret)); + } + + for (int64_t i = 0; OB_SUCC(ret) && i < udf_construct_exprs.count(); ++i) { + ObQualifiedName &q_name = columns.at(i); + if (OB_FAIL(ObRawExprUtils::replace_ref_column(real_ref_expr, + q_name.ref_expr_, + udf_construct_exprs.at(i)))) { + LOG_WARN("replace column ref expr failed", K(ret)); + } + } + // replace expr, only outside ref_expr_ is equal to expr + ObQualifiedName &q_name = columns.at(i); + const ObUDFInfo &udf_info = q_name.access_idents_.at(q_name.access_idents_.count() - 1).udf_info_; + if (OB_SUCC(ret) && OB_NOT_NULL(udf_info.ref_expr_)) { + if (OB_FAIL(ObRawExprUtils::replace_ref_column(ref_expr, udf_info.ref_expr_, real_ref_expr))) { + LOG_WARN("replace column ref expr failed", K(ret)); + } + } + } } } else if (table_schema->is_external_table() && ObResolverUtils::is_external_file_column_name(columns.at(i).col_name_)) { @@ -7681,7 +8014,7 @@ int ObDMLResolver::resolve_generated_column_expr(const ObString &expr_str, } } - if (OB_SUCC(ret)) { + if (OB_SUCC(ret) && !is_default_udt_constructor) { if (OB_FAIL(real_exprs.push_back(ref_expr))) { LOG_WARN("push back error", K(ret)); } else if (OB_FAIL(ObRawExprUtils::replace_ref_column(ref_expr, columns.at(i).ref_expr_, real_ref_expr))) { diff --git a/src/sql/resolver/dml/ob_dml_resolver.h b/src/sql/resolver/dml/ob_dml_resolver.h index 5da2807153..e3d094d258 100644 --- a/src/sql/resolver/dml/ob_dml_resolver.h +++ b/src/sql/resolver/dml/ob_dml_resolver.h @@ -220,13 +220,20 @@ public: ColumnItem *&col_item); // dot notation int expand_column_in_json_object_star(ParseNode *node); + int pre_process_mvt_agg(ParseNode &node); + int pre_process_dot_notation(ParseNode &node); int pre_process_json_expr(ParseNode &node); int print_json_path(ParseNode *&tmp_path, ObJsonBuffer &res_str); int check_depth_obj_access_ref(ParseNode *node, int8_t &depth, bool &exist_fun, ObJsonBuffer &sql_str, bool obj_check = true); // obj_check : whether need check dot notaion int check_first_node_name(const ObString &node_name, bool &check_res); int transform_dot_notation2_json_query(ParseNode &node, const ObString &sql_str); int transform_dot_notation2_json_value(ParseNode &node, const ObString &sql_str); - int check_column_json_type(ParseNode *tab_col, bool &is_json_col, bool &is_json_type, int8_t only_is_json = 1); + int transform_geo_dot_notation_attr(ParseNode &node, const ObString &sql_str, const ObColumnRefRawExpr &col_expr); + int transform_udt_attrbute_name(const ObString &sql_str, ObIAllocator &allocator, ObString &attr_name); + int create_col_ref_node(ParseNode *table_node, const ObString &column_name, ParseNode *&new_node); + int create_int_val_node(ParseNode *table_node, const uint64_t value, ParseNode *&new_node); + int create_char_node(const ObString &value, ParseNode *&new_node); + int check_column_json_type(ParseNode *tab_col, bool &is_json_cst, bool &is_json_type, ObColumnRefRawExpr *&column_expr, int8_t only_is_json = 1); int check_size_obj_access_ref(ParseNode *node); /* json object resolve star */ int get_target_column_list(ObSEArray &target_list, ObString &tab_name, bool all_tab, diff --git a/src/sql/resolver/dml/ob_select_resolver.cpp b/src/sql/resolver/dml/ob_select_resolver.cpp index eddd939de2..3858504ca6 100644 --- a/src/sql/resolver/dml/ob_select_resolver.cpp +++ b/src/sql/resolver/dml/ob_select_resolver.cpp @@ -6676,6 +6676,10 @@ int ObSelectResolver::check_rollup_items_valid(const ObIArray &rol if (OB_ISNULL(groupby_expr = groupby_exprs.at(k))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("rollup expr is null", K(ret)); + } else if (lib::is_oracle_mode() && ObGeometryType == groupby_expr->get_data_type()) { + // oracle error code compability + ret = OB_ERR_COMPARE_VARRAY_LOB_ATTR; + LOG_WARN("Incorrect cmp type with geometry arguments", K(ret)); } else if (ObLongTextType == groupby_expr->get_data_type() || ObLobType == groupby_expr->get_data_type() || ObJsonType == groupby_expr->get_data_type() diff --git a/src/sql/resolver/expr/ob_raw_expr.cpp b/src/sql/resolver/expr/ob_raw_expr.cpp index 1da4b14490..5c422ee5bb 100644 --- a/src/sql/resolver/expr/ob_raw_expr.cpp +++ b/src/sql/resolver/expr/ob_raw_expr.cpp @@ -30,6 +30,8 @@ #include "sql/engine/expr/ob_pl_expr_subquery.h" #include "share/config/ob_server_config.h" #include "sql/resolver/expr/ob_raw_expr_copier.h" +#include "sql/engine/expr/ob_expr_sql_udt_construct.h" +#include "sql/engine/expr/ob_expr_priv_attribute_access.h" using namespace oceanbase::sql; using namespace oceanbase::common; @@ -69,6 +71,8 @@ int ObRawExprFactory::create_raw_expr(ObItemType expr_type, ObS GENERATE_CASE(T_FUN_PL_OBJECT_CONSTRUCT, ObObjectConstructRawExpr); GENERATE_CASE(T_FUN_PL_GET_CURSOR_ATTR, ObPLGetCursorAttrRawExpr); GENERATE_CASE(T_FUN_PL_SQLCODE_SQLERRM, ObPLSQLCodeSQLErrmRawExpr); + GENERATE_CASE(T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT, ObUDTConstructorRawExpr); + GENERATE_CASE(T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS, ObUDTAttributeAccessRawExpr); GENERATE_DEFAULT(); } return ret; @@ -635,6 +639,7 @@ ObGeoType ObRawExpr::get_geo_expr_result_type() const return geo_type; } case T_FUN_SYS_POINT: + case T_FUN_SYS_ST_CENTROID: return ObGeoType::POINT; case T_FUN_SYS_LINESTRING: return ObGeoType::LINESTRING; @@ -6555,6 +6560,26 @@ int ObRawExprFactory::create_raw_expr(ObRawExpr::ExprClass expr_class, } else { dest = dest_scse; } + } else if (T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT == expr_type) { + ObUDTConstructorRawExpr *dest_udt_expr = nullptr; + if (OB_FAIL(create_raw_expr(expr_type, dest_udt_expr))) { + LOG_WARN("failed to allocate raw expr", K(dest_udt_expr), K(ret)); + } else if (OB_ISNULL(dest_udt_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr is NULL", K(dest_udt_expr), K(ret)); + } else { + dest = dest_udt_expr; + } + } else if (T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS == expr_type) { + ObUDTAttributeAccessRawExpr *dest_udt_attr_expr = nullptr; + if (OB_FAIL(create_raw_expr(expr_type, dest_udt_attr_expr))) { + LOG_WARN("failed to allocate raw expr", K(dest_udt_attr_expr), K(ret)); + } else if (OB_ISNULL(dest_udt_attr_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr is NULL", K(dest_udt_attr_expr), K(ret)); + } else { + dest = dest_udt_attr_expr; + } } else { ObSysFunRawExpr *dest_sys = NULL; if (OB_FAIL(create_raw_expr(expr_type, dest_sys))) { @@ -6656,5 +6681,146 @@ int ObRawExprFactory::create_raw_expr(ObRawExpr::ExprClass expr_class, return ret; } +int ObUDTConstructorRawExpr::get_schema_object_version(share::schema::ObSchemaObjVersion &obj_version) +{ + int ret = OB_SUCCESS; + CK (object_schema_version_ != OB_INVALID_VERSION); + CK (udt_id_ != common::OB_INVALID_ID); + OX (obj_version.object_id_ = udt_id_); + OX (obj_version.object_type_ = share::schema::DEPENDENCY_TYPE); + OX (obj_version.version_ = object_schema_version_); + + return ret; +} + +int ObUDTConstructorRawExpr::set_access_names( + const common::ObIArray &access_idents) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && i < access_idents.count(); ++i) { + OZ (access_names_.push_back(access_idents.at(i).access_name_)); + } + return ret; +} + +int ObUDTConstructorRawExpr::assign(const ObRawExpr &other) +{ + int ret = OB_SUCCESS; + if (OB_LIKELY(this != &other)) { + if (OB_UNLIKELY(get_expr_class() != other.get_expr_class() || + get_expr_type() != other.get_expr_type())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid input expr", K(ret), K(other.get_expr_type())); + } else if (OB_FAIL(ObSysFunRawExpr::assign(other))) { + LOG_WARN("failed to assign expr", K(ret)); + } else { + const ObUDTConstructorRawExpr &tmp = + static_cast(other); + udt_id_ = tmp.udt_id_; + root_udt_id_ = tmp.root_udt_id_; + attr_pos_ = tmp.attr_pos_; + object_schema_version_ = tmp.object_schema_version_; + if (OB_FAIL(access_names_.assign(tmp.access_names_))) { + LOG_WARN("failed to assgin access names", K(ret)); + } + } + } + return ret; +} + +int ObUDTConstructorRawExpr::inner_deep_copy(ObIRawExprCopier &copier) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObSysFunRawExpr::inner_deep_copy(copier))) { + LOG_WARN("failed to copy expr attributes", K(ret)); + } else if (copier.deep_copy_attributes()) { + CK (OB_NOT_NULL(inner_alloc_)); + for (int64_t i = 0; OB_SUCC(ret) && i < access_names_.count(); ++i) { + OZ (ob_write_string(*inner_alloc_, access_names_.at(i), access_names_.at(i))); + } + } + return ret; +} + +ObExprOperator *ObUDTConstructorRawExpr::get_op() +{ + int ret = OB_SUCCESS; + ObExprOperator *expr_op = NULL; + ObExprUdtConstruct *object_op = NULL; + if (T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT == get_expr_type()) { + free_op(); + if (OB_ISNULL(expr_op = ObOpRawExpr::get_op())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("make object construct operator failed", K(ret)); + } + CK (OB_NOT_NULL(object_op = static_cast(expr_op))); + OX (object_op->set_udt_id(udt_id_)); + OX (object_op->set_root_udt_id(root_udt_id_)); + OX (object_op->set_attribute_pos(attr_pos_)); + } + return OB_SUCCESS == ret ? expr_op : NULL; +} + + +int ObUDTAttributeAccessRawExpr::get_schema_object_version(share::schema::ObSchemaObjVersion &obj_version) +{ + int ret = OB_SUCCESS; + CK (object_schema_version_ != OB_INVALID_VERSION); + CK (udt_id_ != common::OB_INVALID_ID); + OX (obj_version.object_id_ = udt_id_); + OX (obj_version.object_type_ = share::schema::DEPENDENCY_TYPE); + OX (obj_version.version_ = object_schema_version_); + + return ret; +} + +int ObUDTAttributeAccessRawExpr::assign(const ObRawExpr &other) +{ + int ret = OB_SUCCESS; + if (OB_LIKELY(this != &other)) { + if (OB_UNLIKELY(get_expr_class() != other.get_expr_class() || + get_expr_type() != other.get_expr_type())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid input expr", K(ret), K(other.get_expr_type())); + } else if (OB_FAIL(ObSysFunRawExpr::assign(other))) { + LOG_WARN("failed to assign expr", K(ret)); + } else { + const ObUDTAttributeAccessRawExpr &tmp = + static_cast(other); + udt_id_ = tmp.udt_id_; + object_schema_version_ = tmp.object_schema_version_; + attr_type_ = tmp.attr_type_; + } + } + return ret; +} + +int ObUDTAttributeAccessRawExpr::inner_deep_copy(ObIRawExprCopier &copier) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObSysFunRawExpr::inner_deep_copy(copier))) { + LOG_WARN("failed to copy expr attributes", K(ret)); + } + return ret; +} + +ObExprOperator *ObUDTAttributeAccessRawExpr::get_op() +{ + int ret = OB_SUCCESS; + ObExprOperator *expr_op = NULL; + ObExprUDTAttributeAccess *object_op = NULL; + if (T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS == get_expr_type()) { + free_op(); + if (OB_ISNULL(expr_op = ObOpRawExpr::get_op())) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("make object construct operator failed", K(ret)); + } + CK (OB_NOT_NULL(object_op = static_cast(expr_op))); + object_op->set_attribute_type(attr_type_); + object_op->set_udt_id(udt_id_); + } + return OB_SUCCESS == ret ? expr_op : NULL; +} + }//namespace sql }//namespace oceanbase diff --git a/src/sql/resolver/expr/ob_raw_expr.h b/src/sql/resolver/expr/ob_raw_expr.h index 984500d743..26dff2486a 100644 --- a/src/sql/resolver/expr/ob_raw_expr.h +++ b/src/sql/resolver/expr/ob_raw_expr.h @@ -97,7 +97,11 @@ extern ObRawExpr *USELESS_POINTER; || ((op) == T_FUN_SYS_ST_COVERS) \ || ((op) == T_FUN_SYS_ST_DWITHIN) \ || ((op) == T_FUN_SYS_ST_WITHIN) \ - || ((op) == T_FUN_SYS_ST_CONTAINS)) \ + || ((op) == T_FUN_SYS_ST_CONTAINS) \ + || ((op) == T_FUN_SYS_PRIV_ST_EQUALS) \ + || ((op) == T_FUN_SYS_PRIV_ST_TOUCHES) \ + || ((op) == T_FUN_SYS_ST_CROSSES) \ + || ((op) == T_FUN_SYS_ST_OVERLAPS)) \ #define IS_MYSQL_GEO_OP(op) \ (((op) == T_FUN_SYS_ST_GEOMFROMTEXT) \ @@ -136,8 +140,15 @@ extern ObRawExpr *USELESS_POINTER; || ((op) == T_FUN_SYS_ST_DISTANCE_SPHERE) \ || ((op) == T_FUN_SYS_ST_DWITHIN) \ || ((op) == T_FUN_SYS_ST_WITHIN) \ - || ((op) == T_FUN_SYS_ST_CONTAINS)) \ - + || ((op) == T_FUN_SYS_ST_CONTAINS) \ + || ((op) == T_FUN_SYS_ST_CROSSES) \ + || ((op) == T_FUN_SYS_ST_OVERLAPS) \ + || ((op) == T_FUN_SYS_ST_UNION) \ + || ((op) == T_FUN_SYS_ST_LENGTH) \ + || ((op) == T_FUN_SYS_ST_DIFFERENCE) \ + || ((op) == T_FUN_SYS_ST_ASGEOJSON) \ + || ((op) == T_FUN_SYS_ST_CENTROID) \ + || ((op) == T_FUN_SYS_ST_SYMDIFFERENCE)) \ #define IS_PRIV_GEO_OP(op) \ (((op) == T_FUN_SYS_PRIV_ST_BUFFER) \ @@ -148,7 +159,17 @@ extern ObRawExpr *USELESS_POINTER; || ((op) == T_FUN_SYS_PRIV_ST_POINT) \ || ((op) == T_FUN_SYS_PRIV_ST_GEOGFROMTEXT) \ || ((op) == T_FUN_SYS_PRIV_ST_GEOGRAPHYFROMTEXT) \ - || ((op) == T_FUN_SYS_PRIV_ST_ASEWKT)) \ + || ((op) == T_FUN_SYS_PRIV_ST_ASEWKT) \ + || ((op) == T_FUN_SYS_PRIV_ST_NUMINTERIORRINGS) \ + || ((op) == T_FUN_SYS_PRIV_ST_ISCOLLECTION) \ + || ((op) == T_FUN_SYS_PRIV_ST_EQUALS) \ + || ((op) == T_FUN_SYS_PRIV_ST_TOUCHES) \ + || ((op) == T_FUN_SYS_PRIV_ST_MAKEENVELOPE) \ + || ((op) == T_FUN_SYS_PRIV_ST_CLIPBYBOX2D) \ + || ((op) == T_FUN_SYS_PRIV_ST_POINTONSURFACE) \ + || ((op) == T_FUN_SYS_PRIV_ST_GEOMETRYTYPE) \ + || ((op) == T_FUN_SYS_PRIV_ST_ASMVTGEOM) \ + || ((op) == T_FUN_SYS_PRIV_ST_MAKE_VALID)) \ #define IS_GEO_OP(op) ((IS_MYSQL_GEO_OP(op)) || IS_PRIV_GEO_OP(op)) @@ -2681,7 +2702,6 @@ public: bool is_xml_column() const { return ob_is_xml_pl_type(get_data_type(), get_udt_id()) || ob_is_xml_sql_type(get_data_type(), get_subschema_id()); } - bool is_udt_hidden_column() const { return is_hidden_column() && get_udt_set_id() > 0;} inline common::ObGeoType get_geo_type() const { return static_cast(srs_info_.geo_type_); } @@ -3655,7 +3675,7 @@ public: const pl::ObPLDataType& get_elem_type() const { return elem_type_; } int64_t get_capacity() const { return capacity_; } uint64_t get_udt_id() const { return udt_id_; } - + int64_t get_udt_version() const { return coll_schema_version_; } int assign(const ObRawExpr &other) override; int inner_deep_copy(ObIRawExprCopier &copier) override; @@ -3726,6 +3746,8 @@ public: inline void set_udt_id(uint64_t udt_id) { udt_id_ = udt_id; } uint64_t get_udt_id() { return udt_id_; } + int64_t get_udt_version() { return object_schema_version_; } + inline int add_elem_type(ObExprResType &elem_type) { return elem_types_.push_back(elem_type); @@ -3949,6 +3971,8 @@ public: inline void set_pkg_id(uint64_t pkg_id){ pkg_id_ = pkg_id; } inline uint64_t get_pkg_id() const { return pkg_id_; } inline uint64_t get_udf_id() const { return udf_id_; } + inline int64_t get_pkg_version() const { return pkg_schema_version_; } + inline int64_t get_udf_version() const { return udf_schema_version_; } inline const ObIArray &get_subprogram_path() const { return subprogram_path_; } inline pl::ObPLIntegerType get_pls_type() const { return pls_type_; } inline common::ObIArray &get_params_type() { return params_type_; } @@ -4971,6 +4995,126 @@ inline uint64_t ObPlQueryRefRawExpr::hash_internal(uint64_t seed) const return hash_value; } +class ObUDTConstructorRawExpr : public ObSysFunRawExpr +{ +public: + ObUDTConstructorRawExpr(common::ObIAllocator &alloc) + : ObSysFunRawExpr(alloc), + udt_id_(OB_INVALID_ID), + root_udt_id_(OB_INVALID_ID), + attr_pos_(0), + access_names_(), + database_id_(OB_INVALID_ID), + object_schema_version_(common::OB_INVALID_VERSION) {} + ObUDTConstructorRawExpr() + : ObSysFunRawExpr(), + udt_id_(OB_INVALID_ID), + root_udt_id_(OB_INVALID_ID), + attr_pos_(0), + access_names_(), + database_id_(OB_INVALID_ID), + object_schema_version_(common::OB_INVALID_VERSION) {} + + virtual ~ObUDTConstructorRawExpr() {} + + inline void set_udt_id(uint64_t udt_id) { udt_id_ = udt_id; } + uint64_t get_udt_id() { return udt_id_; } + inline void set_root_udt_id(uint64_t udt_id) { root_udt_id_ = udt_id; } + uint64_t get_root_udt_id() { return root_udt_id_; } + inline void set_attribute_pos(uint64_t attr_pos) { attr_pos_ = attr_pos; } + uint64_t get_attribute_pos() { return attr_pos_; } + int set_access_names(const common::ObIArray &access_idents); + int add_access_name(const common::ObString &access_name) { return access_names_.push_back(access_name); } + const common::ObIArray& get_access_names() const { return access_names_; } + + int assign(const ObRawExpr &other) override; + int inner_deep_copy(ObIRawExprCopier &copier) override; + + inline void set_database_id(int64_t database_id) + { + database_id_ = database_id; + } + + OB_INLINE uint64_t get_database_id() const { return database_id_; } + + inline void set_coll_schema_version(int64_t schema_version) + { + object_schema_version_ = schema_version; + } + + inline bool need_add_dependency() + { + return object_schema_version_ != common::OB_INVALID_VERSION; + } + + int get_schema_object_version(share::schema::ObSchemaObjVersion &obj_version); + + virtual ObExprOperator *get_op() override; + + VIRTUAL_TO_STRING_KV_CHECK_STACK_OVERFLOW(N_ITEM_TYPE, type_, + N_RESULT_TYPE, result_type_, + N_EXPR_INFO, info_, + N_REL_ID, rel_ids_, + N_FUNC, get_func_name(), + N_CHILDREN, exprs_, + K_(database_id), + K_(object_schema_version)); +private: + uint64_t udt_id_; + // 记录Object每个元素的类型 + uint64_t root_udt_id_; + uint64_t attr_pos_; + // 用于打印构造函数的名字 + common::ObSEArray access_names_; + int64_t database_id_; + int64_t object_schema_version_; +}; + +class ObUDTAttributeAccessRawExpr : public ObSysFunRawExpr +{ +public: + ObUDTAttributeAccessRawExpr(common::ObIAllocator &alloc) + : ObSysFunRawExpr(alloc), + udt_id_(OB_INVALID_ID), + object_schema_version_(common::OB_INVALID_VERSION) {} + ObUDTAttributeAccessRawExpr() + : ObSysFunRawExpr(), + udt_id_(OB_INVALID_ID), + object_schema_version_(common::OB_INVALID_VERSION) {} + + virtual ~ObUDTAttributeAccessRawExpr() {} + + inline void set_udt_id(uint64_t udt_id) { udt_id_ = udt_id; } + uint64_t get_udt_id() { return udt_id_; } + + inline void set_attribute_type(uint64_t attr_type) { attr_type_ = attr_type; } + uint64_t get_attribute_type() { return attr_type_; } + + + int assign(const ObRawExpr &other) override; + int inner_deep_copy(ObIRawExprCopier &copier) override; + + inline void set_schema_object_version(int64_t schema_version) + { + object_schema_version_ = schema_version; + } + + inline bool need_add_dependency() + { + return object_schema_version_ != common::OB_INVALID_VERSION; + } + + int get_schema_object_version(share::schema::ObSchemaObjVersion &obj_version); + + virtual ObExprOperator *get_op() override; + +private: + uint64_t udt_id_; + uint64_t attr_type_; // attribute type + int64_t object_schema_version_; +}; + + }// end sql }// end oceanbase diff --git a/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp b/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp index 822d4c623f..6e6fea431f 100644 --- a/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_deduce_type.cpp @@ -159,6 +159,28 @@ int ObRawExprDeduceType::visit(ObColumnRefRawExpr &expr) || CS_LEVEL_INVALID == expr.get_collation_level())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid meta of binary_ref", K(expr)); + } else if (expr.get_result_type().is_user_defined_sql_type() + || expr.get_result_type().is_collection_sql_type()) { + // need const cast to modify subschema ctx, in physcial plan ctx belong to cur exec_ctx; + ObSQLSessionInfo *session = const_cast(my_session_); + ObExecContext *exec_ctx = OB_ISNULL(session) ? NULL : session->get_cur_exec_ctx(); + uint64_t udt_id = expr.get_result_type().get_udt_id(); + uint16_t subschema_id = expr.get_result_type().get_subschema_id(); + if (subschema_id == ObXMLSqlType) { + // compact with xmltype implement, udt_id may not set, if this column ref is from sub querys + // example: SELECT id, a_t3.po FROM t1 LEFT JOIN (SELECT t3_id, XMLAGG()) ... + // all other udt type should use udt_id to get subschma_id when deduce types + expr.set_subschema_id(ObXMLSqlType); + expr.set_udt_id(T_OBJ_XML); + } else if (OB_ISNULL(exec_ctx)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("need context to search subschema mapping", K(ret), K(udt_id)); + } else if (FALSE_IT(subschema_id = ObMaxSystemUDTSqlType)) { + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_udt_id(udt_id, subschema_id))) { + LOG_WARN("failed to get subschema id by udt id", K(ret), K(udt_id)); + } else { + expr.set_subschema_id(subschema_id); + } } return ret; } @@ -299,7 +321,7 @@ bool need_reject_geometry_type(ObItemType item_type) { bool bool_ret = false; if ((item_type >= T_OP_BIT_AND && item_type <= T_OP_BIT_RIGHT_SHIFT) - || (item_type >= T_OP_BTW && item_type <= T_OP_NOT_IN) + || (item_type >= T_OP_BTW && item_type <= T_OP_OR) || (item_type >= T_FUN_MAX && item_type <= T_FUN_AVG) || item_type == T_OP_POW || item_type == T_FUN_SYS_EXP @@ -436,7 +458,9 @@ int ObRawExprDeduceType::calc_result_type(ObNonTerminalRawExpr &expr, // ToDo: test and fix, not all sql functions need calc json as long text if (ObJsonType == type->get_type() && !need_calc_json(expr.get_expr_type())) { type->set_calc_type(ObLongTextType); - } else if (ObGeometryType == type->get_type() && need_reject_geometry_type(expr.get_expr_type())) { + } else if (!lib::is_oracle_mode() + && ObGeometryType == type->get_type() + && need_reject_geometry_type(expr.get_expr_type())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("Incorrect geometry arguments", K(expr.get_expr_type()), K(ret)); } @@ -586,7 +610,8 @@ int ObRawExprDeduceType::calc_result_type(ObNonTerminalRawExpr &expr, if (OB_FAIL(ret)) { } else if (from != to && !cast_supported(from, from_cs_type, to, to_cs_type) - && !my_session_->is_varparams_sql_prepare()) { + && !my_session_->is_varparams_sql_prepare() + && !(my_session_->is_pl_prepare_stage() && to == ObGeometryType && is_oracle_mode)) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("cast parameter to expected type not supported", K(ret), K(i), K(from), K(to)); } else if (is_oracle_mode && (ob_is_lob_locator(from) || ob_is_text_tc(from))) { @@ -1483,6 +1508,12 @@ int ObRawExprDeduceType::visit(ObAggFunRawExpr &expr) } break; } + case T_FUN_SYS_ST_ASMVT: { + if (OB_FAIL(set_asmvt_result_type(expr, result_type))) { + LOG_WARN("set asmvt result type failed", K(ret)); + } + break; + } case T_FUN_GROUP_CONCAT: { need_add_cast = true; if (OB_FAIL(set_agg_group_concat_result_type(expr, result_type))) { @@ -2353,7 +2384,7 @@ int ObRawExprDeduceType::visit(ObSysFunRawExpr &expr) } else if (lib::is_oracle_mode() && !expr.is_pl_expr() && expr.is_called_in_sql() && T_FUN_SYS_CAST != expr.get_expr_type() && param_expr->get_expr_type() != T_FUN_SYS_CAST && param_expr->get_result_type().get_type() == ObExtendType - && param_expr->get_result_type().get_udt_id() == T_OBJ_XML) { + && ObObjUDTUtil::ob_is_supported_sql_udt(param_expr->get_result_type().get_udt_id())) { if (OB_FAIL(ObRawExprUtils::implict_cast_pl_udt_to_sql_udt(expr_factory_, my_session_, param_expr))) { LOG_WARN("add implict cast to pl udt expr failed", K(ret)); } else if (OB_FAIL(types.push_back(param_expr->get_result_type()))) { @@ -3254,6 +3285,22 @@ int ObRawExprDeduceType::set_agg_regr_result_type(ObAggFunRawExpr &expr, ObExprR ObAccuracy::DDL_DEFAULT_ACCURACY2[ORACLE_MODE][to_type].get_precision()); expr.set_result_type(result_type); } + } + return ret; +} +int ObRawExprDeduceType::set_asmvt_result_type(ObAggFunRawExpr &expr, + ObExprResType& result_type) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(expr.get_real_param_count() < 1)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("get unexpected error", K(ret), K(expr.get_param_count()), K(expr.get_real_param_count()), K(expr)); + } else { + result_type.set_type(ObLongTextType); + result_type.set_collation_type(CS_TYPE_BINARY); + result_type.set_collation_level(CS_LEVEL_IMPLICIT); + result_type.set_accuracy(ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType]); + expr.set_result_type(result_type); } return ret; } @@ -3521,6 +3568,7 @@ int ObRawExprDeduceType::add_implicit_cast(ObAggFunRawExpr &parent, (parent.get_expr_type() == T_FUN_JSON_OBJECTAGG && i == 1) || (parent.get_expr_type() == T_FUN_ORA_JSON_OBJECTAGG && i > 0) || (parent.get_expr_type() == T_FUN_ORA_XMLAGG && i > 0) || + parent.get_expr_type() == T_FUN_SYS_ST_ASMVT || ((parent.get_expr_type() == T_FUN_SUM || parent.get_expr_type() == T_FUN_AVG || parent.get_expr_type() == T_FUN_COUNT) && @@ -3679,7 +3727,12 @@ int ObRawExprDeduceType::try_add_cast_expr_above_for_deduce_type(ObRawExpr &expr cast_dst_type.set_precision(PRECISION_UNKNOWN_YET); cast_dst_type.set_scale(ORA_NUMBER_SCALE_UNKNOWN_YET); } - + if (cast_dst_type.is_user_defined_sql_type() || cast_dst_type.is_collection_sql_type()) { + uint64_t udt_id = (dst_type.is_user_defined_sql_type() || dst_type.is_collection_sql_type()) + ? dst_type.get_udt_id() + : dst_type.get_calc_accuracy().get_accuracy(); + cast_dst_type.set_udt_id(udt_id); + } // 这里仅设置部分情况的accuracy,其他情况的accuracy信息交给cast类型推导设置 if (lib::is_mysql_mode() && cast_dst_type.is_string_type() && cast_dst_type.has_result_flag(ZEROFILL_FLAG)) { diff --git a/src/sql/resolver/expr/ob_raw_expr_deduce_type.h b/src/sql/resolver/expr/ob_raw_expr_deduce_type.h index dc1ef414c0..21e433d126 100644 --- a/src/sql/resolver/expr/ob_raw_expr_deduce_type.h +++ b/src/sql/resolver/expr/ob_raw_expr_deduce_type.h @@ -106,7 +106,7 @@ private: int set_agg_group_concat_result_type(ObAggFunRawExpr &expr, ObExprResType &result_type); int set_json_agg_result_type(ObAggFunRawExpr &expr, ObExprResType& result_type, bool &need_add_cast); - + int set_asmvt_result_type(ObAggFunRawExpr &expr, ObExprResType& result_type); int set_agg_json_array_result_type(ObAggFunRawExpr &expr, ObExprResType &result_type); int set_agg_min_max_result_type(ObAggFunRawExpr &expr, ObExprResType &result_type, diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp index 41fca06f5a..3ad4476086 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp @@ -763,8 +763,8 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, ObRawExpr case T_FUN_ORA_JSON_ARRAYAGG: case T_FUN_ORA_JSON_OBJECTAGG: case T_FUN_ORA_XMLAGG: - case T_FUN_SUM_OPNSIZE:{ - + case T_FUN_SUM_OPNSIZE: + case T_FUN_SYS_ST_ASMVT: { if (OB_FAIL(process_agg_node(node, expr))) { LOG_WARN("fail to process agg node", K(ret), K(node)); } @@ -1180,6 +1180,12 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, ObRawExpr } break; } + case T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT: { + if (OB_FAIL(process_sql_udt_construct_node(node, expr))) { + LOG_WARN("fail to process sql udt construct node", K(ret), K(node)); + } + break; + } case T_REMOTE_SEQUENCE: { if (OB_FAIL(process_remote_sequence_node(node, expr))) { LOG_WARN("failed to process remote sequence node", K(ret)); @@ -1189,6 +1195,12 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, ObRawExpr case T_DBLINK_UDF: { if (OB_FAIL(process_dblink_udf_node(node, expr))) { LOG_WARN("failed to process dblink udf node", K(ret), K(node)); + } + break; + } + case T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS: { + if (OB_FAIL(process_sql_udt_attr_access_node(node, expr))) { + LOG_WARN("fail to process sql udt access attr node", K(ret), K(node)); } break; } @@ -1261,6 +1273,132 @@ int ObRawExprResolverImpl::process_ident_node(const ParseNode &node, ObRawExpr * return ret; } +int ObRawExprResolverImpl::process_sql_udt_construct_node(const ParseNode *node, ObRawExpr *&expr) +{ + INIT_SUCC(ret); + if (OB_ISNULL(node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node is null", K(ret)); + } else if(T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT != node->type_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node->type_ error", K(node->type_)); + } else if (2 > node->num_child_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param num", K(node->num_child_)); + } else { + ObSysFunRawExpr *sys_udt_construct = NULL; + ObUDTConstructorRawExpr * udt_construct = NULL; + if (OB_FAIL(ctx_.expr_factory_.create_raw_expr(T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT, sys_udt_construct))) { + LOG_WARN("failed to create fun sys_udt_construct expr", K(ret)); + } else if (OB_ISNULL(sys_udt_construct)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sys_udt_construct expr is null", K(ret)); + } else { + sys_udt_construct->set_func_name(ObString::make_string("_udt_construct")); + udt_construct = static_cast(sys_udt_construct); + } + for (int32_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) { + const ParseNode *expr_node = node->children_[i]; + if (OB_ISNULL(expr_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node is null", K(ret)); + } else if (expr_node->type_ == T_INT) { + if (i == node->num_child_ - 3) { + // udt_id + udt_construct->set_root_udt_id(expr_node->value_); + } else if (i == node->num_child_ - 2) { + // sub_udt_id + ObExprResType res_type; + res_type.set_type(ObUserDefinedSQLType); + res_type.set_udt_id(expr_node->value_); + udt_construct->set_result_type(res_type); + udt_construct->set_udt_id(expr_node->value_); + ObRawExpr *para_expr = NULL; + OZ(recursive_resolve(expr_node, para_expr)); + CK(OB_NOT_NULL(para_expr)); + OZ(sys_udt_construct->add_param_expr(para_expr)); + } else if (i == node->num_child_ - 1) { + // schema_version + udt_construct->set_coll_schema_version(expr_node->value_); + if (udt_construct->need_add_dependency()) { + ObSchemaObjVersion udt_version; + if (OB_FAIL(udt_construct->get_schema_object_version(udt_version))) { + LOG_WARN("get udt construct schema version failed", K(ret)); + } else if (OB_FAIL(ctx_.stmt_->add_global_dependency_table(udt_version))) { + LOG_WARN("add udt type dependency failed", K(ret), K(udt_version)); + } + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected node type", K(ret), K(i), K(node->num_child_)); + } + } else { + ObRawExpr *para_expr = NULL; + OZ(recursive_resolve(expr_node, para_expr)); + CK(OB_NOT_NULL(para_expr)); + OZ(sys_udt_construct->add_param_expr(para_expr)); + } + } + OX(expr = sys_udt_construct); + } + return ret; +} + +int ObRawExprResolverImpl::process_sql_udt_attr_access_node(const ParseNode *node, ObRawExpr *&expr) +{ + INIT_SUCC(ret); + if (OB_ISNULL(node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node is null", K(ret)); + } else if(T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS != node->type_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node->type_ error", K(node->type_)); + } else if (2 > node->num_child_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected param num", K(node->num_child_)); + } else { + ObSysFunRawExpr *sys_attr_access = NULL; + ObUDTAttributeAccessRawExpr * attr_access_expr = NULL; + if (OB_FAIL(ctx_.expr_factory_.create_raw_expr(T_FUN_SYS_PRIV_SQL_UDT_ATTR_ACCESS, sys_attr_access))) { + LOG_WARN("failed to create fun sys_attr_access expr", K(ret)); + } else if (OB_ISNULL(sys_attr_access)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sys_attr_access expr is null", K(ret)); + } else { + sys_attr_access->set_func_name(ObString::make_string(N_PRIV_UDT_ATTR_ACCESS)); + attr_access_expr = static_cast(sys_attr_access); + } + for (int32_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) { + const ParseNode *expr_node = node->children_[i]; + if (OB_ISNULL(expr_node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node is null", K(ret)); + } else if (i == 1) { + // udt_id + attr_access_expr->set_udt_id(expr_node->value_); + } else if (i == 3) { + // schema_version + attr_access_expr->set_schema_object_version(expr_node->value_); + if (attr_access_expr->need_add_dependency()) { + ObSchemaObjVersion udt_version; + if (OB_FAIL(attr_access_expr->get_schema_object_version(udt_version))) { + LOG_WARN("get udt construct schema version failed", K(ret)); + } else if (OB_FAIL(ctx_.stmt_->add_global_dependency_table(udt_version))) { + LOG_WARN("add udt type dependency failed", K(ret), K(udt_version)); + } + } + } else { + ObRawExpr *para_expr = NULL; + OZ(recursive_resolve(expr_node, para_expr)); + CK(OB_NOT_NULL(para_expr)); + OZ(sys_attr_access->add_param_expr(para_expr)); + } + } + OX(expr = sys_attr_access); + } + return ret; +} + int ObRawExprResolverImpl::process_xml_element_node(const ParseNode *node, ObRawExpr *&expr) { INIT_SUCC(ret); @@ -4479,6 +4617,17 @@ int ObRawExprResolverImpl::process_agg_node(const ParseNode *node, ObRawExpr *&e LOG_WARN("fail to add param expr to agg expr", K(ret)); } } // end for + } else if (T_FUN_SYS_ST_ASMVT == node->type_) { + for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; ++i) { + sub_expr = NULL; + if (OB_ISNULL(node->children_[i])) { + // do nothing + } else if (OB_FAIL(SMART_CALL(recursive_resolve(node->children_[i], sub_expr)))) { + LOG_WARN("fail to recursive resolve expr list item", K(ret)); + } else if (OB_FAIL(agg_expr->add_real_param_expr(sub_expr))) { + LOG_WARN("fail to add param expr to agg expr", K(ret)); + } + } // end for } else if (T_FUN_ORA_XMLAGG == node->type_) { sub_expr = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; ++i) { diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h index 3c81e51a0e..986de6cef3 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h @@ -202,6 +202,8 @@ private: int process_odbc_time_literals(const ObItemType dst_time_type, const ParseNode *expr_node, ObRawExpr *&expr); + int process_sql_udt_construct_node(const ParseNode *node, ObRawExpr *&expr); + int process_sql_udt_attr_access_node(const ParseNode *node, ObRawExpr *&expr); int process_xml_element_node(const ParseNode *node, ObRawExpr *&expr); int process_xml_attributes_node(const ParseNode *node, ObRawExpr *&expr); int process_xml_attributes_values_node(const ParseNode *node, ObRawExpr *&expr); diff --git a/src/sql/resolver/expr/ob_raw_expr_util.cpp b/src/sql/resolver/expr/ob_raw_expr_util.cpp index 27d192a372..eac4168020 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_util.cpp @@ -36,6 +36,7 @@ #include "sql/engine/expr/ob_expr_cast.h" #include "common/ob_smart_call.h" #include "pl/ob_pl_resolver.h" +#include "pl/ob_pl_type.h" #include "sql/optimizer/ob_optimizer_util.h" #include "sql/resolver/dml/ob_dml_resolver.h" #include "sql/resolver/dml/ob_select_resolver.h" @@ -1060,6 +1061,7 @@ int ObRawExprUtils::resolve_udf_param_exprs(ObResolverParams ¶ms, OX (const_default_expr->set_expr_obj_meta(null_meta)); OX (param_exprs.at(i) = default_expr); // rewrite param type, for do not cast default value + CK(udf_raw_expr->get_param_count() < udf_raw_expr->get_params_type().count()); OX (udf_raw_expr->get_params_type().at( udf_raw_expr->get_param_count()).set_meta(null_meta)); } @@ -2366,6 +2368,7 @@ int ObRawExprUtils::build_generated_column_expr(ObRawExprFactory &expr_factory, ObSEArray, 1> ref_sys_exprs; ObSEArray real_columns; ObSequenceNamespaceChecker sequence_checker(schema_checker, &session_info); + ObArray real_exprs; for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); i++) { const ObQualifiedName &q_name = columns.at(i); if (q_name.is_sys_func()) { @@ -2378,12 +2381,17 @@ int ObRawExprUtils::build_generated_column_expr(ObRawExprFactory &expr_factory, OZ (q_name.access_idents_.at(0).check_param_num()); OZ (ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, sys_func)); OZ (ref_sys_exprs.push_back(std::pair(q_name.ref_expr_, sys_func))); + OZ(real_exprs.push_back(sys_func)); } else if (q_name.is_pl_udf()) { ObRawExpr *udf_info = NULL; - for (uint64_t i = 0; OB_SUCC(ret) && i < q_name.access_idents_.count(); ++i) { - const ObUDFInfo &udf_info = q_name.access_idents_.at(i).udf_info_; - if (OB_NOT_NULL(udf_info.ref_expr_)) { - OZ (ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, udf_info.ref_expr_), q_name); + for (uint64_t j = 0; OB_SUCC(ret) && j < q_name.access_idents_.count(); ++j) { + ObObjAccessIdent &access_ident = columns.at(i).access_idents_.at(j); + if (access_ident.is_pl_udf()) { + OZ (pl::ObPLResolver::replace_udf_param_expr(access_ident, columns, real_exprs)); + const ObUDFInfo &udf_info = access_ident.udf_info_; + if (OB_NOT_NULL(udf_info.ref_expr_)) { + OZ (ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, udf_info.ref_expr_), q_name); + } } } OZ(real_columns.push_back(q_name), q_name, i); @@ -4014,11 +4022,17 @@ int ObRawExprUtils::try_add_cast_expr_above(ObRawExprFactory *expr_factory, const ObExprResType &src_type = expr.get_result_type(); CK(OB_NOT_NULL(session) && OB_NOT_NULL(expr_factory)); OZ(ObRawExprUtils::check_need_cast_expr(src_type, dst_type, need_cast, ignore_dup_cast_error)); + if (ret == OB_ERR_INVALID_TYPE_FOR_OP && + const_cast(session)->is_pl_prepare_stage() && + dst_type.is_geometry() && lib::is_oracle_mode()) { + ret = OB_SUCCESS; + need_cast = true; + } if (OB_SUCC(ret) && need_cast) { if (T_FUN_SYS_CAST == expr.get_expr_type() && expr.has_flag(IS_OP_OPERAND_IMPLICIT_CAST) && !ignore_dup_cast_error - && !(src_type.is_user_defined_sql_type() + && !((src_type.is_user_defined_sql_type()|| src_type.is_collection_sql_type()) && (dst_type.is_character_type() || dst_type.is_null()))) { // cases like: select xmltype(var)||xmltype(var) as "res1" from t1 t; // xmltype is a lp constructor, an implicit cast is added to cast PL xmltype to SQL xmltype @@ -4063,9 +4077,10 @@ int ObRawExprUtils::try_add_cast_expr_above(ObRawExprFactory *expr_factory, return ret; } + int ObRawExprUtils::implict_cast_pl_udt_to_sql_udt(ObRawExprFactory *expr_factory, - const ObSQLSessionInfo *session, - ObRawExpr* &real_ref_expr) + const ObSQLSessionInfo *session, + ObRawExpr* &real_ref_expr) { int ret = OB_SUCCESS; @@ -4073,17 +4088,36 @@ int ObRawExprUtils::implict_cast_pl_udt_to_sql_udt(ObRawExprFactory *expr_factor ret = OB_ERR_UNEXPECTED; LOG_WARN("real_ref_expr is null", K(ret)); } else if (real_ref_expr->get_result_type().is_ext()) { - if (real_ref_expr->get_result_type().get_udt_id() == T_OBJ_XML) { - // add implicit cast to sql xmltype + uint64_t udt_id = real_ref_expr->get_result_type().get_udt_id(); + if (ObObjUDTUtil::ob_is_supported_sql_udt(udt_id)) { ObRawExpr *new_expr = NULL; ObCastMode cast_mode = CM_NONE; ObExprResType sql_udt_type; - sql_udt_type.set_sql_udt(ObXMLSqlType); // set subschema id if (OB_FAIL(ObSQLUtils::get_default_cast_mode(false, 0, session, cast_mode))) { LOG_WARN("get default cast mode failed", K(ret)); + } else if (udt_id == T_OBJ_SDO_GEOMETRY) { + sql_udt_type.set_geometry(); + } else { + ObExecContext * exec_ctx = const_cast(session)->get_cur_exec_ctx(); + uint16_t subschema_id; + if (OB_ISNULL(exec_ctx)) { + ret = OB_NOT_INIT; + LOG_WARN("exec context is null", K(ret), K(udt_id)); + } else if (OB_FAIL(exec_ctx->get_subschema_id_by_udt_id(udt_id, subschema_id))) { + LOG_WARN("failed to get ssubschema meta", K(ret), K(udt_id)); + } else if (subschema_id == ObMaxSystemUDTSqlType) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid udt id", K(ret), K(udt_id)); + } else { + // Add implicit cast from pl extend to sql udt + sql_udt_type.set_sql_udt(subschema_id); // set subschema id + sql_udt_type.set_udt_id(udt_id); + } + } + if (OB_FAIL(ret)) { } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above( - expr_factory, session, - *real_ref_expr, sql_udt_type, cast_mode, new_expr))) { + expr_factory, session, + *real_ref_expr, sql_udt_type, cast_mode, new_expr))) { LOG_WARN("try add cast expr above failed", K(ret)); } else if (OB_FAIL(new_expr->add_flag(IS_OP_OPERAND_IMPLICIT_CAST))) { LOG_WARN("failed to add flag", K(ret)); @@ -4096,8 +4130,8 @@ int ObRawExprUtils::implict_cast_pl_udt_to_sql_udt(ObRawExprFactory *expr_factor } int ObRawExprUtils::implict_cast_sql_udt_to_pl_udt(ObRawExprFactory *expr_factory, - const ObSQLSessionInfo *session, - ObRawExpr* &real_ref_expr) + const ObSQLSessionInfo *session, + ObRawExpr* &real_ref_expr) { int ret = OB_SUCCESS; @@ -4105,19 +4139,53 @@ int ObRawExprUtils::implict_cast_sql_udt_to_pl_udt(ObRawExprFactory *expr_factor ret = OB_ERR_UNEXPECTED; LOG_WARN("real_ref_expr is null", K(ret)); } else if (real_ref_expr->get_result_type().is_user_defined_sql_type()) { - if (real_ref_expr->get_result_type().is_xml_sql_type()) { - // add implicit cast to sql xmltype - ObRawExpr *new_expr = NULL; - ObCastMode cast_mode = CM_NONE; - ObExprResType pl_udt_type; - pl_udt_type.set_ext(); - pl_udt_type.set_extend_type(pl::PL_OPAQUE_TYPE); - pl_udt_type.set_udt_id(T_OBJ_XML); + ObRawExpr *new_expr = NULL; + ObCastMode cast_mode = CM_NONE; + ObExprResType pl_udt_type; + pl_udt_type.set_ext(); + + uint16_t subschema_id = real_ref_expr->get_result_type().get_subschema_id(); + const uint64_t expr_udt_id = (subschema_id == ObXMLSqlType) + ? T_OBJ_XML + : real_ref_expr->get_result_type().get_udt_id(); + + OB_ASSERT(ObObjUDTUtil::ob_is_supported_sql_udt(expr_udt_id)); + ObSqlUDTMeta udt_meta; + ObExecContext * exec_ctx = const_cast(session)->get_cur_exec_ctx(); + if (!ObObjUDTUtil::ob_is_supported_sql_udt(expr_udt_id)) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("unsupported udt type for sql udt", + K(ret), K(real_ref_expr->get_result_type()), K(expr_udt_id)); + } else if (OB_ISNULL(exec_ctx)) { + ret = OB_NOT_INIT; + LOG_WARN("exec context is null", K(ret), K(expr_udt_id)); + } else if (subschema_id == ObInvalidSqlType) { // called in resolver, cast sql udt to pl udt + if (OB_FAIL(exec_ctx->get_subschema_id_by_udt_id(expr_udt_id, subschema_id))) { + LOG_WARN("failed to get subschema id by udt id", K(ret), K(expr_udt_id)); + } + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(exec_ctx->get_sqludt_meta_by_subschema_id(subschema_id, udt_meta))) { + LOG_WARN("failed to get udt meta", K(ret), K(udt_meta.udt_id_)); + } else if (!ObObjUDTUtil::ob_is_supported_sql_udt(udt_meta.udt_id_)) { + // Just bypass un-supported type, not return error here. + } else { + // can get extend type by schema guard, leave use of subschema when deduce. + OB_ASSERT(expr_udt_id == udt_meta.udt_id_); + pl_udt_type.set_udt_id(udt_meta.udt_id_); + // set pl extend type, use udt_meta extend type, or get extend type from udtinfoschema + if (subschema_id == ObXMLSqlType) { + pl_udt_type.set_extend_type(pl::PL_OPAQUE_TYPE); + } else { + // PL_RECORD_TYPE or PL_VARRAY_TYPE is supported + pl_udt_type.set_extend_type(udt_meta.pl_type_); + } + // add implicit cast from sql udt to pl extend if (OB_FAIL(ObSQLUtils::get_default_cast_mode(session, cast_mode))) { LOG_WARN("get default cast mode failed", K(ret)); } else if (OB_FAIL(ObRawExprUtils::try_add_cast_expr_above( - expr_factory, session, - *real_ref_expr, pl_udt_type, cast_mode, new_expr))) { + expr_factory, session, + *real_ref_expr, pl_udt_type, cast_mode, new_expr))) { LOG_WARN("try add cast expr above failed", K(ret)); } else if (OB_FAIL(new_expr->add_flag(IS_OP_OPERAND_IMPLICIT_CAST))) { LOG_WARN("failed to add flag", K(ret)); @@ -4175,6 +4243,7 @@ int ObRawExprUtils::create_cast_expr(ObRawExprFactory &expr_factory, // pl xmltype -> sql xmltype -> char type is supported only in sql scenario ObExprResType sql_udt_type; sql_udt_type.set_sql_udt(ObXMLSqlType); // set subschema id + sql_udt_type.set_udt_id(T_OBJ_XML); OZ(create_real_cast_expr(expr_factory, src_expr, sql_udt_type, extra_cast, session)); OZ(create_real_cast_expr(expr_factory, extra_cast, dst_type, func_expr, session)); } else { @@ -4888,9 +4957,8 @@ int ObRawExprUtils::build_column_conv_expr(ObRawExprFactory &expr_factory, expr_factory, col_ref.get_data_type(), col_ref.get_collation_type(), - (col_ref.get_data_type() != ObUserDefinedSQLType) - ? col_ref.get_accuracy().get_accuracy() - : col_ref.get_subschema_id(), + // accuracy used as udt id for udt columns + col_ref.get_accuracy().get_accuracy(), !col_ref.is_not_null_for_write(), &column_conv_info, &col_ref.get_enum_set_values(), @@ -5035,6 +5103,9 @@ int ObRawExprUtils::build_column_conv_expr(const ObSQLSessionInfo *session_info, f_expr->set_func_name(ObString::make_string(N_COLUMN_CONV)); f_expr->set_data_type(dest_type); f_expr->set_expr_type(T_FUN_COLUMN_CONV); + if (ob_is_user_defined_type(dest_type) || ob_is_collection_sql_type(dest_type)) { + f_expr->set_udt_id(accuracy); + } if (expr->is_for_generated_column()) { f_expr->set_for_generated_column(); } @@ -6630,13 +6701,9 @@ int ObRawExprUtils::init_column_expr(const ObColumnSchemaV2 &column_schema, ObCo } } if (OB_SUCC(ret) && column_schema.is_xmltype()) { - // column_expr.set_udt_id(column_schema.get_sub_data_type()); - // } - // ToDo : @gehao, need to conver extend type to udt type? - //if (OB_SUCC(ret) && column_schema.is_sql_xmltype()) { column_expr.set_data_type(ObUserDefinedSQLType); + column_expr.set_udt_id(column_schema.get_sub_data_type()); column_expr.set_subschema_id(ObXMLSqlType); - // reset accuracy } return ret; @@ -7091,8 +7158,10 @@ int ObRawExprUtils::check_composite_cast(ObRawExpr *&expr, ObSchemaChecker &sche && src->get_param_expr(0)->get_expr_type() == T_QUESTIONMARK))) { if (ObNullType == src->get_result_type().get_type()) { // do nothing - } else if (src->get_result_type().is_user_defined_sql_type()) { + } else if (src->get_result_type().is_user_defined_sql_type() || + (src->get_result_type().is_geometry() && is_oracle_mode() && udt_id == T_OBJ_SDO_GEOMETRY)) { // allow pl udt cast to sql udt type + // allow oracle gis cast to pl extend } else if (ObExtendType != src->get_result_type().get_type()) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("invalid cast a normal type to udt", K(ret)); @@ -7865,8 +7934,17 @@ int ObRawExprUtils::create_type_expr(ObRawExprFactory &expr_factory, parse_node.int16_values_[OB_NODE_CAST_N_PREC_IDX] = dst_type.get_precision(); parse_node.int16_values_[OB_NODE_CAST_N_SCALE_IDX] = dst_type.get_scale(); } - if (dst_type.is_ext()) { - dst_expr->set_udt_id(dst_type.get_udt_id()); + if (dst_type.is_ext() + || dst_type.is_user_defined_sql_type() + || dst_type.is_collection_sql_type()) { + // it is not possible to use arg[1] (u32) to record udt_id + // use subschema id before type deduce maybe also not good idea + // but we can always record real udt id on ObExprResType + if (dst_type.is_xml_sql_type()) { + dst_expr->set_udt_id(T_OBJ_XML); + } else { + dst_expr->set_udt_id(dst_type.get_udt_id()); + } } val.set_int(parse_node.value_); diff --git a/src/sql/resolver/ob_resolver_utils.cpp b/src/sql/resolver/ob_resolver_utils.cpp index af3f1dac3b..ead19b2e89 100644 --- a/src/sql/resolver/ob_resolver_utils.cpp +++ b/src/sql/resolver/ob_resolver_utils.cpp @@ -1043,13 +1043,18 @@ int ObResolverUtils::check_type_match(const pl::ObPLResolveCtx &resolve_ctx, || ((ObUserDefinedSQLTC == ob_obj_type_class(dst_type) || ObExtendTC == ob_obj_type_class(dst_type)) && !(ObUserDefinedSQLTC == ob_obj_type_class(src_type) - || ObExtendTC == ob_obj_type_class(src_type)))) { + || ObExtendTC == ob_obj_type_class(src_type) + || ObGeometryTC == ob_obj_type_class(src_type))) + || (ObGeometryTC == ob_obj_type_class(src_type) && lib::is_oracle_mode() + && ObExtendTC != ob_obj_type_class(dst_type))) { ret = OB_ERR_INVALID_TYPE_FOR_OP; LOG_WARN("argument count not match", K(ret), K(src_type), K(dst_type)); } else if (ObExtendTC == ob_obj_type_class(src_type) // 普通类型与复杂类型不能互转 || ObExtendTC == ob_obj_type_class(dst_type)) { if (ObUserDefinedSQLTC == ob_obj_type_class(src_type) - || ObUserDefinedSQLTC == ob_obj_type_class(dst_type)) { + || ObUserDefinedSQLTC == ob_obj_type_class(dst_type) + || ObGeometryTC == ob_obj_type_class(dst_type) + || ObGeometryTC == ob_obj_type_class(src_type)) { // check can cast } else { ret = OB_ERR_INVALID_TYPE_FOR_OP; @@ -1093,6 +1098,9 @@ int ObResolverUtils::get_type_and_type_id( type = ObTinyIntType; } else if (T_FUN_PL_INTEGER_CHECKER == expr->get_expr_type()) { type = ObInt32Type; + } else if (expr->get_result_type().is_geometry()) { + type = ObGeometryType; + type_id = T_OBJ_SDO_GEOMETRY; } else { type = expr->get_result_type().get_type(); } @@ -4935,6 +4943,7 @@ int ObResolverUtils::resolve_generated_column_expr(ObResolverParams ¶ms, case ObLobType: case ObLongTextType: case ObUserDefinedSQLType: + case ObCollectionSQLType: ret = OB_ERR_RESULTANT_DATA_TYPE_OF_VIRTUAL_COLUMN_IS_NOT_SUPPORTED; LOG_WARN("lob data type in generated column definition", K(ret)); break; @@ -5227,12 +5236,64 @@ int ObResolverUtils::resolve_default_expr_v2_column_expr(ObResolverParams ¶m // length('hello')会在resolve后产生一个column,需要将column.ref_expr_替换成真正的sys_func bool is_all_sys_func = true; ObRawExpr *real_ref_expr = NULL; + ObArray real_exprs; for (int64_t i = 0; OB_SUCC(ret) && is_all_sys_func && i < columns.count(); i++) { ObQualifiedName &q_name = columns.at(i); - if (q_name.is_pl_udf()) { - ret = OB_NOT_SUPPORTED; - LOG_USER_ERROR(OB_NOT_SUPPORTED, "using udf as default value"); - LOG_WARN("using udf as default value is not supported", K(ret)); + if (q_name.is_pl_udf()) { // only default constructer is supported + if (OB_FAIL(ObResolverUtils::resolve_external_symbol(*params.allocator_, + *params.expr_factory_, + *params.session_info_, + *params.schema_checker_->get_schema_guard(), + params.sql_proxy_, + &(params.external_param_info_), + params.secondary_namespace_, + q_name, + columns, + real_exprs, + real_ref_expr, + params.package_guard_, + params.is_prepare_protocol_, + false, /*is_check_mode*/ + true /*is_sql_scope*/))) { + LOG_WARN_IGNORE_COL_NOTFOUND(ret, "failed to resolve var", K(q_name), K(ret)); + } else if (OB_ISNULL(real_ref_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("Invalid expr", K(expr), K(ret)); + } else if (real_ref_expr->is_udf_expr() + && (expr->get_expr_type() != T_FUN_PL_OBJECT_CONSTRUCT) + && (expr->get_expr_type() != T_FUN_PL_COLLECTION_CONSTRUCT)) { + // only default constructor is supported currently + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "using udf as default value"); + LOG_WARN("using udf as default value is not supported", + K(ret), K(default_expr_v2_column.get_column_name_str())); + } else { + // column_ref is replaced inside build_generated_column_expr with udf, + // here replace udf with object/collection constructor + if (OB_FAIL(real_exprs.push_back(real_ref_expr))) { + LOG_WARN("push back error", K(ret)); + } + // handle flatterned obj access: a(b,c)->b,c,a repalce ref_expr once an ObQualifiedName handled + for (int64_t i = 0; OB_SUCC(ret) && i < real_exprs.count(); ++i) { + ObQualifiedName &q_name = columns.at(i); + const ObUDFInfo &udf_info = q_name.access_idents_.at(q_name.access_idents_.count() - 1).udf_info_; + if (OB_NOT_NULL(udf_info.ref_expr_)) { + if (OB_FAIL(ObRawExprUtils::replace_ref_column(real_ref_expr, + udf_info.ref_expr_, + real_exprs.at(i)))) { + LOG_WARN("replace column ref expr failed", K(ret)); + } + } + } + // replace expr, only outside ref_expr_ is equal to expr + const ObUDFInfo &udf_info = q_name.access_idents_.at(q_name.access_idents_.count() - 1).udf_info_; + if (OB_SUCC(ret) && OB_NOT_NULL(udf_info.ref_expr_)) { + if (OB_FAIL(ObRawExprUtils::replace_ref_column(expr, udf_info.ref_expr_, real_ref_expr))) { + LOG_WARN("replace column ref expr failed", K(ret)); + } + } + real_ref_expr = NULL; + } } else if (!q_name.is_sys_func()) { is_all_sys_func = false; } else if (OB_ISNULL(q_name.access_idents_.at(0).sys_func_expr_)) { @@ -7186,9 +7247,19 @@ int ObResolverUtils::resolve_external_symbol(common::ObIAllocator &allocator, { int ret = OB_SUCCESS; if (NULL == package_guard) { - CK (OB_NOT_NULL(session_info.get_cur_exec_ctx())); - OZ (session_info.get_cur_exec_ctx()->get_package_guard(package_guard)); - CK (OB_NOT_NULL(package_guard)); + // patch bugfix from 42x: 55397384 + if (NULL != session_info.get_cur_exec_ctx()) { + OZ (session_info.get_cur_exec_ctx()->get_package_guard(package_guard)); + CK (OB_NOT_NULL(package_guard)); + } else { + ret = OB_ERR_SP_UNDECLARED_VAR; + LOG_WARN("exec context is NULL", K(ret)); + if (q_name.access_idents_.count() >= 0) { + LOG_USER_ERROR(OB_ERR_SP_UNDECLARED_VAR, + q_name.access_idents_.at(0).access_name_.length(), + q_name.access_idents_.at(0).access_name_.ptr()); + } + } } if (OB_SUCC(ret)) { pl::ObPLResolver pl_resolver(allocator, diff --git a/src/sql/resolver/ob_schema_checker.cpp b/src/sql/resolver/ob_schema_checker.cpp index efaa4417a9..64930c3f88 100644 --- a/src/sql/resolver/ob_schema_checker.cpp +++ b/src/sql/resolver/ob_schema_checker.cpp @@ -29,6 +29,7 @@ #include "common/ob_smart_call.h" #include "share/schema/ob_sys_variable_mgr.h" // ObSimpleSysVariableSchema #include "sql/resolver/ob_stmt_resolver.h" +#include "pl/ob_pl_stmt.h" using namespace oceanbase::sql; using namespace oceanbase::common; @@ -1215,10 +1216,9 @@ int ObSchemaChecker::get_sys_udt_id(const ObString &udt_name, if (IS_NOT_INIT) { ret = OB_NOT_INIT; LOG_WARN("schema checker is not inited", K_(is_inited)); - } else if (lib::is_oracle_mode() && udt_name.case_compare("xmltype") == 0) { - if (OB_FAIL(schema_mgr_->get_udt_id(OB_SYS_TENANT_ID, OB_SYS_DATABASE_ID, -1, udt_name, udt_id))) { - LOG_WARN("get udt info failed", K(ret)); - } + } else if (lib::is_oracle_mode() && + OB_FAIL(schema_mgr_->get_udt_id(OB_SYS_TENANT_ID, OB_SYS_DATABASE_ID, -1, udt_name, udt_id))) { + LOG_WARN("get udt info failed", K(ret)); } return ret; } @@ -3005,6 +3005,138 @@ bool ObSchemaChecker::is_ora_priv_check() return false; } +int ObSchemaChecker::flatten_udt_attributes( + const uint64_t tenant_id, + const uint64_t udt_id, + ObIAllocator &allocator, + ObString &qualified_name, + int64_t &schema_version, + ObIArray &udt_qualified_names) +{ + int ret = OB_SUCCESS; + const share::schema::ObUDTTypeInfo *udt_info = NULL; + if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("schema checker is not inited", K_(is_inited)); + } else if (OB_FAIL(schema_mgr_->get_udt_info(tenant_id, udt_id, udt_info))) { + LOG_WARN("get udt info failed", K(ret), K(tenant_id)); + } else if (OB_ISNULL(udt_info)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("udt info is null.", K(ret), K(udt_id)); + } else if (OB_FAIL(construct_udt_qualified_name(*udt_info, allocator, tenant_id, qualified_name, udt_qualified_names))) { + LOG_WARN("failed to construct udt qualified name.", K(ret), K(udt_id)); + } else { + schema_version = udt_info->get_schema_version(); + } + return ret; +} + +int ObSchemaChecker::construct_udt_qualified_name(const ObUDTTypeInfo &udt_info, ObIAllocator &allocator, + const uint64_t tenant_id, + ObString &qualified_name, + ObIArray &udt_qualified_names) +{ + int ret = OB_SUCCESS; + bool is_overflow = false; + if (OB_FAIL(check_stack_overflow(is_overflow))) { + LOG_WARN("failed to check stack overflow", K(ret)); + } else if (is_overflow) { + ret = OB_SIZE_OVERFLOW; + LOG_WARN("too deep recusive", K(ret)); + } + for (int i = 0; i < udt_info.get_attributes() && OB_SUCC(ret); i++) { + const ObUDTTypeAttr *attr = udt_info.get_attrs().at(i); + const char *curr_content = qualified_name.ptr() + qualified_name.length(); + if (OB_ISNULL(attr)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument.", K(ret)); + } else if ((i + 1) != attr->get_attribute()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("attribute sequence is wrong.", K(ret), K(udt_info.get_type_id()), K(i), K(attr->get_attribute())); + } else if (qualified_name.write(".", 1) == 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to write qualified name", K(ret), K(udt_info.get_type_id())); + } else if (qualified_name.write(attr->get_name().ptr(), attr->get_name().length()) == 0) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to write qualified name", K(ret), K(udt_info.get_type_id()), K(attr->get_name())); + } else if (attr->get_type_attr_id() >= ObMaxType) { + // udt type + const ObUDTTypeInfo *sub_udt_info = NULL; + if (OB_FAIL(get_udt_info(tenant_id, attr->get_type_attr_id(), sub_udt_info))) { + LOG_WARN("failed to get udt info", K(ret), K(tenant_id), K(udt_info.get_type_id())); + } else if (sub_udt_info->is_collection()) { + char *name_str = static_cast(allocator.alloc(qualified_name.length())); + if (OB_ISNULL(name_str)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to alloc memory", K(ret), K(qualified_name.length()), K(udt_info.get_type_id())); + } else { + MEMCPY(name_str, qualified_name.ptr(), qualified_name.length()); + if (OB_FAIL(udt_qualified_names.push_back(ObString(qualified_name.length(), name_str)))) { + LOG_WARN("failed to push back qualified name", K(ret), K(udt_info.get_type_id())); + } + } + } else if (sub_udt_info->get_typecode() == UDT_TYPE_OBJECT) { + // object + if (OB_FAIL(construct_udt_qualified_name(*sub_udt_info, allocator, tenant_id, + qualified_name, udt_qualified_names))) { + LOG_WARN("add udt attribute to table_schema failed", K(ret), K(attr->get_type_attr_id()), K(tenant_id)); + } + } + } else { + char *name_str = static_cast(allocator.alloc(qualified_name.length())); + if (OB_ISNULL(name_str)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to alloc memory", K(ret), K(qualified_name.length()), K(udt_info.get_type_id())); + } else { + MEMCPY(name_str, qualified_name.ptr(), qualified_name.length()); + if (OB_FAIL(udt_qualified_names.push_back(ObString(qualified_name.length(), name_str)))) { + LOG_WARN("failed to push back qualified name", K(ret), K(udt_info.get_type_id())); + } + } + } + if (OB_SUCC(ret)) { + qualified_name.clip(curr_content); + } + } + return ret; +} + +int ObSchemaChecker::get_udt_attribute_id(const uint64_t udt_id, const ObString &attr_name, uint64_t &attr_id, uint64_t &attr_pos) +{ + int ret = OB_SUCCESS; + uint64_t tenant_id = pl::get_tenant_id_by_object_id(udt_id); + const share::schema::ObUDTTypeInfo *udt_info = NULL; + bool is_overflow = false; + if (OB_FAIL(check_stack_overflow(is_overflow))) { + LOG_WARN("failed to check stack overflow", K(ret)); + } else if (is_overflow) { + ret = OB_SIZE_OVERFLOW; + LOG_WARN("too deep recusive", K(ret)); + } else if (IS_NOT_INIT) { + ret = OB_NOT_INIT; + LOG_WARN("schema checker is not inited", K_(is_inited)); + } else if (OB_FAIL(schema_mgr_->get_udt_info(tenant_id, udt_id, udt_info))) { + LOG_WARN("get udt info failed", K(ret), K(tenant_id)); + } else if (OB_ISNULL(udt_info)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("udt info is null.", K(ret), K(udt_id)); + } else if (!udt_info->is_collection()) { + for (int i = 0; i < udt_info->get_attributes() && OB_SUCC(ret) && attr_id == OB_INVALID_ID; i++) { + const ObUDTTypeAttr *attr = udt_info->get_attrs().at(i); + if (attr->get_name().case_compare(attr_name) == 0) { + attr_id = attr->get_type_attr_id(); + attr_pos++; + } else if (attr->get_type_attr_id() >= ObMaxType) { + attr_pos++; + if (OB_FAIL(get_udt_attribute_id(attr->get_type_attr_id(), attr_name, attr_id, attr_pos))) { + LOG_WARN("failed to get udt attribute id", K(ret), K(udt_id)); + } + } + } + } + return ret; +} + int ObSchemaChecker::remove_tmp_cte_schemas(const ObString& cte_table_name) { int ret = OB_SUCCESS; diff --git a/src/sql/resolver/ob_schema_checker.h b/src/sql/resolver/ob_schema_checker.h index 371c9d7e67..cc2ec0f228 100644 --- a/src/sql/resolver/ob_schema_checker.h +++ b/src/sql/resolver/ob_schema_checker.h @@ -520,9 +520,22 @@ public: int get_directory_id(const uint64_t tenant_id, const common::ObString &directory_name, uint64_t &directory_id); +int flatten_udt_attributes(const uint64_t tenant_id, + const uint64_t udt_id, + ObIAllocator &allocator, + ObString &qualified_name, + int64_t &schema_version, + ObIArray &udt_qualified_names); + int get_udt_attribute_id(const uint64_t udt_id, const ObString &attr_name, uint64_t &attr_id, uint64_t &attr_pos); + int remove_tmp_cte_schemas(const ObString& cte_table_name); private: + +int construct_udt_qualified_name(const share::schema::ObUDTTypeInfo &udt_info, ObIAllocator &allocator, + const uint64_t tenant_id, + ObString &qualified_name, + ObIArray &udt_qualified_names); int get_link_table_schema_inner(uint64_t table_id, const share::schema::ObTableSchema *&table_schema) const; int get_table_schema_inner(const uint64_t tenant_id, uint64_t table_id, diff --git a/src/sql/rewrite/ob_query_range.cpp b/src/sql/rewrite/ob_query_range.cpp index 3410b3178a..476ef24dfd 100644 --- a/src/sql/rewrite/ob_query_range.cpp +++ b/src/sql/rewrite/ob_query_range.cpp @@ -3642,7 +3642,7 @@ int ObQueryRange::pre_extract_geo_op(const ObOpRawExpr *geo_expr, common::ObGeoRelationType op_type; if (OB_ISNULL(l_expr) || OB_ISNULL(r_expr)) { GET_ALWAYS_TRUE_OR_FALSE(true, out_key_part); - } else if (l_expr->has_flag(IS_COLUMN) && r_expr->has_flag(IS_COLUMN)) { + } else if (l_expr->has_flag(CNT_COLUMN) && r_expr->has_flag(CNT_COLUMN)) { GET_ALWAYS_TRUE_OR_FALSE(true, out_key_part); } else if (l_expr->has_flag(IS_DYNAMIC_PARAM) && r_expr->has_flag(IS_DYNAMIC_PARAM)) { GET_ALWAYS_TRUE_OR_FALSE(true, out_key_part); @@ -8907,6 +8907,8 @@ common::ObGeoRelationType ObQueryRange::get_geo_relation(ObItemType type) const { common::ObGeoRelationType rel_type = common::ObGeoRelationType::T_INVALID; switch (type) { + case T_FUN_SYS_PRIV_ST_EQUALS : + case T_FUN_SYS_PRIV_ST_TOUCHES : case T_FUN_SYS_ST_INTERSECTS : { rel_type = common::ObGeoRelationType::T_INTERSECTS; break; @@ -8924,6 +8926,14 @@ common::ObGeoRelationType ObQueryRange::get_geo_relation(ObItemType type) const rel_type = common::ObGeoRelationType::T_COVEREDBY; break; } + case T_FUN_SYS_ST_CROSSES : { + rel_type = common::ObGeoRelationType::T_INTERSECTS; + break; + } + case T_FUN_SYS_ST_OVERLAPS : { + rel_type = common::ObGeoRelationType::T_INTERSECTS; + break; + } default: break; } @@ -9045,7 +9055,7 @@ int ObQueryRange::get_geo_intersects_keypart(uint32_t input_srid, } } - if (OB_SUCC(ret) && (geo_type != ObGeoType::POINT || !std::isnan(distance))) { + if (OB_SUCC(ret) && ((geo_type != ObGeoType::POINT && geo_type != ObGeoType::POINTZ) || !std::isnan(distance))) { // build keypart to index child_of_cellid for (uint64_t i = 0; OB_SUCC(ret) && i < cells.size(); i++) { uint64_t cellid = cells.at(i); diff --git a/src/sql/rewrite/ob_transform_pre_process.cpp b/src/sql/rewrite/ob_transform_pre_process.cpp index ffe76d4897..a3c59ce92a 100644 --- a/src/sql/rewrite/ob_transform_pre_process.cpp +++ b/src/sql/rewrite/ob_transform_pre_process.cpp @@ -39,6 +39,7 @@ #include "sql/resolver/dml/ob_merge_resolver.h" #include "sql/resolver/dml/ob_update_stmt.h" #include "sql/rewrite/ob_expand_aggregate_utils.h" +#include "sql/rewrite/ob_transform_udt_utils.h" #include "pl/ob_pl_stmt.h" #include "pl/ob_pl_resolver.h" #include "sql/privilege_check/ob_ora_priv_check.h" @@ -6987,454 +6988,6 @@ int ObTransformPreProcess::transform_generated_rownum_eq_cond(ObRawExpr *eq_valu return ret; } -int ObTransformPreProcess::transform_udt_column_value_expr_inner(ObDMLStmt *stmt, ObDmlTableInfo &table_info, ObRawExpr *&old_expr, ObRawExpr *hidd_expr) -{ - // replace udt column in value expr - int ret = OB_SUCCESS; - if (old_expr->is_column_ref_expr()) { - ObColumnRefRawExpr *col_ref = static_cast(old_expr); - if (col_ref->is_xml_column()) { - bool need_transform = false; - ObColumnRefRawExpr *hidd_col = static_cast(hidd_expr); - for (int j = 0; j < table_info.column_exprs_.count() && OB_ISNULL(hidd_col); j++) { - if (OB_FAIL(ObTransformUtils::create_udt_hidden_columns(ctx_, stmt, *col_ref, hidd_col, need_transform))) { - LOG_WARN("failed to create udt hidden exprs", K(ret)); - } - } - if (!need_transform) { - // do nothing - } else if (OB_ISNULL(hidd_col)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("hidden column is null", K(ret)); - } else if (!hidd_col->get_result_type().is_blob()) { - // if column is not clob type, don't need add xml_binary - old_expr = hidd_col; - } else if (OB_FAIL(transform_xml_binary(hidd_col, old_expr))) { - LOG_WARN("transform xml binary failed", K(ret)); - } - } - } else { - for (int i = 0; i < old_expr->get_param_count() && OB_SUCC(ret); i++) { - if (OB_FAIL(transform_udt_column_value_expr_inner(stmt, table_info, old_expr->get_param_expr(i), hidd_expr))) { - LOG_WARN("transform udt column value expr failed", K(ret)); - } - } - } - return ret; -} - -int ObTransformPreProcess::transform_udt_column_value_expr(ObDMLStmt *stmt, ObDmlTableInfo &table_info, ObRawExpr *old_expr, ObRawExpr *&new_expr, ObRawExpr *hidd_expr) -{ - int ret = OB_SUCCESS; - // to do: add SYS_MAKEXMLBinary - ObSysFunRawExpr *make_xml_expr = NULL; - ObConstRawExpr *c_expr = NULL; - if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected null", K(ret)); - } else if (OB_FAIL(transform_udt_column_value_expr_inner(stmt, table_info, old_expr, hidd_expr))) { - LOG_WARN("replace udt column failed", K(ret)); - } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_FUN_SYS_PRIV_MAKE_XML_BINARY, make_xml_expr))) { - LOG_WARN("failed to create fun make xml binary expr", K(ret)); - } else if (OB_ISNULL(make_xml_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("xml expr is null", K(ret)); - } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_INT, c_expr))) { - LOG_WARN("create dest type expr failed", K(ret)); - } else if (OB_ISNULL(c_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("const expr is null"); - } else { - ObObj val; - val.set_int(0); - c_expr->set_value(val); - c_expr->set_param(val); - if (OB_FAIL(make_xml_expr->set_param_exprs(c_expr, old_expr))) { - LOG_WARN("set param expr fail", K(ret)); - } else { - make_xml_expr->set_func_name(ObString::make_string("_make_xml_binary")); - if (OB_FAIL(make_xml_expr->formalize(ctx_->session_info_))) { - LOG_WARN("make xml epxr formlize fail", K(ret)); - } - new_expr = make_xml_expr; - } - } - return ret; -} - -int ObTransformPreProcess::transform_udt_column_conv_param_expr(ObDmlTableInfo &table_info, ObRawExpr *old_expr, ObRawExpr *&new_expr) -{ - int ret = OB_SUCCESS; - // to do: add SYS_MAKEXMLBinary - ObSysFunRawExpr *make_xml_expr = NULL; - ObConstRawExpr *c_expr = NULL; - if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected null", K(ret)); - } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_FUN_SYS_PRIV_MAKE_XML_BINARY, make_xml_expr))) { - LOG_WARN("failed to create fun make xml binary expr", K(ret)); - } else if (OB_ISNULL(make_xml_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("xml expr is null", K(ret)); - } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_INT, c_expr))) { - LOG_WARN("create dest type expr failed", K(ret)); - } else if (OB_ISNULL(c_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("const expr is null"); - } else { - ObObj val; - val.set_int(0); - c_expr->set_value(val); - c_expr->set_param(val); - if (OB_FAIL(make_xml_expr->set_param_exprs(c_expr, old_expr))) { - LOG_WARN("set param expr fail", K(ret)); - } else { - make_xml_expr->set_func_name(ObString::make_string("_make_xml_binary")); - if (OB_FAIL(make_xml_expr->formalize(ctx_->session_info_))) { - LOG_WARN("make xml epxr formlize fail", K(ret)); - } - new_expr = make_xml_expr; - } - } - return ret; -} - -int ObTransformPreProcess::transform_udt_column_conv_function(ObDmlTableInfo &table_info, - ObIArray &column_conv_exprs, - ObColumnRefRawExpr &udt_col, - ObColumnRefRawExpr &hidd_col) -{ - int ret = OB_SUCCESS; - bool hidd_found = false; - - for (int64_t j = 0; OB_SUCC(ret) && !hidd_found && j < table_info.column_exprs_.count(); ++j) { - ObColumnRefRawExpr *col = table_info.column_exprs_.at(j); - if (col->get_column_id() == hidd_col.get_column_id()) { - ObRawExpr *old_conv_expr = column_conv_exprs.at(j); - const ObColumnRefRawExpr *tmp = ObRawExprUtils::get_column_ref_expr_recursively(old_conv_expr->get_param_expr(4)); - ObRawExpr *old_col_ref = const_cast(static_cast(tmp)); - hidd_found = true; - ObRawExpr *new_value_expr = NULL; - if (OB_ISNULL(old_col_ref)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("old expr is null", K(ret)); - } else if (OB_FAIL(transform_udt_column_conv_param_expr(table_info, old_col_ref, new_value_expr))) { - LOG_WARN("failed to transform udt value exprs", K(ret)); - } else if (OB_FAIL(static_cast(old_conv_expr)->replace_param_expr(4, new_value_expr))) { - LOG_WARN("failed to push back udt hidden exprs", K(ret)); - } - } - } - return ret; -} - - -int ObTransformPreProcess::replace_udt_assignment_exprs(ObDMLStmt *stmt, - ObDmlTableInfo &table_info, - ObIArray &assignments, - bool &trans_happened) -{ - int ret = OB_SUCCESS; - trans_happened = false; - - for (int64_t j = 0; OB_SUCC(ret) && j < assignments.count(); ++j) { - ObColumnRefRawExpr *hidd_col = NULL; - ObRawExpr *value_expr = NULL; - ObAssignment &assign = assignments.at(j); - bool trigger_exist = false; - if (OB_ISNULL(assign.column_expr_) || OB_ISNULL(assign.expr_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("assgin expr is null", K(ret)); - } else if (!assign.column_expr_->is_xml_column()) { - // do nothins - } else { - for (int j = 0; j < table_info.column_exprs_.count() && OB_ISNULL(hidd_col); j++) { - if (table_info.column_exprs_.at(j)->get_column_id() != assign.column_expr_->get_column_id() && - table_info.column_exprs_.at(j)->get_udt_set_id() == assign.column_expr_->get_udt_set_id()) { - hidd_col = table_info.column_exprs_.at(j); - } - } - if (OB_ISNULL(hidd_col)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("hidden column is null", K(ret)); - } else if (assign.expr_->get_expr_type() == T_FUN_SYS_WRAPPER_INNER) { - trigger_exist = true; - value_expr = assign.expr_->get_param_expr(0); - } else { - value_expr = assign.expr_; - } - - if (OB_FAIL(ret)) { - // do nothing - } else if (value_expr->get_expr_type() != T_FUN_COLUMN_CONV) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpectd expr type", K(ret), K(assign.expr_->get_expr_type())); - } else if (OB_ISNULL(value_expr = value_expr->get_param_expr(4))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("raw expr param is null"); - } else if (value_expr->get_expr_type() == T_FUN_SYS_CAST) { - // don't need cast expr - value_expr = value_expr->get_param_expr(0); - } else if (value_expr->is_const_raw_expr()) { - if (value_expr->get_expr_type() == T_QUESTIONMARK) { - const ParamStore ¶m_store = ctx_->exec_ctx_->get_physical_plan_ctx()->get_param_store(); - ObConstRawExpr *param_expr = static_cast(value_expr); - int64_t param_idx = param_expr->get_value().get_unknown(); - if (param_idx < 0 || param_idx >= param_store.count()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("param_idx is invalid", K(ret), K(param_idx)); - } else if (param_store.at(param_idx).is_xml_sql_type() || - param_store.at(param_idx).is_extend_xml_type()){ - // do nothing - } else if (ob_is_decimal_int_tc(param_store.at(param_idx).get_type()) || - ob_is_number_tc(param_store.at(param_idx).get_type())) { - ret = OB_ERR_INVALID_TYPE_FOR_OP; - LOG_WARN("old_expr_type invalid ObLongTextType type", K(ret), K(param_store.at(param_idx).get_type())); - } else { - ObExprResType res_type; - res_type.set_varchar(); - res_type.set_collation_type(CS_TYPE_UTF8MB4_BIN); - value_expr->set_result_type(res_type); - } - } - } - } - if (OB_SUCC(ret) && assign.column_expr_->is_xml_column()) { - ObRawExpr *new_value_expr = NULL; - ObRawExpr *old_column_expr = assign.column_expr_; - if (OB_FAIL(transform_udt_column_value_expr(stmt, table_info, value_expr, new_value_expr))){ - LOG_WARN("failed to transform udt value exprs", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::build_column_conv_expr(*ctx_->expr_factory_, - *ctx_->allocator_, - *hidd_col, - new_value_expr, - ctx_->session_info_))) { - LOG_WARN("fail to build column conv expr", K(ret), K(hidd_col)); - } else { - trans_happened = true; - assign.column_expr_ = hidd_col; - if (trigger_exist) { - if (OB_FAIL(static_cast(assign.expr_)->replace_param_expr(0, new_value_expr))) { - LOG_WARN("failed to replace wrapper expr param", K(ret)); - } - } else { - assign.expr_ = new_value_expr; - } - } - // process returning clause for update - if (OB_SUCC(ret) && stmt->get_stmt_type() == stmt::T_UPDATE) { - ObDelUpdStmt *update_stmt = static_cast(stmt); - if (update_stmt->is_returning()) { - for (int64_t i = 0; OB_SUCC(ret) && i < update_stmt->get_returning_exprs().count(); i++) { - ObRawExpr *sys_makexml_expr = NULL; - if (OB_ISNULL(hidd_col)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("hidden col is NULL", K(ret), K(i), K(j)); - } else if (OB_FAIL(transform_xml_binary(new_value_expr, sys_makexml_expr))) { - LOG_WARN("fail to create sys_makexml expr", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::replace_ref_column(update_stmt->get_returning_exprs().at(i), - old_column_expr, - sys_makexml_expr))) { - LOG_WARN("fail to replace xml column in returning exprs", K(ret), K(i)); - } - } // end for - } - } //end if: process returning clause - } - } - - return ret; -} - -int ObTransformPreProcess::transform_xml_binary(ObRawExpr *hidden_blob_expr, ObRawExpr *&new_expr) -{ - int ret = OB_SUCCESS; - ObSysFunRawExpr *sys_makexml = NULL; - ObConstRawExpr *c_expr = NULL; - ObColumnRefRawExpr *hidd_col = NULL; - if (OB_ISNULL(ctx_) || OB_ISNULL(ctx_->expr_factory_) || OB_ISNULL(hidden_blob_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpected null", K(ret), KP(ctx_), KP(hidden_blob_expr)); - } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_FUN_SYS_MAKEXML, sys_makexml))) { - LOG_WARN("failed to create fun sys_makexml expr", K(ret)); - } else if (OB_ISNULL(sys_makexml)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("sys_makexml expr is null", K(ret)); - } else if (OB_FAIL(ctx_->expr_factory_->create_raw_expr(T_INT, c_expr))) { - LOG_WARN("create dest type expr failed", K(ret)); - } else if (OB_ISNULL(c_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("const expr is null"); - } else { - ObObj val; - val.set_int(0); - c_expr->set_value(val); - c_expr->set_param(val); - if (OB_FAIL(sys_makexml->set_param_exprs(c_expr, hidden_blob_expr))) { - LOG_WARN("set param expr fail", K(ret)); - } else if (FALSE_IT(sys_makexml->set_func_name(ObString::make_string("SYS_MAKEXML")))) { - } else if (OB_FAIL(sys_makexml->formalize(ctx_->session_info_))) { - LOG_WARN("failed to formalize", K(ret)); - } else { - new_expr = sys_makexml; - } - } - return ret; -} - -int ObTransformPreProcess::set_hidd_col_not_null_attr(const ObColumnRefRawExpr &udt_col, ObIArray &column_exprs) -{ - int ret = OB_SUCCESS; - bool found = false; - for (int64_t j = 0; OB_SUCC(ret) && !found && j < column_exprs.count(); ++j) { - ObColumnRefRawExpr *col_hidden = column_exprs.at(j); - if (col_hidden->get_udt_set_id() == udt_col.get_udt_set_id() && - udt_col.get_column_id() != col_hidden->get_column_id()) { - found = true; - if (udt_col.get_result_type().has_result_flag(HAS_NOT_NULL_VALIDATE_CONSTRAINT_FLAG)) { - col_hidden->set_result_flag(HAS_NOT_NULL_VALIDATE_CONSTRAINT_FLAG); - } - if (udt_col.get_result_type().has_result_flag(NOT_NULL_WRITE_FLAG)) { - col_hidden->set_result_flag(NOT_NULL_WRITE_FLAG); - } - } - } - if (!found) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to find hidden column", K(ret), K(udt_col.get_udt_set_id())); - } - return ret; -} - -int ObTransformPreProcess::get_dml_view_col_exprs(const ObDMLStmt *stmt, ObIArray &assign_col_exprs) -{ - int ret = OB_SUCCESS; - if (stmt->get_stmt_type() == stmt::T_UPDATE) { - const ObUpdateStmt *upd_stmt = static_cast(stmt); - for (int64_t i = 0; OB_SUCC(ret) && i < upd_stmt->get_update_table_info().count(); ++i) { - ObUpdateTableInfo* table_info = upd_stmt->get_update_table_info().at(i); - if (OB_ISNULL(table_info)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get null table info", K(ret)); - } - for (int64_t j = 0; OB_SUCC(ret) && j < table_info->assignments_.count(); ++j) { - ObAssignment &assign = table_info->assignments_.at(j); - if (OB_ISNULL(assign.column_expr_) || OB_ISNULL(assign.expr_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("assgin expr is null", K(ret)); - } else if (assign.column_expr_->is_xml_column() && - OB_FAIL(add_var_to_array_no_dup(assign_col_exprs, assign.column_expr_))) { - LOG_WARN("failed to push back column expr", K(ret)); - } - } - } - } - return ret; -} - -int ObTransformPreProcess::get_update_generated_udt_in_parent_stmt(const ObIArray &parent_stmts, - const ObDMLStmt *stmt, - ObIArray &col_exprs) -{ - int ret = OB_SUCCESS; - - const ObDMLStmt *root_stmt = NULL; - ObSEArray parent_col_exprs; - const ObSelectStmt *sel_stmt = NULL; - const ObDMLStmt *parent_stmt = NULL; - int64_t table_id = OB_INVALID; - bool is_valid = false; - if (OB_ISNULL(stmt)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpect null stmt", K(ret)); - } else if (!stmt->is_select_stmt() || parent_stmts.empty()) { - //do nothing - } else if (OB_FALSE_IT(sel_stmt = static_cast(stmt))) { - } else if (OB_ISNULL(root_stmt = parent_stmts.at(parent_stmts.count()-1).stmt_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to get parent stmt", K(ret)); - } else if (OB_FAIL(ObTransformUtils::get_parent_stmt(root_stmt, stmt, parent_stmt, table_id, is_valid))) { - LOG_WARN("failed to get parent stmt", K(ret)); - } else if (!is_valid) { - //do nothing - } else if (OB_ISNULL(parent_stmt)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpect null stmt", K(ret)); - } else if (OB_FAIL(get_dml_view_col_exprs(parent_stmt, parent_col_exprs))) { - LOG_WARN("failed to get assignment columns", K(ret)); - } else if (!parent_col_exprs.empty()) { - for (int64_t i = 0; OB_SUCC(ret) && i < parent_col_exprs.count(); ++i) { - ObColumnRefRawExpr* col = parent_col_exprs.at(i); - int64_t sel_idx = -1; - if (OB_ISNULL(col)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpect null column expr", K(ret)); - } else if (OB_FALSE_IT(sel_idx = col->get_column_id() - OB_APP_MIN_COLUMN_ID)) { - } else if (sel_idx < 0 || sel_idx >= sel_stmt->get_select_item_size()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("select item index is incorrect", K(sel_idx), K(ret)); - } else { - ObRawExpr *sel_expr = sel_stmt->get_select_item(sel_idx).expr_; - ObColumnRefRawExpr *col_expr = NULL; - if (OB_ISNULL(sel_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpect null expr", K(ret)); - } else if (!sel_expr->is_column_ref_expr()) { - //do nothing - } else if (OB_FALSE_IT(col_expr = static_cast(sel_expr))) { - } else if (OB_FAIL(add_var_to_array_no_dup(col_exprs, col_expr))) { - LOG_WARN("failed to push back column expr", K(ret)); - } - } - } - } - return ret; -} - -int ObTransformPreProcess::check_skip_child_select_view(const ObIArray &parent_stmts, - ObDMLStmt *stmt, bool &skip_for_view_table) -{ - int ret = OB_SUCCESS; - const ObSelectStmt *sel_stmt = NULL; - const ObDMLStmt *parent_stmt = NULL; - bool is_valid = false; - if (OB_ISNULL(stmt)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("unexpect null stmt", K(ret)); - } else if (!stmt->is_select_stmt() || parent_stmts.count() != 1 || - stmt->get_table_size() != 1) { - //do nothing - } else if (OB_FALSE_IT(sel_stmt = static_cast(stmt))) { - } else if (OB_ISNULL(parent_stmt = parent_stmts.at(0).stmt_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to get parent stmt", K(ret)); - } else if (parent_stmt->get_table_size() != 1 || - !(parent_stmt->is_delete_stmt() || parent_stmt->is_update_stmt())) { - // do nothing - } else { - const sql::TableItem *basic_table_item = stmt->get_table_item(0); - const sql::TableItem *view_table_item = parent_stmt->get_table_item(0); - if (OB_ISNULL(basic_table_item) || OB_ISNULL(view_table_item)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to get table item", K(ret)); - } else if (basic_table_item->is_basic_table() && view_table_item->is_generated_table()) { - if (OB_NOT_NULL(view_table_item->ref_query_) && - view_table_item->ref_query_->get_table_size() > 0 && - OB_NOT_NULL(view_table_item->ref_query_->get_table_item(0)) && - basic_table_item->table_id_ == view_table_item->ref_query_->get_table_item(0)->table_id_) { - skip_for_view_table = true; - } - } else if (!basic_table_item->is_basic_table() || !view_table_item->is_view_table_) { - // do nothing - } else if (OB_ISNULL(view_table_item->view_base_item_)) { - // do nothing - } else if (basic_table_item->table_id_ == view_table_item->view_base_item_->table_id_) { - skip_for_view_table = true; - } - } - return ret; -} - int ObTransformPreProcess::transform_json_object_expr_with_star(const ObIArray &parent_stmts, ObDMLStmt *stmt, bool &trans_happened) { @@ -7466,337 +7019,22 @@ int ObTransformPreProcess::transform_json_object_expr_with_star(const ObIArray &parent_stmts, - ObDMLStmt *stmt, bool &trans_happened) -{ - int ret = OB_SUCCESS; - ObSEArray scopes; - ObSEArray replace_exprs; - ObSEArray from_col_exprs; - ObSEArray to_col_exprs; - ObSEArray parent_assign_xml_col_exprs; - bool skip_for_view_table = false; - - if (OB_FAIL(get_update_generated_udt_in_parent_stmt(parent_stmts, stmt, parent_assign_xml_col_exprs))) { - LOG_WARN("Fail to get update generated column array.", K(ret)); - } else if (OB_FAIL(check_skip_child_select_view(parent_stmts, stmt, skip_for_view_table))) { - LOG_WARN("Fail to check if select in delete view.", K(ret)); - } else if (skip_for_view_table) { - // do nothing - } else { - FastUdtExprChecker expr_checker(replace_exprs); - if (OB_FAIL(scopes.push_back(SCOPE_DML_COLUMN)) || - (stmt->get_stmt_type() != stmt::T_MERGE && OB_FAIL(scopes.push_back(SCOPE_DML_VALUE))) || - OB_FAIL(scopes.push_back(SCOPE_DML_CONSTRAINT)) || - OB_FAIL(scopes.push_back(SCOPE_INSERT_DESC)) || - OB_FAIL(scopes.push_back(SCOPE_BASIC_TABLE)) || - OB_FAIL(scopes.push_back(SCOPE_DICT_FIELDS)) || - OB_FAIL(scopes.push_back(SCOPE_SHADOW_COLUMN)) || - ((stmt->get_stmt_type() == stmt::T_INSERT || stmt->get_stmt_type() == stmt::T_UPDATE) && - OB_FAIL(scopes.push_back(SCOPE_RETURNING))) || - (stmt->get_stmt_type() != stmt::T_MERGE && OB_FAIL(scopes.push_back(SCOPE_INSERT_VECTOR)))) { - LOG_WARN("Fail to create scope array.", K(ret)); - } - ObStmtExprGetter visitor; - visitor.checker_ = &expr_checker; - visitor.remove_scope(scopes); - if (OB_SUCC(ret) && OB_FAIL(stmt->iterate_stmt_expr(visitor))) { - LOG_WARN("get relation exprs failed", K(ret)); - } - - //collect query udt exprs which need to be replaced - for (int64_t i = 0; OB_SUCC(ret) && i < replace_exprs.count(); i++) { - if (OB_ISNULL(replace_exprs.at(i))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("replace expr is null", K(ret)); - } else { - ObColumnRefRawExpr *col_expr = static_cast(replace_exprs.at(i)); - ObColumnRefRawExpr *hidd_col = NULL; - ObRawExpr *sys_makexml_expr = NULL; - bool need_transform = false; - if (!col_expr->is_xml_column() || has_exist_in_array(parent_assign_xml_col_exprs, col_expr)) { - // do nothing - } else if (OB_FAIL(ObTransformUtils::create_udt_hidden_columns(ctx_, - stmt, - *col_expr, - hidd_col, - need_transform))) { - LOG_WARN("failed to create udt hidden exprs", K(ret)); - } else if (need_transform == false) { - // do nothing - } else if (OB_FAIL(transform_xml_binary(hidd_col, sys_makexml_expr))) { - LOG_WARN("failed to push back udt hidden exprs", K(ret)); - } else if (OB_FAIL(from_col_exprs.push_back(col_expr))) { - LOG_WARN("failed to push back udt exprs", K(ret)); - } else if (OB_FAIL(to_col_exprs.push_back(sys_makexml_expr))) { - LOG_WARN("failed to push back udt hidden exprs", K(ret)); - } - } - - //do replace - if (OB_SUCC(ret) && !from_col_exprs.empty()) { - ObStmtExprReplacer replacer; - replacer.remove_scope(scopes); - if (OB_FAIL(replacer.add_replace_exprs(from_col_exprs, to_col_exprs))) { - LOG_WARN("failed to add replace exprs", K(ret)); - } else if (OB_FAIL(stmt->iterate_stmt_expr(replacer))) { - LOG_WARN("failed to iterate stmt expr", K(ret)); - } else { - trans_happened = true; - } - } - } - } - - return ret; -} - -int ObTransformPreProcess::transform_udt_columns_constraint_exprs(ObDMLStmt *stmt, bool &trans_happened) -{ - int ret = OB_SUCCESS; - ObSEArray scopes; - ObSEArray replace_exprs; - ObSEArray from_col_exprs; - ObSEArray to_col_exprs; - FastUdtExprChecker expr_checker(replace_exprs); - ObStmtExprGetter visitor; - visitor.remove_all(); - visitor.add_scope(SCOPE_DML_CONSTRAINT); - visitor.checker_ = &expr_checker; - - if (OB_SUCC(ret) && OB_FAIL(stmt->iterate_stmt_expr(visitor))) { - LOG_WARN("get relation exprs failed", K(ret)); - } - - //collect query udt exprs which need to be replaced - for (int64_t i = 0; OB_SUCC(ret) && i < replace_exprs.count(); i++) { - if (OB_ISNULL(replace_exprs.at(i))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("replace expr is null", K(ret)); - } else { - ObColumnRefRawExpr *col_expr = static_cast(replace_exprs.at(i)); - ObColumnRefRawExpr *hidd_col = NULL; - ObRawExpr *sys_makexml_expr = NULL; - bool need_transform = false; - if (!col_expr->is_xml_column()) { - // do nothing - } else if (OB_FAIL(ObTransformUtils::create_udt_hidden_columns(ctx_, - stmt, - *col_expr, - hidd_col, - need_transform))) { - LOG_WARN("failed to create udt hidden exprs", K(ret)); - } else if (need_transform == false) { - // do nothing; - } else if (OB_FAIL(transform_xml_binary(hidd_col, sys_makexml_expr))) { - LOG_WARN("failed to push back udt hidden exprs", K(ret)); - } else if (OB_FAIL(from_col_exprs.push_back(col_expr))) { - LOG_WARN("failed to push back udt exprs", K(ret)); - } else if (OB_FAIL(to_col_exprs.push_back(sys_makexml_expr))) { - LOG_WARN("failed to push back udt hidden exprs", K(ret)); - } - } - } - - //do replace - if (OB_SUCC(ret) && !from_col_exprs.empty()) { - ObStmtExprReplacer replacer; - replacer.remove_all(); - replacer.add_scope(SCOPE_DML_CONSTRAINT); - if (OB_FAIL(replacer.add_replace_exprs(from_col_exprs, to_col_exprs))) { - LOG_WARN("failed to add replace exprs", K(ret)); - } else if (OB_FAIL(stmt->iterate_stmt_expr(replacer))) { - LOG_WARN("failed to iterate stmt expr", K(ret)); - } else { - trans_happened = true; - } - } - return ret; -} - - int ObTransformPreProcess::transform_udt_columns(const ObIArray &parent_stmts, ObDMLStmt *stmt, bool &trans_happened) { int ret = OB_SUCCESS; trans_happened = false; - ObSEArray udt_exprs; - ObSEArray from_col_exprs; - ObSEArray to_col_exprs; if (OB_ISNULL(stmt) || OB_ISNULL(ctx_) || OB_ISNULL(ctx_->session_info_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("stmt is NULL", K(ret), K(ctx_), K(ctx_->session_info_)); } else if (is_mysql_mode() || ctx_->session_info_->get_ddl_info().is_ddl()) { // do nothing - } else if (OB_FAIL(transform_query_udt_columns_exprs(parent_stmts, stmt, trans_happened))) { - LOG_WARN("failed to do query udt exprs transform", K(ret)); - } else if (OB_FAIL(transform_udt_columns_constraint_exprs(stmt, trans_happened))) { + } else if (OB_FAIL(ObTransformUdtUtils::transform_query_udt_columns_exprs(ctx_, parent_stmts, stmt, trans_happened))) { + LOG_WARN("failed to do query udt exprs transform", K(ret)); + } else if (OB_FAIL(ObTransformUdtUtils::transform_udt_columns_constraint_exprs(ctx_, stmt, trans_happened))) { LOG_WARN("failed to do udt constraint exprs transform", K(ret)); - } else { - // xmltype transform - if (stmt->get_stmt_type() == stmt::T_UPDATE) { - ObUpdateStmt *upd_stmt = static_cast(stmt); - for (int64_t i = 0; OB_SUCC(ret) && i < upd_stmt->get_update_table_info().count(); ++i) { - bool is_happened = false; - ObUpdateTableInfo* table_info = upd_stmt->get_update_table_info().at(i); - if (OB_ISNULL(table_info)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("get null table info", K(ret)); - } else if (OB_FAIL(replace_udt_assignment_exprs(upd_stmt, *table_info, table_info->assignments_, - is_happened))) { - LOG_WARN("failed to replace assignment exprs", K(ret)); - } else { - trans_happened |= is_happened; - LOG_TRACE("succeed to do const propagation for assignment expr", K(is_happened)); - } - } - } else if (stmt->get_stmt_type() == stmt::T_MERGE) { - bool is_happened = false; - ObMergeStmt *merge_stmt = static_cast(stmt); - ObMergeTableInfo &table_info = merge_stmt->get_merge_table_info(); - if (OB_FAIL(replace_udt_assignment_exprs(merge_stmt, table_info, - table_info.assignments_, - is_happened))) { - LOG_WARN("failed to replace assignment exprs", K(ret)); - } else if (table_info.values_desc_.count() == 0) { - // do nothing - } else { - trans_happened |= is_happened; - common::ObIArray &value_vector = table_info.values_vector_; - int64_t column_count = table_info.values_desc_.count(); - int64_t row_count = value_vector.count() / column_count; - - for (int64_t i = 0; OB_SUCC(ret) && i < table_info.column_exprs_.count(); ++i) { - ObColumnRefRawExpr *col = table_info.column_exprs_.at(i); - if (col->is_xml_column()) { - if (OB_FAIL(set_hidd_col_not_null_attr(*col, table_info.column_exprs_))) { - LOG_WARN("failed to set hidden column not null attr", K(ret)); - } - } - } - - for (int64_t i = 0; OB_SUCC(ret) && i < table_info.values_desc_.count(); ++i) { - ObColumnRefRawExpr *value_desc = table_info.values_desc_.at(i); - if (value_desc->is_xml_column()) { - ObColumnRefRawExpr *hidd_col = NULL; - ObRawExpr *new_value_expr = NULL; - ObRawExpr *value_expr = value_vector.at(i); - bool need_transform = false; // not_used - if (OB_FAIL(ObTransformUtils::create_udt_hidden_columns(ctx_, merge_stmt, *value_desc, hidd_col, need_transform))) { - LOG_WARN("failed to create udt hidden exprs", K(ret)); - } else if (need_transform == false) { - // do nothing - } else { - bool hidd_found = false; - for (int64_t j = 0; OB_SUCC(ret) && !hidd_found && j < table_info.column_exprs_.count(); ++j) { - ObColumnRefRawExpr *col = table_info.column_exprs_.at(j); - if (col->get_column_id() == hidd_col->get_column_id()) { - ObRawExpr *old_conv_expr = merge_stmt->get_column_conv_exprs().at(j); - hidd_found = true; - if (OB_FAIL(transform_udt_column_conv_param_expr(table_info, value_expr, new_value_expr))) { - LOG_WARN("failed to transform udt value exprs", K(ret)); - } else if (OB_FAIL(static_cast(old_conv_expr)->replace_param_expr(4, new_value_expr))) { - LOG_WARN("failed to push back udt hidden exprs", K(ret)); - } - } - } - } - } - } - - LOG_TRACE("succeed to do const propagation for assignment expr", K(is_happened)); - } - } else if (stmt->get_stmt_type() == stmt::T_INSERT || stmt->get_stmt_type() == stmt::T_INSERT_ALL) { - ObDelUpdStmt *insert_stmt = static_cast(stmt); - // common::ObIArray &value_vector = insert_stmt->get_values_vector(); - // int64_t column_count = insert_stmt->get_values_desc().count(); - // int64_t row_count = insert_stmt->get_values_vector().count() / column_count; - ObInsertAllStmt *insert_all_stmt = static_cast(stmt); - ObInsertStmt *single_insert_stmt = static_cast(stmt); - common::ObArray table_info_arr; - if (stmt->get_stmt_type() == stmt::T_INSERT) { - table_info_arr.push_back(&(single_insert_stmt->get_insert_table_info())); - } else { - ObIArray &table_infos = insert_all_stmt->get_insert_all_table_info(); - for (int64_t i = 0; i < table_infos.count(); i++) { - table_info_arr.push_back(table_infos.at(i)); - } - } - - for (int64_t count = 0; OB_SUCC(ret) && count < table_info_arr.count(); ++count) { - ObInsertTableInfo *table_info = table_info_arr.at(count); - for (int64_t i = 0; OB_SUCC(ret) && i < table_info->column_exprs_.count(); ++i) { - ObColumnRefRawExpr *col = table_info->column_exprs_.at(i); - if (col->is_xml_column()) { - if (OB_FAIL(set_hidd_col_not_null_attr(*col, table_info->column_exprs_))) { - LOG_WARN("failed to set hidden column not null attr", K(ret)); - } - } - } - - for (int64_t i = 0; OB_SUCC(ret) && i < table_info->values_desc_.count(); ++i) { - ObColumnRefRawExpr *value_desc = table_info->values_desc_.at(i); - if (value_desc->is_xml_column()) { - ObColumnRefRawExpr *hidd_col = NULL; - bool need_transform = false; - if (OB_FAIL(ObTransformUtils::create_udt_hidden_columns(ctx_, - insert_stmt, - *value_desc, - hidd_col, - need_transform))) { - LOG_WARN("failed to create udt hidden exprs", K(ret)); - } else if (need_transform == false) { - // do nothing - } else if (OB_FAIL(transform_udt_column_conv_function(*table_info, - table_info->column_conv_exprs_, - *value_desc, *hidd_col))) { - LOG_WARN("failed to push back column conv exprs", K(ret)); - } - } - } - // process returning exprs - if (OB_SUCC(ret) && insert_stmt->is_returning()) { - ObIArray &column_convert = table_info->column_conv_exprs_; - const ObIArray &table_columns = table_info->column_exprs_; - ObSEArray, 8> xml_col_idxs; // use pair to store xml col idx and its hidden col idx - for (int64_t i = 0; OB_SUCC(ret) && i < table_columns.count(); i++) { - ObColumnRefRawExpr *ref_col = table_columns.at(i); - if (ref_col->is_xml_column()) { - bool is_found = false; - for (int64_t j = 0; OB_SUCC(ret) && !is_found && j < table_columns.count(); j++) { - if (ref_col->get_column_id() != table_columns.at(j)->get_column_id() && - ref_col->get_udt_set_id() == table_columns.at(j)->get_udt_set_id()) { - is_found = true; - xml_col_idxs.push_back(std::make_pair(i, j)); - } - } // end for - if (!is_found) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to find hidden column", K(ret), K(i)); - } - } - } // end for - - CK(column_convert.count() == table_columns.count()); - for (int64_t i = 0; OB_SUCC(ret) && i < insert_stmt->get_returning_exprs().count(); i++) { - for (int64_t j = 0; OB_SUCC(ret) && j < xml_col_idxs.count(); j++) { - ObRawExpr *hidd_col = NULL; - ObRawExpr *sys_makexml_expr = NULL; - if (OB_ISNULL(hidd_col = column_convert.at(xml_col_idxs.at(j).second))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("hidden col is NULL", K(ret), K(i), K(j)); - } else if (OB_FAIL(transform_xml_binary(hidd_col, sys_makexml_expr))) { - LOG_WARN("fail to create expr sys_makexml", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::replace_ref_column(insert_stmt->get_returning_exprs().at(i), - table_columns.at(xml_col_idxs.at(j).first), - sys_makexml_expr))) { - LOG_WARN("fail to replace xml column in returning exprs", K(ret), K(i), K(j)); - } - } - } - } // end if - } - } + } else if (OB_FAIL(ObTransformUdtUtils::transform_udt_dml_stmt(ctx_, stmt, trans_happened))) { + LOG_WARN("failed to do udt dml transform", K(ret)); } return ret; } diff --git a/src/sql/rewrite/ob_transform_pre_process.h b/src/sql/rewrite/ob_transform_pre_process.h index 1049d795e1..0d160e8327 100644 --- a/src/sql/rewrite/ob_transform_pre_process.h +++ b/src/sql/rewrite/ob_transform_pre_process.h @@ -481,23 +481,6 @@ struct DistinctObjMeta int transform_json_object_expr_with_star(const ObIArray &parent_stmts, ObDMLStmt *stmt, bool &trans_happened); int transform_udt_columns(const common::ObIArray &parent_stmts, ObDMLStmt *stmt, bool &trans_happened); - int transform_udt_column_conv_function(ObDmlTableInfo &table_info, - ObIArray &column_conv_exprs, - ObColumnRefRawExpr &udt_col, - ObColumnRefRawExpr &hidd_col); - int transform_udt_column_value_expr_inner(ObDMLStmt *stmt, ObDmlTableInfo &table_info, ObRawExpr *&old_expr, ObRawExpr *hidd_expr = NULL); - int transform_xml_binary(ObRawExpr *hidden_blob_expr, ObRawExpr *&new_expr); - int transform_udt_column_value_expr(ObDMLStmt *stmt, ObDmlTableInfo &table_info, ObRawExpr *old_expr, ObRawExpr *&new_expr, ObRawExpr *hidd_expr = NULL); - int transform_udt_column_conv_param_expr(ObDmlTableInfo &table_info, ObRawExpr *old_expr, ObRawExpr *&new_expr); - int replace_udt_assignment_exprs(ObDMLStmt *stmt, ObDmlTableInfo &table_info, ObIArray &assignments, bool &trans_happened); - int set_hidd_col_not_null_attr(const ObColumnRefRawExpr &udt_col, ObIArray &column_exprs); - int check_skip_child_select_view(const ObIArray &parent_stmts, ObDMLStmt *stmt, bool &skip_for_view_table); - int transform_query_udt_columns_exprs(const ObIArray &parent_stmts, ObDMLStmt *stmt, bool &trans_happened); - int transform_udt_columns_constraint_exprs(ObDMLStmt *stmt, bool &trans_happened); - int get_update_generated_udt_in_parent_stmt(const ObIArray &parent_stmts, const ObDMLStmt *stmt, - ObIArray &col_exprs); - int get_dml_view_col_exprs(const ObDMLStmt *stmt, ObIArray &assign_col_exprs); - /* * following functions are used for transform rowid in subquery */ diff --git a/src/sql/rewrite/ob_transform_udt_utils.cpp b/src/sql/rewrite/ob_transform_udt_utils.cpp new file mode 100644 index 0000000000..80b093495f --- /dev/null +++ b/src/sql/rewrite/ob_transform_udt_utils.cpp @@ -0,0 +1,1108 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX SQL_REWRITE +#include "lib/allocator/ob_allocator.h" +#include "lib/oblog/ob_log_module.h" +#include "common/ob_common_utility.h" +#include "common/ob_smart_call.h" +#include "share/ob_unit_getter.h" +#include "share/schema/ob_column_schema.h" +#include "sql/ob_sql_context.h" +#include "sql/resolver/expr/ob_raw_expr.h" +#include "sql/resolver/expr/ob_raw_expr_util.h" +#include "sql/optimizer/ob_optimizer_util.h" +#include "sql/code_generator/ob_expr_generator_impl.h" +#include "sql/engine/ob_physical_plan.h" +#include "sql/engine/ob_exec_context.h" +#include "sql/engine/ob_physical_plan.h" +#include "sql/engine/expr/ob_expr_xmlparse.h" +#include "sql/session/ob_sql_session_info.h" +#include "share/config/ob_server_config.h" +#include "sql/rewrite/ob_transform_utils.h" +#include "sql/rewrite/ob_transform_udt_utils.h" +#include "sql/resolver/dml/ob_select_stmt.h" +#include "sql/resolver/dml/ob_select_resolver.h" +#include "sql/resolver/dml/ob_dml_stmt.h" +#include "sql/resolver/dml/ob_update_stmt.h" +#include "sql/resolver/dml/ob_insert_all_stmt.h" +#include "sql/resolver/dml/ob_insert_stmt.h" +#include "sql/resolver/dml/ob_merge_stmt.h" +#include "pl/ob_pl_stmt.h" + + +using namespace oceanbase::common; +using namespace oceanbase::share; +using namespace oceanbase::share::schema; +namespace oceanbase +{ +using namespace common; +namespace sql +{ + + +int ObTransformUdtUtils::transform_xml_value_expr_inner(ObTransformerCtx *ctx, ObDMLStmt *stmt, ObDmlTableInfo &table_info, + ObRawExpr *&old_expr) +{ + // replace udt column in value expr + int ret = OB_SUCCESS; + if (old_expr->is_column_ref_expr()) { + ObColumnRefRawExpr *col_ref = static_cast(old_expr); + if (col_ref->is_xml_column()) { + bool need_transform = false; + ObArray hidd_cols; + ObColumnRefRawExpr *hidd_col = NULL; + if (OB_FAIL(ObTransformUdtUtils::create_udt_hidden_columns(ctx, stmt, *col_ref, hidd_cols, need_transform))) { + LOG_WARN("failed to create udt hidden exprs", K(ret)); + } else if (!need_transform) { + // do nothing + } else if (hidd_cols.empty()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("hidden column is null", K(ret)); + } else if (FALSE_IT(hidd_col = hidd_cols.at(0))) { + } else if (!hidd_col->get_result_type().is_blob()) { + // if column is not clob type, don't need add xml_binary + old_expr = hidd_col; + } else if (OB_FAIL(transform_sys_makexml(ctx, hidd_col, old_expr))) { + LOG_WARN("transform xml binary failed", K(ret)); + } + } + } else { + for (int i = 0; i < old_expr->get_param_count() && OB_SUCC(ret); i++) { + if (OB_FAIL(transform_xml_value_expr_inner(ctx, stmt, table_info, old_expr->get_param_expr(i)))) { + LOG_WARN("transform udt column value expr failed", K(ret)); + } + } + } + return ret; +} + +int ObTransformUdtUtils::transform_make_xml_binary(ObTransformerCtx *ctx, ObRawExpr *old_expr, ObRawExpr *&new_expr) +{ + int ret = OB_SUCCESS; + // to do: add SYS_MAKEXMLBinary + ObSysFunRawExpr *make_xml_expr = NULL; + ObConstRawExpr *c_expr = NULL; + if (OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret)); + } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_SYS_PRIV_MAKE_XML_BINARY, make_xml_expr))) { + LOG_WARN("failed to create fun make xml binary expr", K(ret)); + } else if (OB_ISNULL(make_xml_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("xml expr is null", K(ret)); + } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_INT, c_expr))) { + LOG_WARN("create dest type expr failed", K(ret)); + } else if (OB_ISNULL(c_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("const expr is null"); + } else { + ObObj val; + val.set_int(0); + c_expr->set_value(val); + c_expr->set_param(val); + if (OB_FAIL(make_xml_expr->set_param_exprs(c_expr, old_expr))) { + LOG_WARN("set param expr fail", K(ret)); + } else { + make_xml_expr->set_func_name(ObString::make_string("_make_xml_binary")); + if (OB_FAIL(make_xml_expr->formalize(ctx->session_info_))) { + LOG_WARN("make xml epxr formlize fail", K(ret)); + } + new_expr = make_xml_expr; + } + } + return ret; +} + +bool ObTransformUdtUtils::check_assign_value_from_same_table(const ObColumnRefRawExpr &udt_col, + const ObRawExpr &udt_value, + uint64_t &udt_set_id) +{ + bool ret = false; + const ObColumnRefRawExpr *src_expr = ObRawExprUtils::get_column_ref_expr_recursively(udt_value.get_param_expr(4)); + if (OB_NOT_NULL(src_expr) && src_expr->get_table_id() == udt_col.get_table_id() && + src_expr->get_udt_id() == udt_col.get_udt_id()) { + ret = true; + udt_set_id = src_expr->get_udt_set_id(); + } + return ret; +} + +int ObTransformUdtUtils::transform_replace_udt_column_convert_value(ObDmlTableInfo &table_info, + ObIArray &column_exprs, + uint64_t udt_set_id, + ObIArray &column_conv_exprs) +{ + int ret = OB_SUCCESS; + for (int i = 0; i < column_exprs.count() && OB_SUCC(ret); i++) { + ObColumnRefRawExpr *left_expr = column_exprs.at(i); + // get rid of udt column name + ObString left_attr_name; + bool found = false; + for (int j = 0; j < table_info.column_exprs_.count() && OB_SUCC(ret) && !found; j++) { + if (table_info.column_exprs_.at(j)->get_udt_set_id() == udt_set_id) { + ObString qualified_name; + // get rid of udt column name + ObString right_attr_name = qualified_name.after('.'); + if (left_attr_name.case_compare(right_attr_name) == 0) { + found = true; + // found corresponding column + ObRawExpr *new_value_expr = table_info.column_exprs_.at(j); + ObRawExpr *old_conv_expr = column_conv_exprs.at(i); + ObRawExpr *old_col_ref = NULL; + ObRawExpr *cast_expr = NULL; + if (new_value_expr->get_result_type().get_type() != left_expr->get_result_type().get_type()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("expr result type unexpected", K(ret), K(new_value_expr->get_result_type().get_type()), + K(left_expr->get_result_type().get_type())); + } else if (OB_ISNULL(cast_expr = old_conv_expr->get_param_expr(4))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("convert epxr param is null", K(ret)); + } else if (T_FUN_SYS_CAST != cast_expr->get_expr_type()){ + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected expr type", K(ret), K(cast_expr->get_expr_type())); + } else if (FALSE_IT(old_col_ref = old_conv_expr->get_param_expr(4)->get_param_expr(0))) { + } else if (OB_ISNULL(old_col_ref)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("old expr is null", K(ret)); + } else if (OB_FAIL(ObTransformUtils::replace_expr(cast_expr, new_value_expr, old_conv_expr))) { + LOG_WARN("failed to replace column convert expr value", K(ret)); + } + } + } + } + } + return ret; +} + +int ObTransformUdtUtils::transform_udt_column_conv_function(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ObIArray &column_exprs, + ObIArray &column_conv_exprs, + ObColumnRefRawExpr &udt_col, + ObIArray &hidd_cols, + ObRawExpr *value_expr) +{ + int ret = OB_SUCCESS; + if (udt_col.is_xml_column()) { + ObColumnRefRawExpr &hidd_col = *hidd_cols.at(0); + if (OB_FAIL(transform_udt_hidden_column_conv_function_inner(ctx, stmt, column_exprs, column_conv_exprs, + udt_col, hidd_col, 0, OB_INVALID_VERSION, + value_expr))) { + LOG_WARN("failed to transform udt column conv inner", K(ret)); + } + } + return ret; +} + + +int ObTransformUdtUtils::replace_udt_assignment_exprs(ObTransformerCtx *ctx, ObDMLStmt *stmt, ObDmlTableInfo &table_info, + ObIArray &assignments, bool &trans_happened) +{ + int ret = OB_SUCCESS; + trans_happened = false; + + for (int64_t i = 0; OB_SUCC(ret) && i < assignments.count(); ++i) { + ObArrayhidd_cols; + ObRawExpr *value_expr = NULL; + ObRawExpr *udt_conv_expr = NULL; + ObAssignment &assign = assignments.at(i); + bool trigger_exist = false; + if (OB_ISNULL(assign.column_expr_) || OB_ISNULL(assign.expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("assgin expr is null", K(ret)); + } else if (!assign.column_expr_->is_xml_column()) { + // do nothins + } else { + for (int j = 0; j < table_info.column_exprs_.count() && OB_SUCC(ret); j++) { + if (table_info.column_exprs_.at(j)->get_column_id() != assign.column_expr_->get_column_id() && + table_info.column_exprs_.at(j)->get_udt_set_id() == assign.column_expr_->get_udt_set_id()) { + if (OB_FAIL(hidd_cols.push_back(table_info.column_exprs_.at(j)))) { + LOG_WARN("failed to push back hidden exprs", K(ret)); + } + } + } + if (OB_FAIL(ret)) { + } else if (hidd_cols.empty()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("hidden column is null", K(ret)); + } else if (assign.expr_->get_expr_type() == T_FUN_SYS_WRAPPER_INNER) { + trigger_exist = true; + udt_conv_expr = assign.expr_->get_param_expr(0); + } else { + udt_conv_expr = assign.expr_; + } + + if (OB_FAIL(ret)) { + // do nothing + } else if (udt_conv_expr->get_expr_type() != T_FUN_COLUMN_CONV) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpectd expr type", K(ret), K(assign.expr_->get_expr_type())); + } else if (OB_ISNULL(value_expr = udt_conv_expr->get_param_expr(4))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("raw expr param is null"); + } else if (value_expr->get_expr_type() == T_FUN_SYS_CAST) { + // don't need cast expr + value_expr = value_expr->get_param_expr(0); + } else if (value_expr->is_const_raw_expr()) { + if (value_expr->get_expr_type() == T_QUESTIONMARK) { + const ParamStore ¶m_store = ctx->exec_ctx_->get_physical_plan_ctx()->get_param_store(); + ObConstRawExpr *param_expr = static_cast(value_expr); + int64_t param_idx = param_expr->get_value().get_unknown(); + if (param_idx < 0 || param_idx >= param_store.count()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("param_idx is invalid", K(ret), K(param_idx)); + } else if (param_store.at(param_idx).is_xml_sql_type() + || param_store.at(param_idx).is_extend_xml_type()){ + // do nothing + } else if (ob_is_decimal_int_tc(param_store.at(param_idx).get_type()) + || ob_is_number_tc(param_store.at(param_idx).get_type())) { + ret = OB_ERR_INVALID_TYPE_FOR_OP; + LOG_WARN("old_expr_type invalid ObLongTextType type", K(ret), K(param_store.at(param_idx).get_type())); + } else { + ObExprResType res_type; + res_type.set_varchar(); + res_type.set_collation_type(CS_TYPE_UTF8MB4_BIN); + value_expr->set_result_type(res_type); + } + } + } + } + if (OB_SUCC(ret) && assign.column_expr_->is_xml_column()) { + ObRawExpr *new_value_expr = NULL; + ObRawExpr *old_column_expr = assign.column_expr_; + if (OB_FAIL(transform_xml_value_expr_inner(ctx, stmt, table_info, value_expr))) { + LOG_WARN("replace udt column failed", K(ret)); + } else if (OB_FAIL(transform_make_xml_binary(ctx, value_expr, new_value_expr))){ + LOG_WARN("failed to transform udt value exprs", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_column_conv_expr(*ctx->expr_factory_, + *ctx->allocator_, + *hidd_cols.at(0), + new_value_expr, + ctx->session_info_))) { + LOG_WARN("fail to build column conv expr", K(ret), K(hidd_cols.at(0))); + } else { + trans_happened = true; + assign.column_expr_ = hidd_cols.at(0); + if (trigger_exist) { + if (OB_FAIL(static_cast(assign.expr_)->replace_param_expr(0, new_value_expr))) { + LOG_WARN("failed to replace wrapper expr param", K(ret)); + } + } else { + trans_happened = true; + assign.column_expr_ = hidd_cols.at(0); + if (trigger_exist) { + if (OB_FAIL(static_cast(assign.expr_)->replace_param_expr(0, new_value_expr))) { + LOG_WARN("failed to replace wrapper expr param", K(ret)); + } + } else { + assign.expr_ = new_value_expr; + } + } + } + // process returning clause for update + if (OB_SUCC(ret) && stmt->get_stmt_type() == stmt::T_UPDATE) { + ObDelUpdStmt *update_stmt = static_cast(stmt); + if (update_stmt->is_returning()) { + for (int64_t i = 0; OB_SUCC(ret) && i < update_stmt->get_returning_exprs().count(); i++) { + ObRawExpr *sys_makexml_expr = NULL; + if (OB_FAIL(transform_sys_makexml(ctx, new_value_expr, sys_makexml_expr))) { + LOG_WARN("fail to create sys_makexml expr", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::replace_ref_column(update_stmt->get_returning_exprs().at(i), + old_column_expr, + sys_makexml_expr))) { + LOG_WARN("fail to replace xml column in returning exprs", K(ret), K(i)); + } + } // end for + } //end if: process returning clause + } + } + } + + return ret; +} + +int ObTransformUdtUtils::transform_udt_assignments(ObTransformerCtx *ctx, ObDMLStmt *stmt, ObDmlTableInfo &table_info, ObColumnRefRawExpr &udt_col, + ObRawExpr *udt_value, ObArray &hidden_cols, ObIArray &assignments, + ObAssignment &udt_assign) +{ + int ret = OB_SUCCESS; + ObArray col_conv; + ObArray col_exprs; + uint64_t src_udt_set_id = 0; + for (int i = 0; i < hidden_cols.count() && OB_SUCC(ret); i++) { + ObRawExpr *new_value_expr = NULL; + if (OB_FAIL(ObRawExprUtils::build_null_expr(*ctx->expr_factory_, new_value_expr))) { + LOG_WARN("build null expr failed", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::build_column_conv_expr(*ctx->expr_factory_, + *ctx->allocator_, + *hidden_cols.at(i), + new_value_expr, + ctx->session_info_))) { + LOG_WARN("fail to build column conv expr", K(ret), K(hidden_cols.at(i))); + } else if (OB_FAIL(col_conv.push_back(new_value_expr))) { + LOG_WARN("push back udt hidden col conv failed", K(ret)); + } + } + if (OB_FAIL(ret)) { + } else if (check_assign_value_from_same_table(udt_col, *udt_value, src_udt_set_id)) { + if (OB_FAIL(transform_replace_udt_column_convert_value(table_info, hidden_cols, src_udt_set_id, col_conv))) { + LOG_WARN("transform replace udt hidden col conv value failed", K(ret)); + } else { + for (int i = 0; i < hidden_cols.count() && OB_SUCC(ret); i++) { + ObAssignment hidd_assign; + hidd_assign.column_expr_ = hidden_cols.at(i); + hidd_assign.expr_ = col_conv.at(i); + if (OB_FAIL(assignments.push_back(hidd_assign))) { + LOG_WARN("push back udt hidden col assignment failed", K(ret)); + } + } + } + } else if (FALSE_IT(col_exprs = hidden_cols)) { + } else if (OB_FAIL(col_exprs.push_back(&udt_col))) { + LOG_WARN("push back udt col failed", K(ret)); + } else if (OB_FAIL(col_conv.push_back(udt_value))) { + LOG_WARN("push back udt col conv failed", K(ret)); + } else if (OB_FAIL(transform_udt_column_conv_function(ctx, stmt, col_exprs, col_conv, + udt_col, hidden_cols))) { + LOG_WARN("transform udt col conv failed", K(ret)); + } else { + // last column conv expr is udt col conv + uint32_t udt_idx = col_conv.count() - 1; + udt_assign.expr_ = col_conv.at(udt_idx); + for (int i = 0; i < col_exprs.count() - 1 && OB_SUCC(ret); i++) { + ObAssignment hidd_assign; + hidd_assign.column_expr_ = col_exprs.at(i); + hidd_assign.expr_ = col_conv.at(i); + if (OB_FAIL(assignments.push_back(hidd_assign))) { + LOG_WARN("push back udt hidden col assignment failed", K(ret)); + } + } + } + return ret; +} + +int ObTransformUdtUtils::transform_sys_makexml(ObTransformerCtx *ctx, ObRawExpr *hidden_blob_expr, ObRawExpr *&new_expr) +{ + int ret = OB_SUCCESS; + ObSysFunRawExpr *sys_makexml = NULL; + ObConstRawExpr *c_expr = NULL; + ObColumnRefRawExpr *hidd_col = NULL; + if (OB_ISNULL(ctx) || OB_ISNULL(ctx->expr_factory_) || OB_ISNULL(hidden_blob_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected null", K(ret), KP(ctx), KP(hidden_blob_expr)); + } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_FUN_SYS_MAKEXML, sys_makexml))) { + LOG_WARN("failed to create fun sys_makexml expr", K(ret)); + } else if (OB_ISNULL(sys_makexml)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sys_makexml expr is null", K(ret)); + } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_INT, c_expr))) { + LOG_WARN("create dest type expr failed", K(ret)); + } else if (OB_ISNULL(c_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("const expr is null"); + } else { + ObObj val; + val.set_int(0); + c_expr->set_value(val); + c_expr->set_param(val); + if (OB_FAIL(sys_makexml->set_param_exprs(c_expr, hidden_blob_expr))) { + LOG_WARN("set param expr fail", K(ret)); + } else if (FALSE_IT(sys_makexml->set_func_name(ObString::make_string("SYS_MAKEXML")))) { + } else if (OB_FAIL(sys_makexml->formalize(ctx->session_info_))) { + LOG_WARN("failed to formalize", K(ret)); + } else { + new_expr = sys_makexml; + } + } + return ret; +} + +int ObTransformUdtUtils::set_hidd_col_not_null_attr(const ObColumnRefRawExpr &udt_col, ObIArray &column_exprs) +{ + int ret = OB_SUCCESS; + bool found = false; + for (int64_t j = 0; OB_SUCC(ret) && !found && j < column_exprs.count(); ++j) { + ObColumnRefRawExpr *col_hidden = column_exprs.at(j); + if (col_hidden->get_udt_set_id() == udt_col.get_udt_set_id() && + udt_col.get_column_id() != col_hidden->get_column_id()) { + found = true; + if (udt_col.get_result_type().has_result_flag(HAS_NOT_NULL_VALIDATE_CONSTRAINT_FLAG)) { + col_hidden->set_result_flag(HAS_NOT_NULL_VALIDATE_CONSTRAINT_FLAG); + } + if (udt_col.get_result_type().has_result_flag(NOT_NULL_WRITE_FLAG)) { + col_hidden->set_result_flag(NOT_NULL_WRITE_FLAG); + } + } + } + if (!found) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to find hidden column", K(ret), K(udt_col.get_udt_set_id())); + } + return ret; +} + +int ObTransformUdtUtils::get_dml_view_col_exprs(const ObDMLStmt *stmt, ObIArray &assign_col_exprs) +{ + int ret = OB_SUCCESS; + if (stmt->get_stmt_type() == stmt::T_UPDATE) { + const ObUpdateStmt *upd_stmt = static_cast(stmt); + for (int64_t i = 0; OB_SUCC(ret) && i < upd_stmt->get_update_table_info().count(); ++i) { + ObUpdateTableInfo* table_info = upd_stmt->get_update_table_info().at(i); + if (OB_ISNULL(table_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null table info", K(ret)); + } + for (int64_t j = 0; OB_SUCC(ret) && j < table_info->assignments_.count(); ++j) { + ObAssignment &assign = table_info->assignments_.at(j); + if (OB_ISNULL(assign.column_expr_) || OB_ISNULL(assign.expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("assgin expr is null", K(ret)); + } else if (assign.column_expr_->is_xml_column() && + OB_FAIL(add_var_to_array_no_dup(assign_col_exprs, assign.column_expr_))) { + LOG_WARN("failed to push back column expr", K(ret)); + } + } + } + } + return ret; +} + +int ObTransformUdtUtils::create_udt_hidden_columns(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + const ObColumnRefRawExpr &udt_expr, + ObIArray &col_exprs, + bool &need_transform) +{ + int ret = OB_SUCCESS; + const ObTableSchema *table_schema = NULL; + const TableItem *table = NULL; + const ColumnItem *column_item = NULL; + ObArray hidden_cols; + need_transform = false; + bool from_base = false; + bool from_xml = false; + bool view_table_do_transform = (stmt->get_stmt_type() == stmt::T_INSERT || + stmt->get_stmt_type() == stmt::T_UPDATE || + stmt->get_stmt_type() == stmt::T_MERGE); + if (OB_ISNULL(stmt) + || OB_ISNULL(ctx) + || OB_ISNULL(ctx->session_info_) + || OB_ISNULL(ctx->expr_factory_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null unexpected", K(ctx), K(stmt), K(ret)); + } else if (OB_ISNULL(table = stmt->get_table_item_by_id(udt_expr.get_table_id()))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to get table item", K(udt_expr.get_table_id()), K(ret)); + } else if (table->is_view_table_ && (!view_table_do_transform)) { + // do nothing. + LOG_INFO("udt columns in views does not need transfrom", K(udt_expr.get_table_id()), K(table)); + } else if (table->is_view_table_ && table->view_base_item_ == NULL) { + // do nothing + } else if (OB_FAIL(ctx->schema_checker_->get_table_schema(ctx->session_info_->get_effective_tenant_id(), + table->ref_id_, table_schema))) { + if (((table->is_generated_table() || table->is_temp_table()) && OB_NOT_NULL(table->ref_query_)) + || (table->is_json_table() && (OB_NOT_NULL(table->json_table_def_)))) { + // situation for select a from (select xmltype('') a from dual ) + LOG_INFO("table schema not found for tmp view does not need transfrom", K(ret), KPC(table)); + ret = OB_SUCCESS; + } else if (table->is_function_table()) { + // xml table don't do transform + ret = OB_SUCCESS; + } else { + LOG_WARN("failed to get table schema", K(ret)); + } + } else if (OB_ISNULL(table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table should not be null", K(table->ref_id_)); + } else { + if (table->is_view_table_ && view_table_do_transform) { + // for view table, we should check col group in base table + const ObTableSchema *base_table_schema = NULL; + from_base = true; + if (table->view_base_item_ == NULL) { + // do nothing or return error + } else { + ObSelectStmt *real_stmt = NULL; + if (OB_ISNULL(real_stmt = table->ref_query_->get_real_stmt())) { + // case : view definition is set_op + // Bug : + ret = OB_ERR_UNEXPECTED; + LOG_WARN("real stmt is NULL", K(ret)); + } else { + SelectItem &t_col = real_stmt->get_select_item((udt_expr.get_column_id() - OB_APP_MIN_COLUMN_ID)); + + if (t_col.expr_->get_expr_type() == T_FUN_SYS_MAKEXML) { // xmltype special case + if (t_col.expr_->get_param_count() != 2) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid xml generated table column", K(ret), K(t_col.expr_)); + } else if (!t_col.expr_->get_param_expr(1)->is_column_ref_expr()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid xml generated table column", K(ret), K(t_col.expr_->get_param_expr(1)->is_column_ref_expr())); + } else { + from_xml = true; + ObColumnRefRawExpr* col_expr = static_cast(t_col.expr_->get_param_expr(1)); + column_item = stmt->get_column_item_by_base_id(table->table_id_, col_expr->get_column_id()); + if (OB_NOT_NULL(column_item)) { + if (OB_ISNULL(column_item->expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column item expr is null", K(ret)); + } else { + col_expr = column_item->expr_; + need_transform = true; + } + } else { + ColumnItem column_item; + column_item.expr_ = col_expr; + column_item.table_id_ = col_expr->get_table_id(); + column_item.column_id_ = col_expr->get_column_id(); + column_item.column_name_ = col_expr->get_column_name(); + if (OB_FAIL(stmt->add_column_item(column_item))) { + LOG_WARN("add column item to stmt failed", K(ret)); + } else { + need_transform = true; + } + } + if (OB_SUCC(ret) && OB_FAIL(col_exprs.push_back(col_expr))) { + LOG_WARN("add column ref to array failed", K(ret)); + } + } + } else if (t_col.expr_->get_expr_type() == T_REF_COLUMN) { + int64_t col_id = dynamic_cast(t_col.expr_)->get_column_id(); + if (OB_FAIL(ctx->schema_checker_->get_table_schema(ctx->session_info_->get_effective_tenant_id(), + table->view_base_item_->ref_id_, base_table_schema))) { + LOG_WARN("failed to get table schema", K(ret)); + } else if (OB_ISNULL(base_table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table should not be null", K(table->view_base_item_->ref_id_)); + } else if (OB_FAIL(base_table_schema->get_column_schema_in_same_col_group(col_id, + udt_expr.get_udt_set_id(), + hidden_cols))) { + LOG_WARN("failed to get column schema", K(ret)); + } + } else { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid view column type", K(ret), K(t_col.expr_)); + } + } + } + } else if (OB_FAIL(table_schema->get_column_schema_in_same_col_group(udt_expr.get_column_id(), + udt_expr.get_udt_set_id(), + hidden_cols))) { + LOG_WARN("failed to get column schema", K(ret)); + } else if (udt_expr.is_xml_column() && hidden_cols.count() != 1) { + // xmltype only 1 hidden column currently + ret = OB_ERR_UNEXPECTED; + LOG_WARN("hidden cols count is not expected", K(table->ref_id_), K(hidden_cols.count())); + } + if (OB_SUCC(ret) && !from_xml) { + for (uint32_t i = 0; i < hidden_cols.count() && OB_SUCC(ret); i++) { + ObColumnRefRawExpr* col_expr = NULL; + if (from_base) { + column_item = stmt->get_column_item_by_base_id(table->table_id_, hidden_cols.at(i)->get_column_id()); + } else { + column_item = stmt->get_column_item(table->table_id_, hidden_cols.at(i)->get_column_id()); + } + + if (OB_NOT_NULL(column_item)) { + if (OB_ISNULL(column_item->expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column item expr is null", K(ret)); + } else { + col_expr = column_item->expr_; + need_transform = true; + } + } else if (OB_FAIL(ObRawExprUtils::build_column_expr(*ctx->expr_factory_, *hidden_cols.at(i), col_expr))) { + LOG_WARN("build column expr failed", K(ret)); + } else if (OB_ISNULL(col_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to create raw expr for dummy output", K(ret)); + } else { + col_expr->set_table_id(table->table_id_); + col_expr->set_explicited_reference(); + col_expr->set_column_attr(udt_expr.get_table_name(), col_expr->get_column_name()); + ColumnItem column_item; + column_item.expr_ = col_expr; + column_item.table_id_ = col_expr->get_table_id(); + column_item.column_id_ = col_expr->get_column_id(); + column_item.column_name_ = col_expr->get_column_name(); + if (OB_FAIL(stmt->add_column_item(column_item))) { + LOG_WARN("add column item to stmt failed", K(ret)); + } else { + need_transform = true; + } + } + if (OB_SUCC(ret) && OB_FAIL(col_exprs.push_back(col_expr))) { + LOG_WARN("add column ref to array failed", K(ret)); + } + } + } + } + return ret; +} + +int ObTransformUdtUtils::get_update_generated_udt_in_parent_stmt(const ObIArray &parent_stmts, + const ObDMLStmt *stmt, + ObIArray &col_exprs) +{ + int ret = OB_SUCCESS; + + const ObDMLStmt *root_stmt = NULL; + ObSEArray parent_col_exprs; + const ObSelectStmt *sel_stmt = NULL; + const ObDMLStmt *parent_stmt = NULL; + int64_t table_id = OB_INVALID; + bool is_valid = false; + if (OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null stmt", K(ret)); + } else if (!stmt->is_select_stmt() || parent_stmts.empty()) { + //do nothing + } else if (OB_FALSE_IT(sel_stmt = static_cast(stmt))) { + } else if (OB_ISNULL(root_stmt = parent_stmts.at(parent_stmts.count()-1).stmt_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to get parent stmt", K(ret)); + } else if (OB_FAIL(ObTransformUtils::get_parent_stmt(root_stmt, stmt, parent_stmt, table_id, is_valid))) { + LOG_WARN("failed to get parent stmt", K(ret)); + } else if (!is_valid) { + //do nothing + } else if (OB_ISNULL(parent_stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null stmt", K(ret)); + } else if (OB_FAIL(get_dml_view_col_exprs(parent_stmt, parent_col_exprs))) { + LOG_WARN("failed to get assignment columns", K(ret)); + } else if (!parent_col_exprs.empty()) { + for (int64_t i = 0; OB_SUCC(ret) && i < parent_col_exprs.count(); ++i) { + ObColumnRefRawExpr* col = parent_col_exprs.at(i); + int64_t sel_idx = -1; + if (OB_ISNULL(col)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null column expr", K(ret)); + } else if (OB_FALSE_IT(sel_idx = col->get_column_id() - OB_APP_MIN_COLUMN_ID)) { + } else if (sel_idx < 0 || sel_idx >= sel_stmt->get_select_item_size()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("select item index is incorrect", K(sel_idx), K(ret)); + } else { + ObRawExpr *sel_expr = sel_stmt->get_select_item(sel_idx).expr_; + ObColumnRefRawExpr *col_expr = NULL; + if (OB_ISNULL(sel_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null expr", K(ret)); + } else if (!sel_expr->is_column_ref_expr()) { + //do nothing + } else if (OB_FALSE_IT(col_expr = static_cast(sel_expr))) { + } else if (OB_FAIL(add_var_to_array_no_dup(col_exprs, col_expr))) { + LOG_WARN("failed to push back column expr", K(ret)); + } + } + } + } + return ret; +} + +int ObTransformUdtUtils::check_skip_child_select_view(const ObIArray &parent_stmts, + ObDMLStmt *stmt, bool &skip_for_view_table) +{ + int ret = OB_SUCCESS; + const ObSelectStmt *sel_stmt = NULL; + const ObDMLStmt *parent_stmt = NULL; + bool is_valid = false; + if (OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpect null stmt", K(ret)); + } else if (!stmt->is_select_stmt() || parent_stmts.count() != 1 || + stmt->get_table_size() != 1) { + //do nothing + } else if (OB_FALSE_IT(sel_stmt = static_cast(stmt))) { + } else if (OB_ISNULL(parent_stmt = parent_stmts.at(0).stmt_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to get parent stmt", K(ret)); + } else if (parent_stmt->get_table_size() != 1 || + !(parent_stmt->is_delete_stmt() || parent_stmt->is_update_stmt())) { + // do nothing + } else { + const sql::TableItem *basic_table_item = stmt->get_table_item(0); + const sql::TableItem *view_table_item = parent_stmt->get_table_item(0); + if (OB_ISNULL(basic_table_item) || OB_ISNULL(view_table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to get table item", K(ret)); + } else if (basic_table_item->is_basic_table() && view_table_item->is_generated_table()) { + if (OB_NOT_NULL(view_table_item->ref_query_) && + view_table_item->ref_query_->get_table_size() > 0 && + OB_NOT_NULL(view_table_item->ref_query_->get_table_item(0)) && + basic_table_item->table_id_ == view_table_item->ref_query_->get_table_item(0)->table_id_) { + skip_for_view_table = true; + } + } else if (!basic_table_item->is_basic_table() || !view_table_item->is_view_table_) { + // do nothing + } else if (OB_ISNULL(view_table_item->view_base_item_)) { + // do nothing + } else if (basic_table_item->table_id_ == view_table_item->view_base_item_->table_id_) { + skip_for_view_table = true; + } + } + return ret; +} + +int ObTransformUdtUtils::transform_query_udt_columns_exprs(ObTransformerCtx *ctx, const ObIArray &parent_stmts, + ObDMLStmt *stmt, bool &trans_happened) +{ + int ret = OB_SUCCESS; + ObSEArray scopes; + ObSEArray replace_exprs; + ObSEArray from_col_exprs; + ObSEArray to_col_exprs; + ObSEArray parent_assign_xml_col_exprs; + bool skip_for_view_table = false; + + if (OB_FAIL(get_update_generated_udt_in_parent_stmt(parent_stmts, stmt, parent_assign_xml_col_exprs))) { + LOG_WARN("Fail to get update generated column array.", K(ret)); + } else if (OB_FAIL(check_skip_child_select_view(parent_stmts, stmt, skip_for_view_table))) { + LOG_WARN("Fail to check if select in delete view.", K(ret)); + } else if (skip_for_view_table) { + // do nothing + } else { + FastUdtExprChecker expr_checker(replace_exprs); + if (OB_FAIL(scopes.push_back(SCOPE_DML_COLUMN)) || + (stmt->get_stmt_type() != stmt::T_MERGE && OB_FAIL(scopes.push_back(SCOPE_DML_VALUE))) || + OB_FAIL(scopes.push_back(SCOPE_DML_CONSTRAINT)) || + OB_FAIL(scopes.push_back(SCOPE_INSERT_DESC)) || + OB_FAIL(scopes.push_back(SCOPE_BASIC_TABLE)) || + OB_FAIL(scopes.push_back(SCOPE_DICT_FIELDS)) || + OB_FAIL(scopes.push_back(SCOPE_SHADOW_COLUMN)) || + ((stmt->get_stmt_type() == stmt::T_INSERT || stmt->get_stmt_type() == stmt::T_UPDATE) && + OB_FAIL(scopes.push_back(SCOPE_RETURNING))) || + (stmt->get_stmt_type() != stmt::T_MERGE && OB_FAIL(scopes.push_back(SCOPE_INSERT_VECTOR)))) { + LOG_WARN("Fail to create scope array.", K(ret)); + } + ObStmtExprGetter visitor; + visitor.checker_ = &expr_checker; + visitor.remove_scope(scopes); + if (OB_SUCC(ret) && OB_FAIL(stmt->iterate_stmt_expr(visitor))) { + LOG_WARN("get relation exprs failed", K(ret)); + } + + //collect query udt exprs which need to be replaced + for (int64_t i = 0; OB_SUCC(ret) && i < replace_exprs.count(); i++) { + if (OB_ISNULL(replace_exprs.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("replace expr is null", K(ret)); + } else { + ObColumnRefRawExpr *col_expr = static_cast(replace_exprs.at(i)); + ObArray hidd_cols; + ObRawExpr *sys_makexml_expr = NULL; + bool need_transform = false; + if (!col_expr->is_xml_column() || has_exist_in_array(parent_assign_xml_col_exprs, col_expr)) { + // do nothing + } else if (OB_FAIL(ObTransformUdtUtils::create_udt_hidden_columns(ctx, stmt, *col_expr, hidd_cols, need_transform))) { + LOG_WARN("failed to create udt hidden exprs", K(ret)); + } else if (need_transform == false) { + // do nothing + } else if (OB_FAIL(transform_sys_makexml(ctx, hidd_cols.at(0), sys_makexml_expr))) { + LOG_WARN("failed to transform make_xml exprs", K(ret)); + } else if (OB_FAIL(from_col_exprs.push_back(col_expr))) { + LOG_WARN("failed to push back udt exprs", K(ret)); + } else if (OB_FAIL(to_col_exprs.push_back(sys_makexml_expr))) { + LOG_WARN("failed to push back udt hidden exprs", K(ret)); + } + } + + //do replace + if (OB_SUCC(ret) && !from_col_exprs.empty()) { + ObStmtExprReplacer replacer; + replacer.remove_scope(scopes); + if (OB_FAIL(replacer.add_replace_exprs(from_col_exprs, to_col_exprs))) { + LOG_WARN("failed to add replace exprs", K(ret)); + } else if (OB_FAIL(stmt->iterate_stmt_expr(replacer))) { + LOG_WARN("failed to iterate stmt expr", K(ret)); + } else { + trans_happened = true; + } + } + } + } + + return ret; +} + + +int ObTransformUdtUtils::transform_udt_columns_constraint_exprs(ObTransformerCtx *ctx, ObDMLStmt *stmt, bool &trans_happened) +{ + int ret = OB_SUCCESS; + ObSEArray scopes; + ObSEArray replace_exprs; + ObSEArray from_col_exprs; + ObSEArray to_col_exprs; + FastUdtExprChecker expr_checker(replace_exprs); + ObStmtExprGetter visitor; + visitor.remove_all(); + visitor.add_scope(SCOPE_DML_CONSTRAINT); + visitor.checker_ = &expr_checker; + + if (OB_SUCC(ret) && OB_FAIL(stmt->iterate_stmt_expr(visitor))) { + LOG_WARN("get relation exprs failed", K(ret)); + } + + //collect query udt exprs which need to be replaced + for (int64_t i = 0; OB_SUCC(ret) && i < replace_exprs.count(); i++) { + if (OB_ISNULL(replace_exprs.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("replace expr is null", K(ret)); + } else { + ObColumnRefRawExpr *col_expr = static_cast(replace_exprs.at(i)); + ObArray hidd_cols; + ObRawExpr *sys_makexml_expr = NULL; + bool need_transform = false; + if (!col_expr->is_xml_column()) { + // do nothing + } else if (OB_FAIL(ObTransformUdtUtils::create_udt_hidden_columns(ctx, + stmt, + *col_expr, + hidd_cols, + need_transform))) { + LOG_WARN("failed to create udt hidden exprs", K(ret)); + } else if (need_transform == false) { + // do nothing; + } else if (OB_FAIL(transform_sys_makexml(ctx, hidd_cols.at(0), sys_makexml_expr))) { + LOG_WARN("failed to transform make_xml exprs", K(ret)); + } else if (OB_FAIL(from_col_exprs.push_back(col_expr))) { + LOG_WARN("failed to push back udt exprs", K(ret)); + } else if (OB_FAIL(to_col_exprs.push_back(sys_makexml_expr))) { + LOG_WARN("failed to push back udt hidden exprs", K(ret)); + } + } + } + + //do replace + if (OB_SUCC(ret) && !from_col_exprs.empty()) { + ObStmtExprReplacer replacer; + replacer.remove_all(); + replacer.add_scope(SCOPE_DML_CONSTRAINT); + if (OB_FAIL(replacer.add_replace_exprs(from_col_exprs, to_col_exprs))) { + LOG_WARN("failed to add replace exprs", K(ret)); + } else if (OB_FAIL(stmt->iterate_stmt_expr(replacer))) { + LOG_WARN("failed to iterate stmt expr", K(ret)); + } else { + trans_happened = true; + } + } + return ret; +} + +int ObTransformUdtUtils::transform_udt_hidden_column_conv_function_inner(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ObIArray &column_exprs, + ObIArray &column_conv_exprs, + ObColumnRefRawExpr &udt_col, + ObColumnRefRawExpr &targe_col, + uint32_t attr_idx, + int64_t schema_version, + ObRawExpr *udt_value) +{ + int ret = OB_SUCCESS; + bool hidd_found = false; + for (int64_t j = 0; OB_SUCC(ret) && !hidd_found && j < column_exprs.count(); ++j) { + ObColumnRefRawExpr *col = column_exprs.at(j); + if (col->get_column_id() == targe_col.get_column_id()) { + ObRawExpr *old_conv_expr = column_conv_exprs.at(j); + ObRawExpr *old_col_ref = NULL; + ObRawExpr *cast_expr = NULL; + if (udt_col.is_xml_column()) { + if (OB_NOT_NULL(udt_value)) { + old_col_ref = udt_value; + } else { + const ObColumnRefRawExpr *tmp = ObRawExprUtils::get_column_ref_expr_recursively(old_conv_expr->get_param_expr(4)); + old_col_ref = const_cast(static_cast(tmp)); + } + } else if (OB_NOT_NULL(cast_expr = old_conv_expr->get_param_expr(4))) { + if (T_FUN_SYS_CAST != cast_expr->get_expr_type()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected expr type", K(ret), K(cast_expr->get_expr_type())); + } else { + old_col_ref = old_conv_expr->get_param_expr(4)->get_param_expr(0); + } + } + hidd_found = true; + ObRawExpr *new_value_expr = NULL; + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(old_col_ref)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("old expr is null", K(ret)); + } else if (udt_col.is_xml_column()) { + if (OB_FAIL(transform_make_xml_binary(ctx, old_col_ref, new_value_expr))) { + LOG_WARN("failed to transform udt value exprs", K(ret)); + } else if (OB_FAIL(static_cast(old_conv_expr)->replace_param_expr(4, new_value_expr))) { + LOG_WARN("failed to push back udt hidden exprs", K(ret)); + } + } + } + } + return ret; +} + +int ObTransformUdtUtils::transform_returning_exprs(ObTransformerCtx *ctx, ObDelUpdStmt *stmt, ObInsertTableInfo *table_info) +{ + int ret = OB_SUCCESS; + if (stmt->is_returning()) { + ObIArray &column_convert = table_info->column_conv_exprs_; + const ObIArray &table_columns = table_info->column_exprs_; + ObSEArray, 8> xml_col_idxs; // use pair to store xml col idx and its hidden col idx + for (int64_t i = 0; OB_SUCC(ret) && i < table_columns.count(); i++) { + ObColumnRefRawExpr *ref_col = table_columns.at(i); + if (ref_col->is_xml_column()) { + bool is_found = false; + for (int64_t j = 0; OB_SUCC(ret) && !is_found && j < table_columns.count(); j++) { + if (ref_col->get_column_id() != table_columns.at(j)->get_column_id() && + ref_col->get_udt_set_id() == table_columns.at(j)->get_udt_set_id()) { + is_found = true; + xml_col_idxs.push_back(std::make_pair(i, j)); + } + } // end for + if (!is_found) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to find hidden column", K(ret), K(i)); + } + } + } // end for + + CK(column_convert.count() == table_columns.count()); + for (int64_t i = 0; OB_SUCC(ret) && i < stmt->get_returning_exprs().count(); i++) { + for (int64_t j = 0; OB_SUCC(ret) && j < xml_col_idxs.count(); j++) { + ObRawExpr *hidd_col = NULL; + ObRawExpr *sys_makexml_expr = NULL; + if (OB_ISNULL(hidd_col = column_convert.at(xml_col_idxs.at(j).second))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("hidden col is NULL", K(ret), K(i), K(j)); + } else if (OB_FAIL(ObTransformUdtUtils::transform_sys_makexml(ctx, hidd_col, sys_makexml_expr))) { + LOG_WARN("fail to create expr sys_makexml", K(ret)); + } else if (OB_FAIL(ObRawExprUtils::replace_ref_column(stmt->get_returning_exprs().at(i), + table_columns.at(xml_col_idxs.at(j).first), + sys_makexml_expr))) { + LOG_WARN("fail to replace xml column in returning exprs", K(ret), K(i), K(j)); + } + } + } + } + return ret; +} + +bool ObTransformUdtUtils::is_in_values_desc(const uint64_t column_id, const ObInsertTableInfo &table_info, uint64_t &idx) +{ + bool bRet = false; + ObColumnRefRawExpr *expr = nullptr; + for (int64_t i = 0; !bRet && i < table_info.values_desc_.count(); i++) { + ObColumnRefRawExpr *expr = table_info.values_desc_.at(i); + if (column_id == expr->get_column_id()) { + bRet = true; + idx = i; + } + } + return bRet; +} + +int ObTransformUdtUtils::transform_udt_dml_stmt(ObTransformerCtx *ctx, ObDMLStmt *stmt, bool &trans_happened) +{ + int ret = OB_SUCCESS; + stmt::StmtType type = stmt->get_stmt_type(); + common::ObArray table_info_assign; + common::ObArray table_info_insert; + + if (type == stmt::T_UPDATE) { + ObUpdateStmt *upd_stmt = static_cast(stmt); + for (int64_t i = 0; OB_SUCC(ret) && i < upd_stmt->get_update_table_info().count(); ++i) { + if (OB_FAIL(table_info_assign.push_back(upd_stmt->get_update_table_info().at(i)))) { + LOG_WARN("failed to push table info", K(ret)); + } + } + } else if (type == stmt::T_MERGE) { + ObMergeStmt *merge_stmt = static_cast(stmt); + if (OB_FAIL(table_info_assign.push_back(&merge_stmt->get_merge_table_info()))) { + LOG_WARN("failed to push table info", K(ret)); + } else if (OB_FAIL(table_info_insert.push_back(&merge_stmt->get_merge_table_info()))) { + LOG_WARN("failed to push table info", K(ret)); + } + } else if (type == stmt::T_INSERT) { + ObInsertStmt *insert_stmt = static_cast(stmt); + if (OB_FAIL(table_info_insert.push_back(&insert_stmt->get_insert_table_info()))) { + LOG_WARN("failed to push table info", K(ret)); + } + } else if (type == stmt::T_INSERT_ALL) { + ObInsertAllStmt *insert_all_stmt = static_cast(stmt); + ObIArray &table_infos = insert_all_stmt->get_insert_all_table_info(); + for (int64_t i = 0; i < table_infos.count(); i++) { + if (OB_FAIL(table_info_insert.push_back(table_infos.at(i)))) { + LOG_WARN("failed to push table info", K(ret)); + } + } + } + + for (int64_t i = 0; OB_SUCC(ret) && i < table_info_assign.count(); ++i) { + bool is_happened = false; + ObDmlTableInfo* table_info = table_info_assign.at(i); + if (OB_ISNULL(table_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get null table info", K(ret)); + } else if (OB_FAIL(replace_udt_assignment_exprs(ctx, stmt, *table_info, + type == stmt::T_UPDATE ? + static_cast(table_info)->assignments_ : + static_cast(table_info)->assignments_, + is_happened))) { + LOG_WARN("failed to replace assignment exprs", K(ret)); + } else { + trans_happened |= is_happened; + LOG_TRACE("succeed to do const propagation for assignment expr", K(is_happened)); + } + } + + for (int64_t count = 0; OB_SUCC(ret) && count < table_info_insert.count(); ++count) { + ObInsertTableInfo *table_info = table_info_insert.at(count); + for (int64_t i = 0; OB_SUCC(ret) && i < table_info->column_exprs_.count(); ++i) { + ObColumnRefRawExpr *col = table_info->column_exprs_.at(i); + if (col->is_xml_column()) { + if (OB_FAIL(set_hidd_col_not_null_attr(*col, table_info->column_exprs_))) { + LOG_WARN("failed to set hidden column not null attr", K(ret)); + } + } + } + + for (int64_t i = 0; OB_SUCC(ret) && i < table_info->column_exprs_.count() && i < table_info->column_conv_exprs_.count(); ++i) { + ObRawExpr *value_expr = NULL; + uint64_t value_idx = 0; + ObColumnRefRawExpr *col = table_info->column_exprs_.at(i); + bool is_in_values = is_in_values_desc(col->get_column_id(), *table_info, value_idx); + if (col->is_xml_column() && is_in_values) { + ObArray hidd_cols; + bool need_transform = false; + if (OB_FAIL(ObTransformUdtUtils::create_udt_hidden_columns(ctx, stmt, *col, hidd_cols, need_transform))) { + LOG_WARN("failed to create udt hidden exprs", K(ret)); + } else if (need_transform == false) { + // do nothing + } else if (type == stmt::T_MERGE && is_in_values && + FALSE_IT(value_expr = table_info->values_vector_.at(value_idx))) { + } else if (OB_FAIL(transform_udt_column_conv_function(ctx, stmt, + table_info->column_exprs_, + table_info->column_conv_exprs_, + *col, hidd_cols, value_expr))) { + LOG_WARN("failed to push back column conv exprs", K(ret)); + } + } + } + // process returning exprs + if (OB_SUCC(ret) && OB_FAIL(transform_returning_exprs(ctx, static_cast(stmt), table_info))) { + LOG_WARN("failed to transform returning exprs", K(ret)); + } + } + return ret; +} + +} // end namespace sql +} // end namespace oceanbase \ No newline at end of file diff --git a/src/sql/rewrite/ob_transform_udt_utils.h b/src/sql/rewrite/ob_transform_udt_utils.h new file mode 100644 index 0000000000..ccf4f4ce39 --- /dev/null +++ b/src/sql/rewrite/ob_transform_udt_utils.h @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OB_TRANSFORM_UDT_UTILS_H_ +#define OB_TRANSFORM_UDT_UTILS_H_ + +#include "sql/rewrite/ob_transform_rule.h" +#include "sql/resolver/dml/ob_select_stmt.h" +#include "sql/resolver/dml/ob_merge_stmt.h" +#include "sql/rewrite/ob_transform_utils.h" +#include "sql/ob_sql_context.h" + +namespace oceanbase +{ + +namespace sql +{ + +class ObTransformUdtUtils +{ +public: + static int transform_query_udt_columns_exprs(ObTransformerCtx *ctx, const ObIArray &parent_stmts, ObDMLStmt *stmt, bool &trans_happened); + static int transform_udt_columns_constraint_exprs(ObTransformerCtx *ctx, ObDMLStmt *stmt, bool &trans_happened); + static int transform_udt_dml_stmt(ObTransformerCtx *ctx, ObDMLStmt *stmt, bool &trans_happened); +private: + static int transform_udt_column_conv_function(ObTransformerCtx *ctx, ObDMLStmt *stmt, + ObIArray &column_exprs, + ObIArray &column_conv_exprs, + ObColumnRefRawExpr &udt_col, + ObIArray &hidd_cols, + ObRawExpr *value_expr = NULL); + static int transform_sys_makexml(ObTransformerCtx *ctx, ObRawExpr *hidden_blob_expr, ObRawExpr *&new_expr); + static int replace_udt_assignment_exprs(ObTransformerCtx *ctx, ObDMLStmt *stmt, ObDmlTableInfo &table_info, + ObIArray &assignments, bool &trans_happened); + static int set_hidd_col_not_null_attr(const ObColumnRefRawExpr &udt_col, ObIArray &column_exprs); + static int transform_returning_exprs(ObTransformerCtx *ctx, ObDelUpdStmt *stmt, ObInsertTableInfo *table_info); + static bool is_in_values_desc(const uint64_t column_id, const ObInsertTableInfo &table_info, uint64_t &idx); + static int transform_replace_udt_column_convert_value(ObDmlTableInfo &table_info, + ObIArray &column_exprs, + uint64_t udt_set_id, + ObIArray &column_conv_exprs); + static bool check_assign_value_from_same_table(const ObColumnRefRawExpr &udt_col, const ObRawExpr &udt_value, uint64_t &udt_set_id); + static int transform_xml_value_expr_inner(ObTransformerCtx *ctx, ObDMLStmt *stmt, ObDmlTableInfo &table_info, ObRawExpr *&old_expr); + static int transform_udt_hidden_column_conv_function_inner(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ObIArray &column_exprs, + ObIArray &column_conv_exprs, + ObColumnRefRawExpr &udt_col, + ObColumnRefRawExpr &targe_col, + uint32_t attr_idx = 0, + int64_t schema_version = OB_INVALID_VERSION, + ObRawExpr *udt_value = NULL); + static int transform_make_xml_binary(ObTransformerCtx *ctx, ObRawExpr *old_expr, ObRawExpr *&new_expr); + static int transform_udt_assignments(ObTransformerCtx *ctx, ObDMLStmt *stmt, ObDmlTableInfo &table_info, + ObColumnRefRawExpr &udt_col, ObRawExpr *udt_value, + common::ObArray &hidden_cols, ObIArray &assignments, + ObAssignment &udt_assign); + static int check_skip_child_select_view(const ObIArray &parent_stmts, ObDMLStmt *stmt, bool &skip_for_view_table); + static int get_update_generated_udt_in_parent_stmt(const ObIArray &parent_stmts, const ObDMLStmt *stmt, + ObIArray &col_exprs); + static int get_dml_view_col_exprs(const ObDMLStmt *stmt, ObIArray &assign_col_exprs); + static int create_udt_hidden_columns(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + const ObColumnRefRawExpr &udt_expr, + ObIArray &col_exprs, + bool &need_transform); + +}; + +} +} + +#endif /* OB_TRANSFORM_PRE_PROCESS_H_ */ \ No newline at end of file diff --git a/src/sql/rewrite/ob_transform_utils.cpp b/src/sql/rewrite/ob_transform_utils.cpp index ca7b9f2427..7c0cff9801 100644 --- a/src/sql/rewrite/ob_transform_utils.cpp +++ b/src/sql/rewrite/ob_transform_utils.cpp @@ -2923,6 +2923,10 @@ int ObTransformUtils::get_simple_filter_column(const ObDMLStmt *stmt, case T_FUN_SYS_ST_DWITHIN: case T_FUN_SYS_ST_WITHIN: case T_FUN_SYS_ST_CONTAINS: + case T_FUN_SYS_PRIV_ST_EQUALS: + case T_FUN_SYS_PRIV_ST_TOUCHES: + case T_FUN_SYS_ST_CROSSES: + case T_FUN_SYS_ST_OVERLAPS: { ObRawExpr *left = NULL; ObRawExpr *right = NULL; @@ -12175,6 +12179,8 @@ int ObTransformUtils::extract_udt_exprs(ObRawExpr *expr, ObIArray & if (OB_ISNULL(expr)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected null", K(ret), K(expr)); + } else if (expr->get_expr_type() == T_FUN_SYS_PRIV_SQL_UDT_CONSTRUCT) { + // do nothing } else if (expr->is_column_ref_expr()) { ObColumnRefRawExpr *col_expr = static_cast(expr); if (ob_is_extend(col_expr->get_data_type()) @@ -14020,152 +14026,6 @@ int ObTransformUtils::expand_wild_star_to_columns(ObTransformerCtx *ctx, return ret; } -int ObTransformUtils::create_udt_hidden_columns(ObTransformerCtx *ctx, - ObDMLStmt *stmt, - const ObColumnRefRawExpr &udt_expr, - ObColumnRefRawExpr *&col_expr, - bool &need_transform) -{ - int ret = OB_SUCCESS; - const ObTableSchema *table_schema = NULL; - const TableItem *table = NULL; - col_expr = NULL; - const ColumnItem *column_item = NULL; - ObSEArray hidden_cols; - need_transform = false; - bool from_base = false; - bool from_xml = false; - bool view_table_do_transform = (stmt->get_stmt_type() == stmt::T_INSERT || - stmt->get_stmt_type() == stmt::T_UPDATE || - stmt->get_stmt_type() == stmt::T_MERGE); - if (OB_ISNULL(stmt) - || OB_ISNULL(ctx) - || OB_ISNULL(ctx->session_info_) - || OB_ISNULL(ctx->expr_factory_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("null unexpected", K(ctx), K(stmt), K(ret)); - } else if (OB_ISNULL(table = stmt->get_table_item_by_id(udt_expr.get_table_id()))) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to get table item", K(udt_expr.get_table_id()), K(ret)); - } else if (table->is_view_table_ && (!view_table_do_transform)) { - // do nothing. - LOG_INFO("udt columns in views does not need transfrom", K(udt_expr.get_table_id()), K(table)); - } else if (table->is_view_table_ && table->view_base_item_ == NULL) { - // do nothing - } else if (OB_FAIL(ctx->schema_checker_->get_table_schema(ctx->session_info_->get_effective_tenant_id(), - table->ref_id_, table_schema))) { - if ((table->is_generated_table() || table->is_temp_table()) && OB_NOT_NULL(table->ref_query_)) { - // situation for select a from (select xmltype('') a from dual ) - LOG_INFO("table schema not found for tmp view does not need transfrom", K(ret), KPC(table)); - ret = OB_SUCCESS; - } else { - LOG_WARN("failed to get table schema", K(ret)); - } - } else if (OB_ISNULL(table_schema)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("table should not be null", K(table->ref_id_)); - } else { - if (table->is_view_table_ && view_table_do_transform) { - // for view table, we should check col group in base table - const ObTableSchema *base_table_schema = NULL; - from_base = true; - if (table->view_base_item_ == NULL) { - // do nothing or return error - } else { - ObSelectStmt *real_stmt = NULL; - if (OB_ISNULL(real_stmt = table->ref_query_->get_real_stmt())) { - // case : view definition is set_op - // Bug : - ret = OB_ERR_UNEXPECTED; - LOG_WARN("real stmt is NULL", K(ret)); - } else { - SelectItem &t_col = real_stmt->get_select_item((udt_expr.get_column_id() - OB_APP_MIN_COLUMN_ID)); - - if (t_col.expr_->get_expr_type() == T_FUN_SYS_MAKEXML) { // xmltype special case - if (t_col.expr_->get_param_count() != 2) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid xml generated table column", K(ret), K(t_col.expr_)); - } else if (!t_col.expr_->get_param_expr(1)->is_column_ref_expr()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid xml generated table column", K(ret), K(t_col.expr_->get_param_expr(1)->is_column_ref_expr())); - } else { - from_xml = true; - col_expr = static_cast(t_col.expr_->get_param_expr(1)); - } - } else if (t_col.expr_->get_expr_type() == T_REF_COLUMN) { - int64_t col_id = dynamic_cast(t_col.expr_)->get_column_id(); - if (OB_FAIL(ctx->schema_checker_->get_table_schema(ctx->session_info_->get_effective_tenant_id(), - table->view_base_item_->ref_id_, base_table_schema))) { - LOG_WARN("failed to get table schema", K(ret)); - } else if (OB_ISNULL(base_table_schema)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("table should not be null", K(table->view_base_item_->ref_id_)); - } else if (OB_FAIL(base_table_schema->get_column_schema_in_same_col_group(col_id, - udt_expr.get_udt_set_id(), - hidden_cols))) { - LOG_WARN("failed to get column schema", K(ret)); - } - } else { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid view column type", K(ret), K(t_col.expr_)); - } - } - } - } else if (OB_FAIL(table_schema->get_column_schema_in_same_col_group(udt_expr.get_column_id(), - udt_expr.get_udt_set_id(), - hidden_cols))) { - LOG_WARN("failed to get column schema", K(ret)); - } - if(OB_FAIL(ret)) { - } else if (!from_xml && hidden_cols.count() != 1) { - // xmltype only 1 hidden column currently - ret = OB_ERR_UNEXPECTED; - LOG_WARN("hidden cols count is not expected", K(table->ref_id_), K(hidden_cols.count())); - } else if (from_base) { - if (from_xml) { - column_item = stmt->get_column_item_by_base_id(table->table_id_, col_expr->get_column_id()); - } else { - column_item = stmt->get_column_item_by_base_id(table->table_id_, hidden_cols.at(0)->get_column_id()); - } - } else { - column_item = stmt->get_column_item(table->table_id_, hidden_cols.at(0)->get_column_id()); - } - - if(OB_FAIL(ret)) { - } else if (OB_NOT_NULL(column_item)) { - if (OB_ISNULL(column_item->expr_)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("column item expr is null", K(ret)); - } else { - col_expr = column_item->expr_; - need_transform = true; - } - } else if (!from_xml && OB_FAIL(ObRawExprUtils::build_column_expr(*ctx->expr_factory_, *hidden_cols.at(0), col_expr))) { - LOG_WARN("build column expr failed", K(ret)); - } else if (OB_ISNULL(col_expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("failed to create raw expr for dummy output", K(ret)); - } else { - if (!from_xml) { - col_expr->set_table_id(table->table_id_); - col_expr->set_explicited_reference(); - col_expr->set_column_attr(udt_expr.get_table_name(), col_expr->get_column_name()); - } - ColumnItem column_item; - column_item.expr_ = col_expr; - column_item.table_id_ = col_expr->get_table_id(); - column_item.column_id_ = col_expr->get_column_id(); - column_item.column_name_ = col_expr->get_column_name(); - if (OB_FAIL(stmt->add_column_item(column_item))) { - LOG_WARN("add column item to stmt failed", K(ret)); - } else { - need_transform = true; - } - } - } - return ret; -} - int ObTransformUtils::check_is_index_part_key(ObTransformerCtx &ctx, ObDMLStmt &stmt, ObRawExpr *check_expr, diff --git a/src/sql/rewrite/ob_transform_utils.h b/src/sql/rewrite/ob_transform_utils.h index 5d9f170f15..f1b52e4499 100644 --- a/src/sql/rewrite/ob_transform_utils.h +++ b/src/sql/rewrite/ob_transform_utils.h @@ -313,11 +313,7 @@ public: ObRawExprFactory &expr_factory, const ObDMLStmt *stmt, ObDMLStmt *&new_stmt); - static int create_udt_hidden_columns(ObTransformerCtx *ctx, - ObDMLStmt *stmt, - const ObColumnRefRawExpr &udt_expr, - ObColumnRefRawExpr *&col_expr, - bool &need_transform); + /** * @brief joined_table需要维护一个基表的table id列表 * 对于它的左右子节点,如果是基表 或者generated table,直接使用其table id; diff --git a/src/sql/session/ob_sql_session_info.cpp b/src/sql/session/ob_sql_session_info.cpp index b4d92cc3aa..1f3a931a4e 100644 --- a/src/sql/session/ob_sql_session_info.cpp +++ b/src/sql/session/ob_sql_session_info.cpp @@ -64,6 +64,7 @@ using namespace oceanbase::share::schema; using namespace oceanbase::share; using namespace oceanbase::pl; using namespace oceanbase::obmysql; +using namespace oceanbase::observer; static const int64_t DEFAULT_XA_END_TIMEOUT_SECONDS = 60;/*60s*/ @@ -524,6 +525,15 @@ int ObSQLSessionInfo::is_preserve_order_for_pagination_enabled(bool &enabled) co return ret; } +bool ObSQLSessionInfo::is_pl_prepare_stage() const +{ + bool bret = false; + if (OB_NOT_NULL(cur_exec_ctx_) && OB_NOT_NULL(cur_exec_ctx_->get_sql_ctx())) { + bret = cur_exec_ctx_->get_sql_ctx()->is_prepare_stage_; + } + return bret; +} + bool ObSQLSessionInfo::is_index_skip_scan_enabled() const { bool bret = false; @@ -2909,12 +2919,12 @@ int ObSQLSessionInfo::ps_use_stream_result_set(bool &use_stream) { return ret; } -observer::ObPieceCache* ObSQLSessionInfo::get_piece_cache(bool need_init) { +ObPieceCache* ObSQLSessionInfo::get_piece_cache(bool need_init) { if (NULL == piece_cache_ && need_init) { - void *buf = get_session_allocator().alloc(sizeof(observer::ObPieceCache)); + void *buf = get_session_allocator().alloc(sizeof(ObPieceCache)); if (NULL != buf) { - MEMSET(buf, 0, sizeof(observer::ObPieceCache)); - piece_cache_ = new (buf) observer::ObPieceCache(); + MEMSET(buf, 0, sizeof(ObPieceCache)); + piece_cache_ = new (buf) ObPieceCache(); if (OB_SUCCESS != piece_cache_->init(get_effective_tenant_id())) { piece_cache_->~ObPieceCache(); get_session_allocator().free(piece_cache_); diff --git a/src/sql/session/ob_sql_session_info.h b/src/sql/session/ob_sql_session_info.h index b17b8d9be8..1d731ec27a 100644 --- a/src/sql/session/ob_sql_session_info.h +++ b/src/sql/session/ob_sql_session_info.h @@ -1565,6 +1565,7 @@ public: inline void inc_in_bytes(int64_t in_bytes) { IGNORE_RETURN ATOMIC_FAA(&in_bytes_, in_bytes); } inline int64_t get_out_bytes() const { return ATOMIC_LOAD(&out_bytes_); } inline void inc_out_bytes(int64_t out_bytes) { IGNORE_RETURN ATOMIC_FAA(&out_bytes_, out_bytes); } + bool is_pl_prepare_stage() const; private: transaction::ObTxnFreeRouteCtx txn_free_route_ctx_; //save the current sql exec context in session diff --git a/src/storage/blocksstable/encoding/ob_encoding_util.h b/src/storage/blocksstable/encoding/ob_encoding_util.h index 3e5d283820..3dcfb2bbb3 100644 --- a/src/storage/blocksstable/encoding/ob_encoding_util.h +++ b/src/storage/blocksstable/encoding/ob_encoding_util.h @@ -119,6 +119,7 @@ OB_INLINE ObObjTypeStoreClass *get_store_class_map() ObGeometrySC, //ObGeometryTC ObStringSC, // ObUserDefinedSQLTC, UDT null_bitmaps ObDecimalIntSC, // ObDecimalIntTC + ObTextSC, // ObCollectionSQLTC ObMaxSC // ObMaxTC }; STATIC_ASSERT(ARRAYSIZEOF(store_class_map) == common::ObMaxTC + 1, @@ -180,6 +181,7 @@ OB_INLINE int64_t *get_type_size_map() -1, //Geometry -1, //ObUserDefinedSQLType -1, //ObDecimalIntType + -1, //ObCollectionSQLType -1 // ObMaxType }; STATIC_ASSERT(ARRAYSIZEOF(type_size_map) == common::ObMaxType + 1, @@ -242,6 +244,7 @@ OB_INLINE int64_t *get_estimate_base_store_size_map() 9, // ObGeometryType 8, // ObUserDefinedSQLType 8, // ObDecimalIntType + 8, // ObCollectionSQLType -1 // ObMaxType }; STATIC_ASSERT(ARRAYSIZEOF(estimate_base_store_size_map) == common::ObMaxType + 1, diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_bugfix_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_bugfix_mysql.result index 59c5a29dd1..908c57d0cb 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_bugfix_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_bugfix_mysql.result @@ -336,7 +336,7 @@ ST_GEOMFROMTEXT('POLYGON((0 0,0 0,0 0,0 0))')) 0 create table tt1(id int,p point); alter table tt1 change p p polygon; -ERROR 0A000: Change geometry type not supported +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field. desc tt1; Field Type Null Key Default Extra id int(11) YES NULL @@ -650,3 +650,25 @@ Outputs & filters: (3747839314902384640,MIN,MIN ; 3747839314902384640,MAX,MAX), (3748120789879095296,MIN,MIN ; 3748120789879095296,MAX,MAX), (3751498489599623168,MIN,MIN ; 3751498489599623168,MAX,MAX), (3765009288481734656,MIN,MIN ; 3765009288481734656,MAX,MAX), (3819052484010180608,MIN,MIN ; 3819052484010180608,MAX,MAX), (3746994889972252672,MIN,MIN ; 3746994889972252672,MAX,MAX), (3458764513820540928,MIN,MIN ; 3458764513820540928,MAX,MAX) +drop table if exists t1; +create table t1( g geometry );// +drop PROCEDURE IF EXISTS pro;// +CREATE PROCEDURE pro() +BEGIN +DECLARE g blob; +select ST_SymDifference(point(2,3),ST_GeomFromText('MultiPolygon(((0 0,0 3,3 3,3 0,0 0),(0.5 1,1 2,2 2,2 1,0.5 1)))')) INTO g; +insert into t1 values(g); +END ; +// +call pro();// +select ST_AsText(g) from t1;// +ST_AsText(g) +POLYGON((0 0,3 0,3 3,0 3,0 0),(0.5 1,1 2,2 2,2 1,0.5 1)) +DROP FUNCTION IF EXISTS getg;// +CREATE FUNCTION getg(stuId blob) +RETURNS varchar(200) DETERMINISTIC +RETURN ST_AsText(stuId) ; // +select getg(ST_SymDifference(point(1,0),point(1,6)));// +getg(ST_SymDifference(point(1,0),point(1,6))) +MULTIPOINT((1 0),(1 6)) +drop table t1; diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_cast_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_cast_mysql.result index 51b106a1e5..97713e2927 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_cast_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_cast_mysql.result @@ -286,6 +286,7 @@ LINESTRING(9 9,10 10) # Testing result of table column input # ############################################# # +drop table if exists gis_linestring_castable; CREATE TABLE gis_linestring_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_linestring_castable VALUES (101, ST_GEOMFROMTEXT('LINESTRING(1 1, 2 2)')), @@ -617,6 +618,7 @@ MULTIPOINT((6 6),(7 7)) # Testing result of table column input # ############################################# # +drop table if exists gis_multipoint_castable; CREATE TABLE gis_multipoint_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_multipoint_castable VALUES (101, ST_GEOMFROMTEXT('POINT(1 1)')), @@ -772,6 +774,7 @@ MULTILINESTRING((13 13,14 14),(15 15,16 16)) # Testing result of table column input # ############################################# # +drop table if exists gis_multilinestring_castable; CREATE TABLE gis_multilinestring_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_multilinestring_castable VALUES (101, ST_GEOMFROMTEXT('LINESTRING(1 1, 2 2)')), @@ -922,6 +925,7 @@ MULTIPOLYGON(((13 13,14 13,14 14,13 14,13 13)),((15 15,16 15,16 16,15 16,15 15)) # Testing result of table column input # ############################################# # +drop table if exists gis_multipolygon_castable; CREATE TABLE gis_multipolygon_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_multipolygon_castable VALUES (101, ST_GEOMFROMTEXT('POLYGON((3 3, 4 3, 4 4, 3 4, 3 3))')), @@ -1097,6 +1101,7 @@ GEOMETRYCOLLECTION(POINT(16 16),LINESTRING(17 17,18 18)) # Testing result of table column input # ############################################# # +drop table if exists gis_geometrycollection_castable; CREATE TABLE gis_geometrycollection_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_geometrycollection_castable VALUES (101, ST_GEOMFROMTEXT('POINT(1 1)')), @@ -1246,14 +1251,15 @@ ERROR 22S03: A parameter of function cast_as_point contains a geometry with lati SELECT CAST(0xE610000001010000000000000000000000E1120100008056C0 AS POINT); ERROR 22S03: A parameter of function cast_as_point contains a geometry with latitude -90.000000, which is out of range. It must be within [-90.000000, 90.000000]. # -create table tt2(a year); -insert into tt2 values(2010-10-10); -select * from tt2; +drop table if exists gis_tt2; +create table gis_tt2(a year); +insert into gis_tt2 values(2010-10-10); +select * from gis_tt2; a 1990 -select cast(a as point) from tt2; +select cast(a as point) from gis_tt2; ERROR SR001: There's no spatial reference system with SRID 809056561. -drop table tt2; +drop table gis_tt2; select cast(cast("1.23" as decimal) as point); ERROR 22023: Invalid GIS data provided to function cast_as_point. select cast(cast("1.23" as decimal) as linestring); @@ -1331,6 +1337,7 @@ ERROR SR001: There's no spatial reference system with SRID 257. SELECT TIME(ST_GEOMETRYFROMTEXT('polygon((1 1,1 1,1 1,1 1))')); TIME(ST_GEOMETRYFROMTEXT('polygon((1 1,1 1,1 1,1 1))')) NULL +drop table if exists t; create table t(id int, t time); insert into t values(1, st_geomfromtext('POINT(1 1)')); ERROR 22007: Incorrect value diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_ddl_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_ddl_mysql.result index 181fbca34d..eefd202ffb 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_ddl_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_ddl_mysql.result @@ -397,9 +397,9 @@ drop table tt4; drop table if exists test; create table test(p point srid 4326); alter table test modify p MULTIPOINT; -ERROR 0A000: Modify geometry type not supported +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field. alter table test change p p1 MULTIPOINT; -ERROR 0A000: Change geometry type not supported +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field. alter table test modify p POINT SRID 0; ERROR 0A000: Modify geometry srid not supported alter table test change p p1 point srid 0; @@ -492,3 +492,125 @@ POINT(10 10) MULTILINESTRING((1 1,2 2,3 3),(10 10,20 20,30 30)) drop table geometries; drop table t1; +bugfix: 53170626 +drop table if exists geo_t1; +create table geo_t1 as select point(1,1); +desc geo_t1; +Field Type Null Key Default Extra +point(1,1) point YES NULL +drop table geo_t1; +create table geo_t1 as select _st_makevalid(st_geomfromtext('POLYGON((2 2,6 -2,10 2,10 -2,6 2,2 -2,2 2))')); +desc geo_t1; +Field Type Null Key Default Extra +_st_makevalid(st_geomfromtext('POLYGON((2 2,6 -2,10 2,10 -2,6 2,2 -2,2 2))')) geometry YES NULL +drop table geo_t1; +create table geo_t1 as select _ST_POINT(0, 0); +desc geo_t1; +Field Type Null Key Default Extra +_ST_POINT(0, 0) geometry YES NULL +drop table geo_t1; +create table geo_t1 as select ST_TRANSFORM(ST_GEOMFROMTEXT('POINT(0 0)', 4326), NULL); +desc geo_t1; +Field Type Null Key Default Extra +ST_TRANSFORM(ST_GEOMFROMTEXT('POINT(0 0)', 4326), NULL) geometry YES NULL +drop table geo_t1; +create table geo_t1 as select ST_X(ST_GEOMFROMTEXT('POINT(0 0)')); +desc geo_t1; +Field Type Null Key Default Extra +ST_X(ST_GEOMFROMTEXT('POINT(0 0)')) double YES NULL +drop table geo_t1; +bugfix: 53668721 +drop table if exists coll_t1; +drop view if exists coll_v1; +CREATE table coll_t1 (c1 GeomCollection); +insert into coll_t1 values (GEOMCOLLECTION(POINT(0,0))); +desc coll_t1; +Field Type Null Key Default Extra +c1 geomcollection YES NULL +select st_astext(t.c1) from coll_t1 t; +st_astext(t.c1) +GEOMETRYCOLLECTION(POINT(0 0)) +CREATE view coll_v1 as select * from coll_t1; +desc coll_v1; +Field Type Null Key Default Extra +c1 geomcollection YES NULL +select st_astext(t.c1) from coll_v1 t; +st_astext(t.c1) +GEOMETRYCOLLECTION(POINT(0 0)) +drop table coll_t1; +drop view coll_v1; +bugfix: 55274751 +drop table if exists geo_t1; +create table geo_t1(t GeomCollection); +insert into geo_t1 values (st_geomfromtext('GeometryCollection(point(1 1), linestring(0 0, 2 2))')); +ALTER TABLE geo_t1 MODIFY t int; +ERROR HY000: Incorrect integer value +ALTER TABLE geo_t1 MODIFY t double; +ERROR 22003: Out of range value for column +ALTER TABLE geo_t1 MODIFY t datetime; +ERROR 22007: Incorrect value +ALTER TABLE geo_t1 MODIFY t timestamp; +ERROR 22007: Incorrect value +ALTER TABLE geo_t1 MODIFY t date; +ERROR 22007: Incorrect value +ALTER TABLE geo_t1 MODIFY t varchar(1); +ERROR HY000: Incorrect string value +ALTER TABLE geo_t1 MODIFY t ENUM('a','b'); +ERROR 0A000: Not supported feature or function +ALTER TABLE geo_t1 MODIFY t SET('a','b'); +ERROR 0A000: Not supported feature or function +ALTER TABLE geo_t1 MODIFY t JSON; +ERROR 0A000: Not supported feature or function +ALTER TABLE geo_t1 MODIFY t BIT(8); +ERROR 22001: Data too long for column +ALTER TABLE geo_t1 MODIFY t varchar(256); +ERROR HY000: Incorrect string value +ALTER TABLE geo_t1 MODIFY t text; +ERROR HY000: Incorrect string value +ALTER TABLE geo_t1 MODIFY t LONGTEXT CHARSET binary; +select hex(t) from geo_t1; +hex(t) +000000000107000000020000000101000000000000000000F03F000000000000F03F0102000000020000000000000000000000000000000000000000000000000000400000000000000040 +ALTER TABLE geo_t1 MODIFY t GeomCollection; +select hex(t) from geo_t1; +hex(t) +000000000107000000020000000101000000000000000000F03F000000000000F03F0102000000020000000000000000000000000000000000000000000000000000400000000000000040 +ALTER TABLE geo_t1 change t tt int; +ERROR HY000: Incorrect integer value +ALTER TABLE geo_t1 change t tt double; +ERROR 22003: Out of range value for column +ALTER TABLE geo_t1 change t tt datetime; +ERROR 22007: Incorrect value +ALTER TABLE geo_t1 change t tt timestamp; +ERROR 22007: Incorrect value +ALTER TABLE geo_t1 change t tt date; +ERROR 22007: Incorrect value +ALTER TABLE geo_t1 change t tt varchar(1); +ERROR HY000: Incorrect string value +ALTER TABLE geo_t1 change t tt ENUM('a','b'); +ERROR 0A000: Not supported feature or function +ALTER TABLE geo_t1 change t tt SET('a','b'); +ERROR 0A000: Not supported feature or function +ALTER TABLE geo_t1 change t tt JSON; +ERROR 0A000: Not supported feature or function +ALTER TABLE geo_t1 change t tt BIT(8); +ERROR 22001: Data too long for column +ALTER TABLE geo_t1 change t tt varchar(256); +ERROR HY000: Incorrect string value +ALTER TABLE geo_t1 change t tt text; +ERROR HY000: Incorrect string value +ALTER TABLE geo_t1 change t tt LONGTEXT CHARSET binary; +select hex(tt) from geo_t1; +hex(tt) +000000000107000000020000000101000000000000000000F03F000000000000F03F0102000000020000000000000000000000000000000000000000000000000000400000000000000040 +ALTER TABLE geo_t1 change tt t GeomCollection; +select hex(t) from geo_t1; +hex(t) +000000000107000000020000000101000000000000000000F03F000000000000F03F0102000000020000000000000000000000000000000000000000000000000000400000000000000040 +bugfix: 53251134 +drop table if exists geo_t1; +create table geo_t1 as select ST_Centroid(ST_geomfromtext('POLYGON((121.474243 31.234504, 121.471775 31.233348, 121.470724 31.23155, 121.471603 31.230229, 121.472655 31.230357, 121.475777 31.232045, 121.474243 31.234504))')) centroid ; +desc geo_t1; +Field Type Null Key Default Extra +centroid point YES NULL +drop table geo_t1; diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_dml_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_dml_mysql.result index f59cfea2f6..97ceb865b3 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_dml_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_dml_mysql.result @@ -2,7 +2,7 @@ # Base test of GEOMETRY dml. # ---------------------------------------------------------------------- alter system set _enable_defensive_check = 1; -DROP TABLE IF EXISTS spatial_index_dml_constraint, tt1; +DROP TABLE IF EXISTS spatial_index_dml_constraint, tt1, T_GEO; CREATE TABLE spatial_index_dml_constraint (i INT, g GEOMETRY NOT NULL SRID 4326, PRIMARY KEY (i)); SET @v1=ST_GEOMFROMTEXT('POINT(0 0)', 4326); SET @v2=ST_GEOMFROMTEXT('LINESTRING(0 0,10 10)', 4326); @@ -423,3 +423,23 @@ GEOMETRYCOLLECTION(POINT(10 10),POINT(30 30),LINESTRING(15 15,20 20)) GEOMETRYCOLLECTION(POINT(10 10),POINT(30 30),LINESTRING(15 15,20 20)) alter system set _enable_defensive_check = 0; drop table t_geo; +create table t_geo(geo geometry); +insert into t_geo values(x'000000000140340000000000004034000000000000'); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field. +insert into t_geo values(st_geomfromwkb(x'000000000140340000000000004034000000000000')); +select hex(geo) from t_geo; +hex(geo) +00000000010100000000000000000034400000000000003440 +drop table t_geo; +DROP TABLE IF EXISTS tt3; +create table tt3(id int,p geometry); +insert into tt3 values(1,st_geomfromtext('point(1 2)')); +update tt3 set p=x'000000000101000000000000000000F03F0000000000000840'; +select st_astext(p) from tt3; +st_astext(p) +POINT(1 3) +update tt3 set p =x'0000000001E9030000000000000000F03F00000000000000400000000000000840'; +select st_astext(p) from tt3; +st_astext(p) +POINT Z (1 2 3) +drop table tt3; diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_filter_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_filter_mysql.result index 4591ca44c8..9c92edf247 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_filter_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_filter_mysql.result @@ -3308,3 +3308,35 @@ c1 ST_AsText(g) 8 POLYGON((0 0,0 2,2 2,2 0,0 0)) 9 POINT(0 0) drop table t1; +bugfix: 53888898 +drop table t1; +create table t1 ( +id int , +gg geometry not null srid 0, +SPATIAL INDEX index_gis(gg) +); +insert into t1 values(1,ST_GeomFromText('POLYGON((0 0 ,10 0 ,10 11 ,0 11, 0 0 ))')); +select * from t1 where ST_Contains(gg,ST_Centroid(gg)); +id gg +1 $@$@&@&@ +select * from t1 where ST_Contains(ST_Centroid(gg),gg); +id gg +select * from t1 where ST_Within(gg,ST_Centroid(gg)); +id gg +select * from t1 where ST_Within(ST_Centroid(gg),gg); +id gg +1 $@$@&@&@ +select * from t1 where ST_Equals(gg,ST_Centroid(gg)); +id gg +select * from t1 where ST_Equals(ST_Centroid(gg),gg); +id gg +select * from t1; +id gg +1 $@$@&@&@ +delete from t1 where ST_Contains(ST_Centroid(gg),gg); +select * from t1; +id gg +1 $@$@&@&@ +delete from t1 where ST_Contains(gg,ST_Centroid(gg)); +select * from t1; +id gg diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_type_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_type_mysql.result index 7753c9f56f..c18fbf18f2 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_type_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/geometry_type_mysql.result @@ -190,6 +190,15 @@ SET @c8 = ST_GEOMFROMTEXT('GEOMETRYCOLLECTION(POINT(1 1), LINESTRING(2 2, 3 3))' # Check the values whether populated # Cleaning up the trigger DROP TRIGGER geom_trigger; +DROP TABLE IF EXISTS t1; +create table t1(id int, point point); +INSERT into t1 values(3,Point(100, 23)); +select ST_AsText(point) from t1 where ST_SymDifference(point,point) in (ST_SymDifference(point,Point(10, 23)),ST_SymDifference(point,point)); +ST_AsText(point) +POINT(100 23) +select ST_AsText(point) from t1 where ST_SymDifference(point,point) not in (ST_SymDifference(point,Point(10, 23)),ST_SymDifference(point,point)); +ST_AsText(point) +drop table t1; # Final cleanup DROP TABLE gis_point; DROP TABLE gis_linestring; @@ -201,3 +210,15 @@ DROP TABLE gis_geometrycollection; DROP TABLE gis_geometry; DROP TABLE tab; DROP TABLE tab2; +select LINESTRING(point(7,6),point(1,1),point(NULL,NULL)); +LINESTRING(point(7,6),point(1,1),point(NULL,NULL)) +NULL +select LINESTRING(point(NULL,NULL)); +LINESTRING(point(NULL,NULL)) +NULL +select LINESTRING(point(5,NULL)); +LINESTRING(point(5,NULL)) +NULL +select POLYGON(LINESTRING(POINT(0,0), POINT(0,5), POINT(5,5), POINT(5,0), POINT(NULL,0))); +POLYGON(LINESTRING(POINT(0,0), POINT(0,5), POINT(5,5), POINT(5,0), POINT(NULL,0))) +NULL diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_astext_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_astext_mysql.result index 94b001981d..4f0b810a4a 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_astext_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_astext_mysql.result @@ -422,3 +422,19 @@ select st_astext(cast(x'00000000010700000007000000010100000000000000000024400000 ERROR 22023: Invalid GIS data provided to function cast_as_geometrycollection. select st_astext(ST_GeometryFromWKB(x'0103000000020000000500000000000000000034C00000000000002440000000000000544000000000008056C000000000000054C000000000000034C00000000000000000000000000000544000000000000034C00000000000002440',4326,'axis-order=lat-long')); ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +bugfix: 53543670 +SELECT ST_AsText(x'0000000001EC0300000600000001E903000000000000000026400000000000003640000000000040534001E903000000000000008040400000000000004640000000000000404001E90300000000000000804B4000000000008050400000000000C05E4001E90300000000000000405340000000000000564000000000000054C001E90300000000000000C0584000000000000026400000000000000000'); +ERROR 22023: Invalid GIS data provided to function st_astext. +bugfix: 53520655 +select ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOLYGON(((0 0 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0),(0.11 0.11 0.55454545645645,0.12 0.12 0.125121435,0.13 0.13 0.4541,0.11 0.11 1)))')); +ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOLYGON(((0 0 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0),(0.11 0.11 0.55454545645645,0.12 0.12 0.125121435,0.13 0.13 0.4541,0.11 0.11 1)))')) +MULTIPOLYGON Z (((0 0 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0),(0.11 0.11 0.55454545645645,0.12 0.12 0.125121435,0.13 0.13 0.4541,0.11 0.11 1))) +select ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOLYGON(((0 1 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0),(0.11 0.11 0.55454545645645,0.12 0.12 0.125121435,0.13 0.13 0.4541,0.11 0.11 1)))')); +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOLYGON(((0 1 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0),(0.11 0 0.55454545645645,0.12 0.12 0.125121435,0.13 0.13 0.4541,0.11 0.11 1)))')); +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_ASTEXT(ST_GEOMFROMTEXT('POLYGON((0 0 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0))')); +ST_ASTEXT(ST_GEOMFROMTEXT('POLYGON((0 0 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0))')) +POLYGON Z ((0 0 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0)) +select ST_ASTEXT(ST_GEOMFROMTEXT('POLYGON((0 1 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0))')); +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_covers_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_covers_mysql.result index 5021a48dd2..c46f4faabc 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_covers_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_covers_mysql.result @@ -1932,12 +1932,12 @@ GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 1,10 1,10 10,1 10,1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) POINT(1 1) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) LINESTRING(1 1,2 2) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) POLYGON((0 0,1 0,1 1,0 1,0 0)) 1 -GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)) 1 +GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)) 0 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) MULTIPOINT((1 1),(2 2)) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) MULTILINESTRING((1 1,2 2),(3 3,4 4)) 1 -GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))) 1 -GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))) 1 -GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 1,10 1,10 10,1 10,1 1),(4 4,6 4,6 6,4 6,4 4))) 1 +GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))) 0 +GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))) 0 +GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 1,10 1,10 10,1 10,1 1),(4 4,6 4,6 6,4 6,4 4))) 0 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) GEOMETRYCOLLECTION(POINT(1 1)) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6)))) GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))) 1 @@ -1953,12 +1953,12 @@ GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)) GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) POINT(1 1) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) LINESTRING(1 1,2 2) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) POLYGON((0 0,1 0,1 1,0 1,0 0)) 1 -GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)) 1 +GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)) 0 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) MULTIPOINT((1 1),(2 2)) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) MULTILINESTRING((1 1,2 2),(3 3,4 4)) 1 -GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))) 1 -GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))) 1 -GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 1,10 1,10 10,1 10,1 1),(4 4,6 4,6 6,4 6,4 4))) 1 +GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))) 0 +GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))) 0 +GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((1 1,10 1,10 10,1 10,1 1),(4 4,6 4,6 6,4 6,4 4))) 0 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) GEOMETRYCOLLECTION(POINT(1 1)) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)) 1 GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(1 1,2 2),POLYGON((0 0,1 0,1 1,0 1,0 0)),POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4)),MULTIPOINT((1 1),(2 2)),MULTILINESTRING((1 1,2 2),(3 3,4 4)),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5))),MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))),GEOMETRYCOLLECTION(POINT(1 1)),GEOMETRYCOLLECTION(LINESTRING(1 1,2 2)),GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))),GEOMETRYCOLLECTION(POLYGON((0 0,10 0,10 10,0 10,0 0),(4 4,6 4,6 6,4 6,4 4))),GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2))),GEOMETRYCOLLECTION(MULTILINESTRING((1 1,2 2),(3 3,4 4))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5)))),GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,1 0,1 1,0 1,0 0)),((5 5,10 5,10 10,5 10,5 5),(6 6,7 6,7 7,6 7,6 6))))) GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0))) 1 @@ -2043,3 +2043,13 @@ select _st_covers(ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'),x'000000 ERROR 22023: Invalid GIS data provided to function _st_covers. select _st_covers(x'00000000010300000001000000050000000000000000000000000000000000000000000000000024400000000000000000000000000000244000000000000024400000000000000000000000000000244000000000000000000000000000000001',ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))')); ERROR 22023: Invalid GIS data provided to function _st_covers. +bugfix: 54036048 +select _st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 5),POLYGON((1 0,10 0,10 10,1 0)),MULTILINESTRING((-5 -10 , 5 -20 ), (-15 -10 , 30 15)),GEOMETRYCOLLECTION(point(1 20)))',26918),ST_GeomFromText('POLYGON((0 0,10 10,20 20,30 30,0 0))',26918)); +_st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 5),POLYGON((1 0,10 0,10 10,1 0)),MULTILINESTRING((-5 -10 , 5 -20 ), (-15 -10 , 30 15)),GEOMETRYCOLLECTION(point(1 20)))',26918),ST_GeomFromText('POLYGON((0 0,10 10,20 20,30 30,0 0))',26918)) +0 +select _st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 5),POLYGON((1 0,10 0,10 10,1 0)),MULTILINESTRING((-5 -10 , 5 -20 ), (-15 -10 , 30 15)),GEOMETRYCOLLECTION(point(1 20)))',4326),ST_GeomFromText('POLYGON((0 0,10 10,20 20,30 30,0 0))',4326)); +_st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 5),POLYGON((1 0,10 0,10 10,1 0)),MULTILINESTRING((-5 -10 , 5 -20 ), (-15 -10 , 30 15)),GEOMETRYCOLLECTION(point(1 20)))',4326),ST_GeomFromText('POLYGON((0 0,10 10,20 20,30 30,0 0))',4326)) +0 +select _st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 5),POLYGON((1 0,10 0,10 10,1 0)),MULTILINESTRING((-5 -10 , 5 -20 ), (-15 -10 , 30 15)),GEOMETRYCOLLECTION(point(1 20)))'),ST_GeomFromText('POLYGON((0 0,10 10,20 20,30 30,0 0))')); +_st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 5),POLYGON((1 0,10 0,10 10,1 0)),MULTILINESTRING((-5 -10 , 5 -20 ), (-15 -10 , 30 15)),GEOMETRYCOLLECTION(point(1 20)))'),ST_GeomFromText('POLYGON((0 0,10 10,20 20,30 30,0 0))')) +0 diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_distance_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_distance_mysql.result index 9ce6040e07..c87e5a9973 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_distance_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_distance_mysql.result @@ -3151,7 +3151,7 @@ select st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 ERROR SU001: There's no unit of measure named 'Clarke'. select st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian foot"); st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian foot") -16417187.697291682 +16417187.697291631 select st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian foot (1937)"); st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian foot (1937)") 16417246.959347302 @@ -3165,7 +3165,44 @@ select st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 ERROR SU001: There's no unit of measure named 'Indian'. select st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian yard"); st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian yard") -5472395.899097215 +5472395.89909721 select st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian yard (1937)"); st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian yard (1937)") 5472415.653115767 +bugfix: 54168045 +select ST_Distance(ST_Distance(ST_GeomFromText('POINT(-1.000009 -30)'),ST_GeomFromText('POINT(-1.000009 -30)')),ST_GeomFromText('POINT(-1.000009 -30 )')); +ERROR 22023: Invalid GIS data provided to function st_distance. +SET @g1 = ST_GeomFromText('POINT(1 1)',4326); +SET @g2 = ST_GeomFromText('POINT(2 2)',4326); +SELECT ST_Distance(@g1, @g2, 1); +ERROR SU001: There's no unit of measure named '1'. +drop table t2; +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da datetime(6), dt datetime(6), sc char(50), sv varchar(50), b blob, tx text); +insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'POINT(1 1)', 'POINT(1 1)', 'POINT(1 1)', 'POINT(1 1)'); +select ST_Distance(it1, it1) from t2; +ST_Distance(it1, it1) +NULL +select ST_Distance(it2, it2) from t2; +ERROR 22023: Invalid GIS data provided to function st_distance. +select ST_Distance(i, i) from t2; +ERROR 22023: Invalid GIS data provided to function st_distance. +select ST_Distance(ib, ib) from t2; +ERROR 22023: Invalid GIS data provided to function st_distance. +select ST_Distance(f, f) from t2; +ERROR 22023: Invalid GIS data provided to function st_distance. +select ST_Distance(d, d) from t2; +ERROR 22023: Invalid GIS data provided to function st_distance. +select ST_Distance(y, y) from t2; +ERROR SR001: There's no spatial reference system with SRID 842479921. +select ST_Distance(da, da) from t2; +ERROR SR001: There's no spatial reference system with SRID 842479921. +select ST_Distance(dt, dt) from t2; +ERROR SR001: There's no spatial reference system with SRID 842479921. +select ST_Distance(sc, sc) from t2; +ERROR SR001: There's no spatial reference system with SRID 1313427280. +select ST_Distance(sv, sv) from t2; +ERROR SR001: There's no spatial reference system with SRID 1313427280. +select ST_Distance(b, b) from t2; +ERROR SR001: There's no spatial reference system with SRID 1313427280. +select ST_Distance(tx, tx) from t2; +ERROR SR001: There's no spatial reference system with SRID 1313427280. diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_geomfromtext_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_geomfromtext_mysql.result index f23ae4c9d5..a281e0b0e6 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_geomfromtext_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_geomfromtext_mysql.result @@ -6919,7 +6919,8 @@ select ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4)')); ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4)')) LINESTRING(1 2,3 4) select ST_AsText(ST_GeomFromText('LINESTRING(1 2 3,4 5 6)')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('LINESTRING(1 2 3,4 5 6)')) +LINESTRING Z (1 2 3,4 5 6) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4))')); ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4))')) GEOMETRYCOLLECTION(LINESTRING(1 2,3 4)) @@ -6936,9 +6937,11 @@ select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2))')); ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2))')) GEOMETRYCOLLECTION(POINT(1 2)) select ST_AsText(ST_GeomFromText('POINT(1 2 3)')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('POINT(1 2 3)')) +POINT Z (1 2 3) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2,5 6 -3),LINESTRING(7 8 -1,9 10 -2,11 12 -3))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2,5 6 -3),LINESTRING(7 8 -1,9 10 -2,11 12 -3))')) +GEOMETRYCOLLECTION Z (LINESTRING Z (1 2 -1,3 4 -2,5 6 -3),LINESTRING Z (7 8 -1,9 10 -2,11 12 -3)) select ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4,5 6,7 8,9 10)')); ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4,5 6,7 8,9 10)')) LINESTRING(1 2,3 4,5 6,7 8,9 10) @@ -6946,14 +6949,17 @@ select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4,5 6),LIN ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4,5 6),LINESTRING(7 8,9 10))')) GEOMETRYCOLLECTION(LINESTRING(1 2,3 4,5 6),LINESTRING(7 8,9 10)) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(5 6 -55,7 8 -22),LINESTRING(1 2 -1,3 4 -2))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(5 6 -55,7 8 -22),LINESTRING(1 2 -1,3 4 -2))')) +GEOMETRYCOLLECTION Z (LINESTRING Z (5 6 -55,7 8 -22),LINESTRING Z (1 2 -1,3 4 -2)) select ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4,5 6,7 8)')); ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4,5 6,7 8)')) LINESTRING(1 2,3 4,5 6,7 8) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2 -1))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2 -1))')) +GEOMETRYCOLLECTION Z (POINT Z (1 2 -1)) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2))')) +GEOMETRYCOLLECTION Z (LINESTRING Z (1 2 -1,3 4 -2)) select ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4,5 6)')); ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4,5 6)')) LINESTRING(1 2,3 4,5 6) @@ -6961,7 +6967,8 @@ select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4,5 6))')) ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4,5 6))')) GEOMETRYCOLLECTION(LINESTRING(1 2,3 4,5 6)) select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2,5 6 -3),(7 8 -1,9 10 -2,11 12 -3))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2,5 6 -3),(7 8 -1,9 10 -2,11 12 -3))')) +MULTILINESTRING Z ((1 2 -1,3 4 -2,5 6 -3),(7 8 -1,9 10 -2,11 12 -3)) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2)))')); ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2)))')) GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2))) @@ -6978,38 +6985,50 @@ select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0 ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2)))')) MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2))) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2 -2),POINT(3 4 -2),POINT(5 6 -3))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2 -2),POINT(3 4 -2),POINT(5 6 -3))')) +GEOMETRYCOLLECTION Z (POINT Z (1 2 -2),POINT Z (3 4 -2),POINT Z (5 6 -3)) select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4,5 6))')); ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4,5 6))')) MULTILINESTRING((1 2,3 4,5 6)) select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2))')) +MULTILINESTRING Z ((1 2 -1,3 4 -2)) select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2,5 6 -3))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2,5 6 -3))')) +MULTILINESTRING Z ((1 2 -1,3 4 -2,5 6 -3)) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4),POINT(5 6))')); ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4),POINT(5 6))')) GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4),POINT(5 6)) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2 -1),POINT(3 4 -2))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2 -1),POINT(3 4 -2))')) +GEOMETRYCOLLECTION Z (POINT Z (1 2 -1),POINT Z (3 4 -2)) select ST_AsText(ST_GeomFromText('MULTILINESTRING((5 6 -55,7 8 -22),(1 2 -1,3 4 -2))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTILINESTRING((5 6 -55,7 8 -22),(1 2 -1,3 4 -2))')) +MULTILINESTRING Z ((5 6 -55,7 8 -22),(1 2 -1,3 4 -2)) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2,5 6 -3))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2,5 6 -3))')) +GEOMETRYCOLLECTION Z (LINESTRING Z (1 2 -1,3 4 -2,5 6 -3)) select ST_AsText(ST_GeomFromText('LINESTRING(1 2 3,4 5 6,7 8 9)')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('LINESTRING(1 2 3,4 5 6,7 8 9)')) +LINESTRING Z (1 2 3,4 5 6,7 8 9) select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)))')) +MULTIPOLYGON Z (((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01))) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2),LINESTRING(5 6 -55,7 8 -22))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2),LINESTRING(5 6 -55,7 8 -22))')) +GEOMETRYCOLLECTION Z (LINESTRING Z (1 2 -1,3 4 -2),LINESTRING Z (5 6 -55,7 8 -22)) select ST_AsText(ST_GeomFromText('LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12)')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12)')) +LINESTRING Z (1 2 3,4 5 6,7 8 9,10 11 12) select ST_AsText(ST_GeomFromText('MULTIPOINT(1 2,3 4)')); ST_AsText(ST_GeomFromText('MULTIPOINT(1 2,3 4)')) MULTIPOINT((1 2),(3 4)) select ST_AsText(ST_GeomFromText('MULTIPOINT(1 2 3,4 5 6)')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTIPOINT(1 2 3,4 5 6)')) +MULTIPOINT Z ((1 2 3),(4 5 6)) select ST_AsText(ST_GeomFromText('MULTIPOINT(1 2 3,4 5 6,7 8 9)')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTIPOINT(1 2 3,4 5 6,7 8 9)')) +MULTIPOINT Z ((1 2 3),(4 5 6),(7 8 9)) select ST_AsText(ST_GeomFromText('MULTIPOINT(1 2,4 5,7 8)')); ST_AsText(ST_GeomFromText('MULTIPOINT(1 2,4 5,7 8)')) MULTIPOINT((1 2),(4 5),(7 8)) @@ -7017,9 +7036,11 @@ select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4))')); ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4))')) MULTILINESTRING((1 2,3 4)) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)))')) +GEOMETRYCOLLECTION Z (POLYGON Z ((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01))) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)))')) +GEOMETRYCOLLECTION Z (POLYGON Z ((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01))) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')); ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')) GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1))) @@ -7027,7 +7048,8 @@ select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4,5 6),(7 8,9 10))')); ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4,5 6),(7 8,9 10))')) MULTILINESTRING((1 2,3 4,5 6),(7 8,9 10)) select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2),(5 6 -55,7 8 -22))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2),(5 6 -55,7 8 -22))')) +MULTILINESTRING Z ((1 2 -1,3 4 -2),(5 6 -55,7 8 -22)) select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')); ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')) MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1))) @@ -7035,34 +7057,44 @@ select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0 ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2)))')) MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2))) select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)))')) +MULTIPOLYGON Z (((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01))) select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)))')) +MULTIPOLYGON Z (((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0))) select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')); ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')) MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1))) select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)))')) +MULTIPOLYGON Z (((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01))) select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)))')) +MULTIPOLYGON Z (((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01))) select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)))')) +MULTIPOLYGON Z (((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0))) select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)),((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)),((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)))')) +MULTIPOLYGON Z (((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)),((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0))) select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)))')) +GEOMETRYCOLLECTION Z (POLYGON Z ((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0))) select ST_AsText(ST_GeomFromText('POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1))')); ST_AsText(ST_GeomFromText('POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1))')) POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)) select ST_AsText(ST_GeomFromText('POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01))')) +POLYGON Z ((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)) select ST_AsText(ST_GeomFromText('POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2))')); ST_AsText(ST_GeomFromText('POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2))')) POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2)) select ST_AsText(ST_GeomFromText('POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01))')) +POLYGON Z ((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)) select ST_AsText(ST_GeomFromText('POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0))')); -ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +ST_AsText(ST_GeomFromText('POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0))')) +POLYGON Z ((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)) # check result collation under old sql engine set @pt = st_geomfromtext('point(1 2)', 4326); select length(@pt); @@ -7100,3 +7132,54 @@ SRID=4326;POINT(123.32112345678988 38.87700000000001) SELECT _ST_ASEWKT(_ST_GEOGRAPHYFROMTEXT('SRID=4326;point(180 180)')); _ST_ASEWKT(_ST_GEOGRAPHYFROMTEXT('SRID=4326;point(180 180)')) SRID=4326;POINT(180 0) +bugfix: 54159493 +select ST_GeomFromText('geomcollection(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))'); +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select _ST_GEOGRAPHYFROMTEXT('geomcollection(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))'); +ERROR 22023: Invalid GIS data provided to function _st_geographyfromtext. +select _ST_GeogFromText('geomcollection(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))'); +ERROR 22023: Invalid GIS data provided to function _st_geogfromtext. +bugfix: 53612010 +drop table typy_set; +create table typy_set (em enum('春','point(0 5)')); +insert into typy_set values('point(0 5)'); +select ST_GeomFromText(em ) from typy_set; +ST_GeomFromText(em ) +@ +select ST_AsText(ST_GeomFromText(em )) from typy_set; +ST_AsText(ST_GeomFromText(em )) +POINT(0 5) +drop table t2; +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da datetime(6), dt datetime(6), sc char(50), sv varchar(50), b blob, tx text); +insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)'); +select ST_GeomFromText(it1) from t2; +ST_GeomFromText(it1) +NULL +select ST_GeomFromText(it2) from t2; +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_GeomFromText(i) from t2; +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_GeomFromText(ib) from t2; +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_GeomFromText(f) from t2; +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_GeomFromText(d) from t2; +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_GeomFromText(y) from t2; +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_GeomFromText(da) from t2; +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_GeomFromText(dt) from t2; +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. +select ST_GeomFromText(sc) from t2; +ST_GeomFromText(sc) +$@$@ +select ST_GeomFromText(sv) from t2; +ST_GeomFromText(sv) +$@$@ +select ST_GeomFromText(b) from t2; +ST_GeomFromText(b) +$@$@ +select ST_GeomFromText(tx) from t2; +ST_GeomFromText(tx) +$@$@ diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_geomfromwkb_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_geomfromwkb_mysql.result index a05b67d785..389fb70290 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_geomfromwkb_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_geomfromwkb_mysql.result @@ -159,9 +159,9 @@ SELECT ST_GeomFromWKB(NULL); ST_GeomFromWKB(NULL) NULL SELECT ST_GeomFromWKB(ST_GeomFromText('POINT()')); -ERROR 22023: Invalid GIS data provided to function st_geomfromwkb. +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. SELECT ST_GeomFromWKB(ST_GeomFromText('LINESTRING(0 0,! 10)')); -ERROR 22023: Invalid GIS data provided to function st_geomfromwkb. +ERROR 22023: Invalid GIS data provided to function st_geomfromtext. select ST_GeometryFromWKB(x'010100000000000000000034C00000000000002E4000000000000034400000000000003440'); ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. select ST_GeomFromWKB(x'010100000000000000000034C00000000000002E4000000000000034400000000000003440'); @@ -214,3 +214,67 @@ select ST_GeometryFromWKB(x'010100000000000000000034C00000000000002E40','axis-or ERROR 22023: Invalid option key 'srid' in function st_geometryfromwkb. select ST_GeomFromWKB(x'010100000000000000000034C00000000000002E40','axis-order=long-lat','srid=4326'); ERROR 22023: Invalid option key 'srid' in function st_geomfromwkb. +select st_astext(st_geomfromwkb(x'000000000140340000000000004034000000000000')); +st_astext(st_geomfromwkb(x'000000000140340000000000004034000000000000')) +POINT(20 20) +select st_astext(st_geomfromwkb(x'000000000140340000000000004034000000000000', 4326)); +st_astext(st_geomfromwkb(x'000000000140340000000000004034000000000000', 4326)) +POINT(20 20) +SELECT ST_astext(ST_GEOMFROMWKB(X'0000000002000000023FF00000000000003FF000000000000040000000000000004000000000000000')); +ST_astext(ST_GEOMFROMWKB(X'0000000002000000023FF00000000000003FF000000000000040000000000000004000000000000000')) +LINESTRING(1 1,2 2) +SELECT ST_astext(ST_GEOMFROMWKB(X'00000000030000000100000005000000000000000000000000000000004008000000000000000000000000000040000000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000')); +ST_astext(ST_GEOMFROMWKB(X'00000000030000000100000005000000000000000000000000000000004008000000000000000000000000000040000000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000')) +POLYGON((0 0,3 0,2 1,1 1,0 0)) +SELECT ST_astext(ST_GEOMFROMWKB(X'00000000040000000200000000013FF00000000000003FF000000000000000000000013FF00000000000003FF0000000000000')); +ST_astext(ST_GEOMFROMWKB(X'00000000040000000200000000013FF00000000000003FF000000000000000000000013FF00000000000003FF0000000000000')) +MULTIPOINT((1 1),(1 1)) +select st_astext(st_geomfromwkb(x'0000000005000000020000000002000000020000000000000000000000000000000040654000000000000000000000000000000000000200000002405400000000000000000000000000004054000000000000404E000000000000')); +st_astext(st_geomfromwkb(x'0000000005000000020000000002000000020000000000000000000000000000000040654000000000000000000000000000000000000200000002405400000000000000000000000000004054000000000000404E000000000000')) +MULTILINESTRING((0 0,170 0),(80 0,80 60)) +select st_astext(st_geomfromwkb(x'0000000006000000010000000003000000010000000640140000000000004008000000000000401C00000000000040100000000000004022000000000000401400000000000040260000000000004018000000000000402A000000000000401C00000000000040140000000000004008000000000000')); +st_astext(st_geomfromwkb(x'0000000006000000010000000003000000010000000640140000000000004008000000000000401C00000000000040100000000000004022000000000000401400000000000040260000000000004018000000000000402A000000000000401C000000000000401400000000000040080000 +MULTIPOLYGON(((5 3,7 4,9 5,11 6,13 7,5 3))) +select st_astext(st_geomfromwkb(x'000000000700000008000000000100000000000000003FF000000000000000000000020000000200000000000000003FF000000000000040240000000000004026000000000000000000000300000001000000050000000000000000000000000000000000000000000000004024000000000000402400000000000040240000000000004024000000000000000000000000000000000000000000000000000000000000000000000400000006000000000100000000000000003FF000000000000000000000014000000000000000400800000000000000000000014010000000000000401400000000000000000000014018000000000000401C00000000000000000000014020000000000000402200000000000000000000014024000000000000402600000000000000000000020000000200000000000000003FF00000000000004024000000000000402600000000000000000000020000000200000000000000004024000000000000402400000000000000000000000000000000000003000000010000000500000000000000003FF000000000000000000000000000004014000000000000401400000000000040180000000000004014000000000000000000000000000000000000000000003FF0000000000000000000000300000001000000054014000000000000401000000000000040140000000000004024000000000000402400000000000040260000000000004024000000000000401400000000000040140000000000004010000000000000')); +st_astext(st_geomfromwkb(x'000000000700000008000000000100000000000000003FF000000000000000000000020000000200000000000000003FF00000000000004024000000000000402600000000000000000000030000000100000005000000000000000000000000000000000000000000000000402400000000 +GEOMETRYCOLLECTION(POINT(0 1),LINESTRING(0 1,10 11),POLYGON((0 0,0 10,10 10,10 0,0 0)),MULTIPOINT((0 1),(2 3),(4 5),(6 7),(8 9),(10 11)),LINESTRING(0 1,10 11),LINESTRING(0 10,10 0),POLYGON((0 1,0 5,5 6,5 0,0 1)),POLYGON((5 4,5 10,10 11,10 5,5 4))) +bugfix: 53757359 +SELECT st_geometryfromwkb(null); +st_geometryfromwkb(null) +NULL +SELECT st_geometryfromwkb(st_geometryfromwkb(null)); +st_geometryfromwkb(st_geometryfromwkb(null)) +NULL +SELECT st_geometryfromwkb(st_length(null)); +st_geometryfromwkb(st_length(null)) +NULL +drop table t2; +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da datetime(6), dt datetime(6), sc char(50), sv varchar(50), b blob, tx text); +insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)'); +select st_geometryfromwkb(it1) from t2; +st_geometryfromwkb(it1) +NULL +select st_geometryfromwkb(it2) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(i) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(ib) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(f) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(d) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(y) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(da) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(dt) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(sc) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(sv) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(b) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. +select st_geometryfromwkb(tx) from t2; +ERROR 22023: Invalid GIS data provided to function st_geometryfromwkb. diff --git a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_srid_mysql.result b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_srid_mysql.result index d66afbc9eb..6dbb5bd546 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_srid_mysql.result +++ b/tools/deploy/mysql_test/test_suite/geometry/r/mysql/st_srid_mysql.result @@ -148,3 +148,7 @@ ERROR 22023: Invalid GIS data provided to function st_geomfromtext. select st_astext(st_srid(x'0000000001030000000300000005000000000010000000000000000000000000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000005000000000000000000144000000000000014400000000000001C4000000000000014400000000000001C400000000000001C4000000000000014400000000000001C40000000000000144000000000000014410500000000000000000014C000000000000014C00000000000001CC000000000000014C00000000000001CC00000000000001CC000000000000014C00000000000001CC000000000000014C000000000000014C0',0)); st_astext(st_srid(x'0000000001030000000300000005000000000010000000000000000000000000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000005000000000000000000144000000000000014400 POLYGON((5.180654e-318 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 327680),(-5 -5,-7 -5,-7 -7,-5 -7,-5 -5)) +bugfix: 53257405 +select st_srid(st_geomfromtext('point(100 100)')) - 3; +st_srid(st_geomfromtext('point(100 100)')) - 3 +-3 diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_bugfix_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_bugfix_mysql.test index 8cabf4bbd3..3831e524f3 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_bugfix_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_bugfix_mysql.test @@ -170,6 +170,7 @@ drop table FF02; # 1. cases should share same plancache alter system flush plan cache; +sleep 3; create table gis_point_plancache (x double, y double, poi geometry); @@ -247,7 +248,7 @@ ST_GEOMFROMTEXT('POLYGON((0 0,0 0,0 0,0 0))')); # create table tt1(id int,p point); ---error 1235 +--error 1416 alter table tt1 change p p polygon; desc tt1; drop table tt1; @@ -417,3 +418,28 @@ call dbms_stats.gather_table_stats('test','geek_poi_7'); --enable_result_log explain SELECT p.p_id,0 as distance FROM geek_poi_7 as p WHERE p.geohash_code like 'ws0emp%' and p.p_delete_time = 0 AND ST_Contains(p.geog_poi,_ST_GeogFromText('POINT(113.42416381835938 23.11138916015625)')); +drop table if exists t1; +--enable_warnings +delimiter //; +create table t1( g geometry );// +drop PROCEDURE IF EXISTS pro;// +CREATE PROCEDURE pro() + BEGIN + DECLARE g blob; + select ST_SymDifference(point(2,3),ST_GeomFromText('MultiPolygon(((0 0,0 3,3 3,3 0,0 0),(0.5 1,1 2,2 2,2 1,0.5 1)))')) INTO g; + insert into t1 values(g); + END ; +// + +call pro();// + +select ST_AsText(g) from t1;// + +DROP FUNCTION IF EXISTS getg;// +CREATE FUNCTION getg(stuId blob) +RETURNS varchar(200) DETERMINISTIC +RETURN ST_AsText(stuId) ; // +select getg(ST_SymDifference(point(1,0),point(1,6)));// + +delimiter ;// +drop table t1; diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_cast_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_cast_mysql.test index bf19b4b1e3..544c99700d 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_cast_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_cast_mysql.test @@ -305,6 +305,9 @@ --echo ############################################# --echo # + --disable_warnings + drop table if exists gis_linestring_castable; + --enable_warnings CREATE TABLE gis_linestring_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_linestring_castable VALUES (101, ST_GEOMFROMTEXT('LINESTRING(1 1, 2 2)')), @@ -640,6 +643,9 @@ --echo ############################################# --echo # + --disable_warnings + drop table if exists gis_multipoint_castable; + --enable_warnings CREATE TABLE gis_multipoint_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_multipoint_castable VALUES (101, ST_GEOMFROMTEXT('POINT(1 1)')), @@ -794,6 +800,9 @@ --echo ############################################# --echo # + --disable_warnings + drop table if exists gis_multilinestring_castable; + --enable_warnings CREATE TABLE gis_multilinestring_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_multilinestring_castable VALUES (101, ST_GEOMFROMTEXT('LINESTRING(1 1, 2 2)')), @@ -947,6 +956,9 @@ --echo ############################################# --echo # + --disable_warnings + drop table if exists gis_multipolygon_castable; + --enable_warnings CREATE TABLE gis_multipolygon_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_multipolygon_castable VALUES (101, ST_GEOMFROMTEXT('POLYGON((3 3, 4 3, 4 4, 3 4, 3 3))')), @@ -1108,6 +1120,9 @@ --echo ############################################# --echo # + --disable_warnings + drop table if exists gis_geometrycollection_castable; + --enable_warnings CREATE TABLE gis_geometrycollection_castable (fid INTEGER NOT NULL PRIMARY KEY, g GEOMETRY); INSERT INTO gis_geometrycollection_castable VALUES (101, ST_GEOMFROMTEXT('POINT(1 1)')), @@ -1270,12 +1285,15 @@ --echo # # bugfix: - create table tt2(a year); - insert into tt2 values(2010-10-10); - select * from tt2; + --disable_warnings + drop table if exists gis_tt2; + --enable_warnings + create table gis_tt2(a year); + insert into gis_tt2 values(2010-10-10); + select * from gis_tt2; --error 3548 - select cast(a as point) from tt2; - drop table tt2; + select cast(a as point) from gis_tt2; + drop table gis_tt2; --error 3037 select cast(cast("1.23" as decimal) as point); @@ -1366,6 +1384,9 @@ DROP TABLE IF EXISTS tt1; # SELECT TIME(ST_GEOMETRYFROMTEXT('polygon((1 1,1 1,1 1,1 1))')); + --disable_warnings + drop table if exists t; + --enable_warnings create table t(id int, t time); --error 1292 insert into t values(1, st_geomfromtext('POINT(1 1)')); diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_ddl_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_ddl_mysql.test index 8b0ad9a44c..86675c3453 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_ddl_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_ddl_mysql.test @@ -106,7 +106,7 @@ if (0) { #ST_SRID 未支持 col2 POINT AS (ST_SRID(col1, 0)) SRID 2000); --source mysql_test/include/show_create_table_old_version_replica2.inc show create table t1; - --error 3643 + --error 1235 INSERT INTO t1 (col1) VALUES (ST_GeomFromText('POINT(1 1)', 4326)); DROP TABLE t1; } @@ -373,7 +373,7 @@ if (0) { # 不支持升级srid ALTER TABLE t1 CHANGE COLUMN col_srid_2000 col_srid_2000 POINT NOT NULL SRID 4326; --echo # Wrong SRID for col_srid_2000, so should not work - --error 3643 + --error 1235 INSERT INTO t1 (col_no_srid, col_srid_0, col_srid_2000) VALUES ( ST_GeomFromText('POINT(1 1)'), ST_GeomFromText('POINT(1 1)', 0), @@ -550,9 +550,9 @@ drop table tt4; drop table if exists test; --enable_warnings create table test(p point srid 4326); ---error 1235 +--error 1416 alter table test modify p MULTIPOINT; ---error 1235 +--error 1416 alter table test change p p1 MULTIPOINT; --error 1235 alter table test modify p POINT SRID 0; @@ -655,3 +655,119 @@ CREATE TABLE t1 SELECT a FROM (SELECT pt AS a FROM geometries UNION SELECT mls F select st_astext(a) from t1; drop table geometries; drop table t1; + +--echo bugfix: 53170626 +--disable_warnings +drop table if exists geo_t1; +--enable_warnings +create table geo_t1 as select point(1,1); +desc geo_t1; +drop table geo_t1; + +create table geo_t1 as select _st_makevalid(st_geomfromtext('POLYGON((2 2,6 -2,10 2,10 -2,6 2,2 -2,2 2))')); +desc geo_t1; +drop table geo_t1; + +create table geo_t1 as select _ST_POINT(0, 0); +desc geo_t1; +drop table geo_t1; + +create table geo_t1 as select ST_TRANSFORM(ST_GEOMFROMTEXT('POINT(0 0)', 4326), NULL); +desc geo_t1; +drop table geo_t1; + +create table geo_t1 as select ST_X(ST_GEOMFROMTEXT('POINT(0 0)')); +desc geo_t1; +drop table geo_t1; + +--echo bugfix: 53668721 +--disable_warnings +drop table if exists coll_t1; +drop view if exists coll_v1; +--enable_warnings +CREATE table coll_t1 (c1 GeomCollection); +insert into coll_t1 values (GEOMCOLLECTION(POINT(0,0))); +desc coll_t1; +select st_astext(t.c1) from coll_t1 t; + +CREATE view coll_v1 as select * from coll_t1; +desc coll_v1; +select st_astext(t.c1) from coll_v1 t; + +drop table coll_t1; +drop view coll_v1; +--echo bugfix: 55274751 +--disable_warnings +drop table if exists geo_t1; +--enable_warnings +create table geo_t1(t GeomCollection); +insert into geo_t1 values (st_geomfromtext('GeometryCollection(point(1 1), linestring(0 0, 2 2))')); +--error 1366 +ALTER TABLE geo_t1 MODIFY t int; +--error 1264 +ALTER TABLE geo_t1 MODIFY t double; +--error 1292 +ALTER TABLE geo_t1 MODIFY t datetime; +--error 1292 +ALTER TABLE geo_t1 MODIFY t timestamp; +--error 1292 +ALTER TABLE geo_t1 MODIFY t date; +--error 1366 +ALTER TABLE geo_t1 MODIFY t varchar(1); +--error 1235 +ALTER TABLE geo_t1 MODIFY t ENUM('a','b'); +--error 1235 +ALTER TABLE geo_t1 MODIFY t SET('a','b'); +--error 1235 +ALTER TABLE geo_t1 MODIFY t JSON; +# mysql success but truncate +--error 1406 +ALTER TABLE geo_t1 MODIFY t BIT(8); +--error 1366 +ALTER TABLE geo_t1 MODIFY t varchar(256); +--error 1366 +ALTER TABLE geo_t1 MODIFY t text; + +ALTER TABLE geo_t1 MODIFY t LONGTEXT CHARSET binary; +select hex(t) from geo_t1; +ALTER TABLE geo_t1 MODIFY t GeomCollection; +select hex(t) from geo_t1; + +--error 1366 +ALTER TABLE geo_t1 change t tt int; +--error 1264 +ALTER TABLE geo_t1 change t tt double; +--error 1292 +ALTER TABLE geo_t1 change t tt datetime; +--error 1292 +ALTER TABLE geo_t1 change t tt timestamp; +--error 1292 +ALTER TABLE geo_t1 change t tt date; +--error 1366 +ALTER TABLE geo_t1 change t tt varchar(1); +--error 1235 +ALTER TABLE geo_t1 change t tt ENUM('a','b'); +--error 1235 +ALTER TABLE geo_t1 change t tt SET('a','b'); +--error 1235 +ALTER TABLE geo_t1 change t tt JSON; +# mysql success but truncate +--error 1406 +ALTER TABLE geo_t1 change t tt BIT(8); +--error 1366 +ALTER TABLE geo_t1 change t tt varchar(256); +--error 1366 +ALTER TABLE geo_t1 change t tt text; + +ALTER TABLE geo_t1 change t tt LONGTEXT CHARSET binary; +select hex(tt) from geo_t1; +ALTER TABLE geo_t1 change tt t GeomCollection; +select hex(t) from geo_t1; + +--echo bugfix: 53251134 +--disable_warnings +drop table if exists geo_t1; +--enable_warnings +create table geo_t1 as select ST_Centroid(ST_geomfromtext('POLYGON((121.474243 31.234504, 121.471775 31.233348, 121.470724 31.23155, 121.471603 31.230229, 121.472655 31.230357, 121.475777 31.232045, 121.474243 31.234504))')) centroid ; +desc geo_t1; +drop table geo_t1; diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_dml_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_dml_mysql.test index 03dfec4813..b7d819bc16 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_dml_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_dml_mysql.test @@ -8,7 +8,7 @@ alter system set _enable_defensive_check = 1; ### 1. Test for spatial index base DML constraint. if (1) { --disable_warnings - DROP TABLE IF EXISTS spatial_index_dml_constraint, tt1; + DROP TABLE IF EXISTS spatial_index_dml_constraint, tt1, T_GEO; --enable_warnings ## 1.1 Insert row @@ -425,3 +425,21 @@ select st_astext(geo) from t_geo; alter system set _enable_defensive_check = 0; drop table t_geo; + +create table t_geo(geo geometry); +--error 1416 +insert into t_geo values(x'000000000140340000000000004034000000000000'); +insert into t_geo values(st_geomfromwkb(x'000000000140340000000000004034000000000000')); +select hex(geo) from t_geo; +drop table t_geo; + +--disable_warnings +DROP TABLE IF EXISTS tt3; +--enable_warnings +create table tt3(id int,p geometry); +insert into tt3 values(1,st_geomfromtext('point(1 2)')); +update tt3 set p=x'000000000101000000000000000000F03F0000000000000840'; +select st_astext(p) from tt3; +update tt3 set p =x'0000000001E9030000000000000000F03F00000000000000400000000000000840'; +select st_astext(p) from tt3; +drop table tt3; diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_filter_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_filter_mysql.test index 15273e410c..79220fad70 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_filter_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_filter_mysql.test @@ -559,3 +559,25 @@ select /*+ full(t1) */ c1, ST_AsText(g) FROM t1 where (ST_Intersects(g, ST_GeomF or ST_Intersects(g, ST_GeomFromText('POINT(1 1)', 4326))); drop table t1; + +--echo bugfix: 53888898 +--error 0,1051 +drop table t1; +create table t1 ( +id int , +gg geometry not null srid 0, +SPATIAL INDEX index_gis(gg) +); +insert into t1 values(1,ST_GeomFromText('POLYGON((0 0 ,10 0 ,10 11 ,0 11, 0 0 ))')); + +select * from t1 where ST_Contains(gg,ST_Centroid(gg)); +select * from t1 where ST_Contains(ST_Centroid(gg),gg); +select * from t1 where ST_Within(gg,ST_Centroid(gg)); +select * from t1 where ST_Within(ST_Centroid(gg),gg); +select * from t1 where ST_Equals(gg,ST_Centroid(gg)); +select * from t1 where ST_Equals(ST_Centroid(gg),gg); +select * from t1; +delete from t1 where ST_Contains(ST_Centroid(gg),gg); +select * from t1; +delete from t1 where ST_Contains(gg,ST_Centroid(gg)); +select * from t1; diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_type_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_type_mysql.test index d466b055d7..ddfaa9966d 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/geometry_type_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/geometry_type_mysql.test @@ -594,6 +594,16 @@ if (0) { SELECT ST_ASTEXT(ST_MULTIPOLYGONFROMTEXT(@multipolygon_text)); SELECT ST_ASTEXT(ST_MULTIPOLYGONFROMWKB(ST_ASWKB(ST_GEOMFROMTEXT(@multipolygon_text)))); } + +--disable_warnings + DROP TABLE IF EXISTS t1; +--enable_warnings +create table t1(id int, point point); +INSERT into t1 values(3,Point(100, 23)); +select ST_AsText(point) from t1 where ST_SymDifference(point,point) in (ST_SymDifference(point,Point(10, 23)),ST_SymDifference(point,point)); +select ST_AsText(point) from t1 where ST_SymDifference(point,point) not in (ST_SymDifference(point,Point(10, 23)),ST_SymDifference(point,point)); +drop table t1; + --echo # Final cleanup DROP TABLE gis_point; DROP TABLE gis_linestring; @@ -605,4 +615,8 @@ DROP TABLE gis_geometrycollection; DROP TABLE gis_geometry; DROP TABLE tab; DROP TABLE tab2; - +# bugfix 53179664 +select LINESTRING(point(7,6),point(1,1),point(NULL,NULL)); +select LINESTRING(point(NULL,NULL)); +select LINESTRING(point(5,NULL)); +select POLYGON(LINESTRING(POINT(0,0), POINT(0,5), POINT(5,5), POINT(5,0), POINT(NULL,0))); diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/st_astext_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/st_astext_mysql.test index 12acde59b8..b45f18fa9a 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/st_astext_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/st_astext_mysql.test @@ -324,3 +324,18 @@ select st_astext(cast(x'00000000010700000007000000010100000000000000000024400000 # bugfix: --error ER_GIS_INVALID_DATA select st_astext(ST_GeometryFromWKB(x'0103000000020000000500000000000000000034C00000000000002440000000000000544000000000008056C000000000000054C000000000000034C00000000000000000000000000000544000000000000034C00000000000002440',4326,'axis-order=lat-long')); + +--echo bugfix: 53543670 +--error 3037 +SELECT ST_AsText(x'0000000001EC0300000600000001E903000000000000000026400000000000003640000000000040534001E903000000000000008040400000000000004640000000000000404001E90300000000000000804B4000000000008050400000000000C05E4001E90300000000000000405340000000000000564000000000000054C001E90300000000000000C0584000000000000026400000000000000000'); + +--echo bugfix: 53520655 +select ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOLYGON(((0 0 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0),(0.11 0.11 0.55454545645645,0.12 0.12 0.125121435,0.13 0.13 0.4541,0.11 0.11 1)))')); +--error 3037 +select ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOLYGON(((0 1 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0),(0.11 0.11 0.55454545645645,0.12 0.12 0.125121435,0.13 0.13 0.4541,0.11 0.11 1)))')); +--error 3037 +select ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOLYGON(((0 1 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0),(0.11 0 0.55454545645645,0.12 0.12 0.125121435,0.13 0.13 0.4541,0.11 0.11 1)))')); + +select ST_ASTEXT(ST_GEOMFROMTEXT('POLYGON((0 0 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0))')); +--error 3037 +select ST_ASTEXT(ST_GEOMFROMTEXT('POLYGON((0 1 0.546548564,0 1 1.00000000001,1 87646 0,0 0 0))')); diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/st_covers_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/st_covers_mysql.test index a7b3e8b55f..b1e936e82a 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/st_covers_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/st_covers_mysql.test @@ -1023,3 +1023,8 @@ select _st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30) select _st_covers(ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))'),x'00000000010300000001000000050000000000000000000000000000000000000000000000000024400000000000000000000000000000244000000000000024400000000000000000000000000000244000000000000000000000000000000001'); --error ER_GIS_INVALID_DATA select _st_covers(x'00000000010300000001000000050000000000000000000000000000000000000000000000000024400000000000000000000000000000244000000000000024400000000000000000000000000000244000000000000000000000000000000001',ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))')); + +--echo bugfix: 54036048 +select _st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 5),POLYGON((1 0,10 0,10 10,1 0)),MULTILINESTRING((-5 -10 , 5 -20 ), (-15 -10 , 30 15)),GEOMETRYCOLLECTION(point(1 20)))',26918),ST_GeomFromText('POLYGON((0 0,10 10,20 20,30 30,0 0))',26918)); +select _st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 5),POLYGON((1 0,10 0,10 10,1 0)),MULTILINESTRING((-5 -10 , 5 -20 ), (-15 -10 , 30 15)),GEOMETRYCOLLECTION(point(1 20)))',4326),ST_GeomFromText('POLYGON((0 0,10 10,20 20,30 30,0 0))',4326)); +select _st_covers(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(10 5),POLYGON((1 0,10 0,10 10,1 0)),MULTILINESTRING((-5 -10 , 5 -20 ), (-15 -10 , 30 15)),GEOMETRYCOLLECTION(point(1 20)))'),ST_GeomFromText('POLYGON((0 0,10 10,20 20,30 30,0 0))')); \ No newline at end of file diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/st_distance_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/st_distance_mysql.test index 7986b6bcff..1791d85a49 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/st_distance_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/st_distance_mysql.test @@ -2427,3 +2427,43 @@ select st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian"); select st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian yard"); select st_distance(ST_GEOMFROMTEXT('POINT(0 0)', 4053), ST_GEOMFROMTEXT('POINT(0 45)', 4053), "Indian yard (1937)"); + +--echo bugfix: 54168045 +# case 1 +--error 3037 +select ST_Distance(ST_Distance(ST_GeomFromText('POINT(-1.000009 -30)'),ST_GeomFromText('POINT(-1.000009 -30)')),ST_GeomFromText('POINT(-1.000009 -30 )')); +# case 2 +SET @g1 = ST_GeomFromText('POINT(1 1)',4326); +SET @g2 = ST_GeomFromText('POINT(2 2)',4326); +--error 3902 +SELECT ST_Distance(@g1, @g2, 1); +# cover cases +--error 0,1051 +drop table t2; +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da datetime(6), dt datetime(6), sc char(50), sv varchar(50), b blob, tx text); +insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'POINT(1 1)', 'POINT(1 1)', 'POINT(1 1)', 'POINT(1 1)'); +select ST_Distance(it1, it1) from t2; +--error 3037 +select ST_Distance(it2, it2) from t2; +--error 3037 +select ST_Distance(i, i) from t2; +--error 3037 +select ST_Distance(ib, ib) from t2; +--error 3037 +select ST_Distance(f, f) from t2; +--error 3037 +select ST_Distance(d, d) from t2; +--error 3548 +select ST_Distance(y, y) from t2; +--error 3548 +select ST_Distance(da, da) from t2; +--error 3548 +select ST_Distance(dt, dt) from t2; +--error 3548 +select ST_Distance(sc, sc) from t2; +--error 3548 +select ST_Distance(sv, sv) from t2; +--error 3548 +select ST_Distance(b, b) from t2; +--error 3548 +select ST_Distance(tx, tx) from t2; diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/st_geomfromtext_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/st_geomfromtext_mysql.test index a6948e0431..2e35b5a79f 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/st_geomfromtext_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/st_geomfromtext_mysql.test @@ -2370,96 +2370,64 @@ select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((5 3, 7 4, 9 5, 11 6, 13 7, 5 3)))')); select ST_AsText(ST_GeomFromText('MULTIPOINT(1 2)')); select ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4)')); - --error 3037 select ST_AsText(ST_GeomFromText('LINESTRING(1 2 3,4 5 6)')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4))')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4),LINESTRING(5 6,7 8))')); select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4),(5 6,7 8))')); select ST_AsText(ST_GeomFromText('POINT(1 2)')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2))')); - --error 3037 select ST_AsText(ST_GeomFromText('POINT(1 2 3)')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2,5 6 -3),LINESTRING(7 8 -1,9 10 -2,11 12 -3))')); select ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4,5 6,7 8,9 10)')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4,5 6),LINESTRING(7 8,9 10))')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(5 6 -55,7 8 -22),LINESTRING(1 2 -1,3 4 -2))')); select ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4,5 6,7 8)')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2 -1))')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2))')); select ST_AsText(ST_GeomFromText('LINESTRING(1 2,3 4,5 6)')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2,3 4,5 6))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2,5 6 -3),(7 8 -1,9 10 -2,11 12 -3))')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2)))')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4))')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2)))')); select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2)))')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2 -2),POINT(3 4 -2),POINT(5 6 -3))')); select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4,5 6))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2,5 6 -3))')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4),POINT(5 6))')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POINT(1 2 -1),POINT(3 4 -2))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTILINESTRING((5 6 -55,7 8 -22),(1 2 -1,3 4 -2))')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2,5 6 -3))')); - --error 3037 select ST_AsText(ST_GeomFromText('LINESTRING(1 2 3,4 5 6,7 8 9)')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)))')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(LINESTRING(1 2 -1,3 4 -2),LINESTRING(5 6 -55,7 8 -22))')); - --error 3037 select ST_AsText(ST_GeomFromText('LINESTRING(1 2 3,4 5 6,7 8 9,10 11 12)')); select ST_AsText(ST_GeomFromText('MULTIPOINT(1 2,3 4)')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTIPOINT(1 2 3,4 5 6)')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTIPOINT(1 2 3,4 5 6,7 8 9)')); select ST_AsText(ST_GeomFromText('MULTIPOINT(1 2,4 5,7 8)')); select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4))')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)))')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)))')); select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')); select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2,3 4,5 6),(7 8,9 10))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTILINESTRING((1 2 -1,3 4 -2),(5 6 -55,7 8 -22))')); select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')); select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2)))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)))')); select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)),((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1)))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01)))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)),((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)))')); - --error 3037 select ST_AsText(ST_GeomFromText('MULTIPOLYGON(((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01)),((0 0.1 0,0.2 10.3 0,10.4 10.5 0,10.7 0.6 0,0 0.1 0)))')); - --error 3037 select ST_AsText(ST_GeomFromText('GEOMETRYCOLLECTION(POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0)))')); select ST_AsText(ST_GeomFromText('POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1))')); - --error 3037 select ST_AsText(ST_GeomFromText('POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01))')); select ST_AsText(ST_GeomFromText('POLYGON((0 0.1,0.2 10.3,10.4 10.5,10.7 0.6,0 0.1),(2 2,2 3,3 3,3 2,2 2))')); - --error 3037 select ST_AsText(ST_GeomFromText('POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01))')); - --error 3037 select ST_AsText(ST_GeomFromText('POLYGON((0 0.1 -0.01,0.2 10.3 -0.02,10.4 10.5 -0.03,10.7 0.6 -0.04,0 0.1 -0.01),(2 2 -0.01,2 3 -0.01,3 3 -0.01,3 2 -0.01,2 2 -0.01),(4 2 0,4 3 0,5 3 0,5 2 0,4 2 0))')); --echo # check result collation under old sql engine @@ -2488,3 +2456,44 @@ # bugfix: SELECT _ST_ASEWKT(_ST_GEOGRAPHYFROMTEXT('SRID=0;point(123.32112345678987654 -321.123)')); SELECT _ST_ASEWKT(_ST_GEOGRAPHYFROMTEXT('SRID=4326;point(180 180)')); + +--echo bugfix: 54159493 +--error 3037 +select ST_GeomFromText('geomcollection(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))'); +--error 3037 +select _ST_GEOGRAPHYFROMTEXT('geomcollection(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))'); +--error 3037 +select _ST_GeogFromText('geomcollection(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))'); + +--echo bugfix: 53612010 +--error 0,1051 +drop table typy_set; +create table typy_set (em enum('春','point(0 5)')); +insert into typy_set values('point(0 5)'); +select ST_GeomFromText(em ) from typy_set; +select ST_AsText(ST_GeomFromText(em )) from typy_set; +--error 0,1051 +drop table t2; +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da datetime(6), dt datetime(6), sc char(50), sv varchar(50), b blob, tx text); +insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)'); +select ST_GeomFromText(it1) from t2; +--error 3037 +select ST_GeomFromText(it2) from t2; +--error 3037 +select ST_GeomFromText(i) from t2; +--error 3037 +select ST_GeomFromText(ib) from t2; +--error 3037 +select ST_GeomFromText(f) from t2; +--error 3037 +select ST_GeomFromText(d) from t2; +--error 3037 +select ST_GeomFromText(y) from t2; +--error 3037 +select ST_GeomFromText(da) from t2; +--error 3037 +select ST_GeomFromText(dt) from t2; +select ST_GeomFromText(sc) from t2; +select ST_GeomFromText(sv) from t2; +select ST_GeomFromText(b) from t2; +select ST_GeomFromText(tx) from t2; diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/st_geomfromwkb_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/st_geomfromwkb_mysql.test index 15c4cd15b3..16be43759e 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/st_geomfromwkb_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/st_geomfromwkb_mysql.test @@ -150,3 +150,54 @@ select ST_GeometryFromWKB(x'010100000000000000000034C00000000000002E40',4326,11) select ST_GeometryFromWKB(x'010100000000000000000034C00000000000002E40','axis-order=long-lat','srid=4326'); --error 3558 select ST_GeomFromWKB(x'010100000000000000000034C00000000000002E40','axis-order=long-lat','srid=4326'); + +# BigEnd +# point +select st_astext(st_geomfromwkb(x'000000000140340000000000004034000000000000')); +select st_astext(st_geomfromwkb(x'000000000140340000000000004034000000000000', 4326)); +# linestring +SELECT ST_astext(ST_GEOMFROMWKB(X'0000000002000000023FF00000000000003FF000000000000040000000000000004000000000000000')); +# polygon +SELECT ST_astext(ST_GEOMFROMWKB(X'00000000030000000100000005000000000000000000000000000000004008000000000000000000000000000040000000000000003FF00000000000003FF00000000000003FF000000000000000000000000000000000000000000000')); +# multipoint +SELECT ST_astext(ST_GEOMFROMWKB(X'00000000040000000200000000013FF00000000000003FF000000000000000000000013FF00000000000003FF0000000000000')); +# multilinestring +select st_astext(st_geomfromwkb(x'0000000005000000020000000002000000020000000000000000000000000000000040654000000000000000000000000000000000000200000002405400000000000000000000000000004054000000000000404E000000000000')); +# multiPOLYGON +select st_astext(st_geomfromwkb(x'0000000006000000010000000003000000010000000640140000000000004008000000000000401C00000000000040100000000000004022000000000000401400000000000040260000000000004018000000000000402A000000000000401C00000000000040140000000000004008000000000000')); +# collection +select st_astext(st_geomfromwkb(x'000000000700000008000000000100000000000000003FF000000000000000000000020000000200000000000000003FF000000000000040240000000000004026000000000000000000000300000001000000050000000000000000000000000000000000000000000000004024000000000000402400000000000040240000000000004024000000000000000000000000000000000000000000000000000000000000000000000400000006000000000100000000000000003FF000000000000000000000014000000000000000400800000000000000000000014010000000000000401400000000000000000000014018000000000000401C00000000000000000000014020000000000000402200000000000000000000014024000000000000402600000000000000000000020000000200000000000000003FF00000000000004024000000000000402600000000000000000000020000000200000000000000004024000000000000402400000000000000000000000000000000000003000000010000000500000000000000003FF000000000000000000000000000004014000000000000401400000000000040180000000000004014000000000000000000000000000000000000000000003FF0000000000000000000000300000001000000054014000000000000401000000000000040140000000000004024000000000000402400000000000040260000000000004024000000000000401400000000000040140000000000004010000000000000')); + +--echo bugfix: 53757359 +SELECT st_geometryfromwkb(null); +SELECT st_geometryfromwkb(st_geometryfromwkb(null)); +SELECT st_geometryfromwkb(st_length(null)); +--error 0,1051 +drop table t2; +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da datetime(6), dt datetime(6), sc char(50), sv varchar(50), b blob, tx text); +insert into t2 values (NULL, 1, 3, 4, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)', 'LINESTRING(0 0,10 10)'); +select st_geometryfromwkb(it1) from t2; +--error 3037 +select st_geometryfromwkb(it2) from t2; +--error 3037 +select st_geometryfromwkb(i) from t2; +--error 3037 +select st_geometryfromwkb(ib) from t2; +--error 3037 +select st_geometryfromwkb(f) from t2; +--error 3037 +select st_geometryfromwkb(d) from t2; +--error 3037 +select st_geometryfromwkb(y) from t2; +--error 3037 +select st_geometryfromwkb(da) from t2; +--error 3037 +select st_geometryfromwkb(dt) from t2; +--error 3037 +select st_geometryfromwkb(sc) from t2; +--error 3037 +select st_geometryfromwkb(sv) from t2; +--error 3037 +select st_geometryfromwkb(b) from t2; +--error 3037 +select st_geometryfromwkb(tx) from t2; \ No newline at end of file diff --git a/tools/deploy/mysql_test/test_suite/geometry/t/st_srid_mysql.test b/tools/deploy/mysql_test/test_suite/geometry/t/st_srid_mysql.test index 49546837a2..3113610bc4 100644 --- a/tools/deploy/mysql_test/test_suite/geometry/t/st_srid_mysql.test +++ b/tools/deploy/mysql_test/test_suite/geometry/t/st_srid_mysql.test @@ -117,3 +117,6 @@ SELECT _ST_SETSRID(ST_GEOMFROMTEXT('POINT'),NULL); # bugfix : select st_astext(st_srid(x'0000000001030000000300000005000000000010000000000000000000000000000000000000002440000000000000000000000000000024400000000000002440000000000000000000000000000024400000000000000000000000000000000005000000000000000000144000000000000014400000000000001C4000000000000014400000000000001C400000000000001C4000000000000014400000000000001C40000000000000144000000000000014410500000000000000000014C000000000000014C00000000000001CC000000000000014C00000000000001CC00000000000001CC000000000000014C00000000000001CC000000000000014C000000000000014C0',0)); + +--echo bugfix: 53257405 +select st_srid(st_geomfromtext('point(100 100)')) - 3; \ No newline at end of file diff --git a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_data_type.result b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_data_type.result index f2f1c02280..3da2f8826a 100644 --- a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_data_type.result +++ b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_data_type.result @@ -52,6 +52,7 @@ data_type data_type_str data_type_class 48 GEOMETRY 23 49 UDT 24 50 DECIMAL_INT 25 +51 COLLECTION 26 select data_type, data_type_str, data_type_class from __all_virtual_data_type order by data_type; data_type data_type_str data_type_class 0 NULL 0 @@ -105,6 +106,7 @@ data_type data_type_str data_type_class 48 GEOMETRY 23 49 UDT 24 50 DECIMAL_INT 25 +51 COLLECTION 26 select * from __all_virtual_data_type where data_type = 22; data_type data_type_str data_type_class 22 VARCHAR 10 @@ -159,6 +161,7 @@ JSON JSON GEOMETRY GEOMETRY UDT UDT DECIMAL_INT DECIMAL_INT +COLLECTION COLLECTION show create table __all_virtual_data_type; Table Create Table __all_virtual_data_type CREATE TABLE `__all_virtual_data_type` ( diff --git a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_data_type_class.result b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_data_type_class.result index 9b77d3cb18..e1f77e9be1 100644 --- a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_data_type_class.result +++ b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_data_type_class.result @@ -26,6 +26,7 @@ data_type_class data_type_class_str 23 GEOMETRY 24 UDT 25 DECIMAL_INT +26 COLLECTION select data_type_class, data_type_class_str from __all_virtual_data_type_class; data_type_class data_type_class_str 0 NULL @@ -53,6 +54,7 @@ data_type_class data_type_class_str 23 GEOMETRY 24 UDT 25 DECIMAL_INT +26 COLLECTION select * from __all_virtual_data_type_class where data_type_class = 10; data_type_class data_type_class_str 10 STRING @@ -107,6 +109,7 @@ JSON JSON GEOMETRY GEOMETRY UDT UDT DECIMAL_INT DECIMAL_INT +COLLECTION COLLECTION show create table __all_virtual_data_type_class; Table Create Table __all_virtual_data_type_class CREATE TABLE `__all_virtual_data_type_class` ( diff --git a/unittest/share/CMakeLists.txt b/unittest/share/CMakeLists.txt index 196e53c575..2df92806f9 100644 --- a/unittest/share/CMakeLists.txt +++ b/unittest/share/CMakeLists.txt @@ -62,11 +62,13 @@ ob_unittest(test_geo_bin) ob_unittest(test_s2adapter) ob_unittest(test_geo_common) ob_unittest(test_wkt_parser) +ob_unittest(test_geo_3d) ob_unittest(test_geo_tree) ob_unittest(test_geo_srs) ob_unittest(test_geo_srs_parser) ob_unittest(test_geo_func_difference) ob_unittest(test_geo_func_union) +ob_unittest(test_geo_func_box) ob_unittest(test_throttling_utils) ob_unittest(test_json_base) diff --git a/unittest/share/test_defined_expr_func_by_type.result b/unittest/share/test_defined_expr_func_by_type.result index a772a4826d..7ec6b17a65 100644 --- a/unittest/share/test_defined_expr_func_by_type.result +++ b/unittest/share/test_defined_expr_func_by_type.result @@ -51,6 +51,7 @@ : defined : not defined : defined + : defined /**************** TINYINT ****************/ @@ -105,6 +106,7 @@ : not defined : not defined : not defined + : not defined /**************** SMALLINT ****************/ @@ -159,6 +161,7 @@ : not defined : not defined : not defined + : not defined /**************** MEDIUMINT ****************/ @@ -213,6 +216,7 @@ : not defined : not defined : not defined + : not defined /**************** INT ****************/ @@ -267,6 +271,7 @@ : not defined : not defined : not defined + : not defined /**************** BIGINT ****************/ @@ -321,6 +326,7 @@ : not defined : not defined : not defined + : not defined /**************** TINYINT UNSIGNED ****************/ @@ -375,6 +381,7 @@ : not defined : not defined : not defined + : not defined /**************** SMALLINT UNSIGNED ****************/ @@ -429,6 +436,7 @@ : not defined : not defined : not defined + : not defined /**************** MEDIUMINT UNSIGNED ****************/ @@ -483,6 +491,7 @@ : not defined : not defined : not defined + : not defined /**************** INT UNSIGNED ****************/ @@ -537,6 +546,7 @@ : not defined : not defined : not defined + : not defined /**************** BIGINT UNSIGNED ****************/ @@ -591,6 +601,7 @@ : not defined : not defined : not defined + : not defined /**************** FLOAT ****************/ @@ -645,6 +656,7 @@ : not defined : not defined : not defined + : not defined /**************** DOUBLE ****************/ @@ -699,6 +711,7 @@ : not defined : not defined : not defined + : not defined /**************** FLOAT UNSIGNED ****************/ @@ -753,6 +766,7 @@ : not defined : not defined : not defined + : not defined /**************** DOUBLE UNSIGNED ****************/ @@ -807,6 +821,7 @@ : not defined : not defined : not defined + : not defined /**************** DECIMAL ****************/ @@ -861,6 +876,7 @@ : not defined : not defined : not defined + : not defined /**************** DECIMAL UNSIGNED ****************/ @@ -915,6 +931,7 @@ : not defined : not defined : not defined + : not defined /**************** DATETIME ****************/ @@ -969,6 +986,7 @@ : not defined : not defined : not defined + : not defined /**************** TIMESTAMP ****************/ @@ -1023,6 +1041,7 @@ : not defined : not defined : not defined + : not defined /**************** DATE ****************/ @@ -1077,6 +1096,7 @@ : not defined : not defined : not defined + : not defined /**************** TIME ****************/ @@ -1131,6 +1151,7 @@ : not defined : not defined : not defined + : not defined /**************** YEAR ****************/ @@ -1185,6 +1206,7 @@ : not defined : not defined : not defined + : not defined /**************** VARCHAR ****************/ @@ -1239,6 +1261,7 @@ : not defined : not defined : not defined + : not defined /**************** CHAR ****************/ @@ -1293,6 +1316,7 @@ : not defined : not defined : not defined + : not defined /**************** HEX_STRING ****************/ @@ -1347,6 +1371,7 @@ : not defined : not defined : not defined + : not defined /**************** EXT ****************/ @@ -1401,6 +1426,7 @@ : defined : not defined : defined + : defined /**************** UNKNOWN ****************/ @@ -1455,6 +1481,7 @@ : not defined : not defined : not defined + : not defined /**************** TINYTEXT ****************/ @@ -1509,6 +1536,7 @@ : not defined : not defined : not defined + : not defined /**************** TEXT ****************/ @@ -1563,6 +1591,7 @@ : not defined : not defined : not defined + : not defined /**************** MEDIUMTEXT ****************/ @@ -1617,6 +1646,7 @@ : not defined : not defined : not defined + : not defined /**************** LONGTEXT ****************/ @@ -1671,6 +1701,7 @@ : not defined : not defined : not defined + : not defined /**************** BIT ****************/ @@ -1725,6 +1756,7 @@ : not defined : not defined : not defined + : not defined /**************** ENUM ****************/ @@ -1779,6 +1811,7 @@ : not defined : not defined : not defined + : not defined /**************** SET ****************/ @@ -1833,6 +1866,7 @@ : not defined : not defined : not defined + : not defined /**************** ENUM_INNER ****************/ @@ -1887,6 +1921,7 @@ : not defined : not defined : not defined + : not defined /**************** SET_INNER ****************/ @@ -1941,6 +1976,7 @@ : not defined : not defined : not defined + : not defined /**************** TIMESTAMP_WITH_TIME_ZONE ****************/ @@ -1995,6 +2031,7 @@ : not defined : not defined : not defined + : not defined /**************** TIMESTAMP_WITH_LOCAL_TIME_ZONE ****************/ @@ -2049,6 +2086,7 @@ : not defined : not defined : not defined + : not defined /**************** TIMESTAMP ****************/ @@ -2103,6 +2141,7 @@ : not defined : not defined : not defined + : not defined /**************** RAW ****************/ @@ -2157,6 +2196,7 @@ : not defined : not defined : not defined + : not defined /**************** INTERVAL_YEAR_TO_MONTH ****************/ @@ -2211,6 +2251,7 @@ : not defined : not defined : not defined + : not defined /**************** INTERVAL_DAY_TO_SECOND ****************/ @@ -2265,6 +2306,7 @@ : not defined : not defined : not defined + : not defined /**************** NUMBER_FLOAT ****************/ @@ -2319,6 +2361,7 @@ : not defined : not defined : not defined + : not defined /**************** NVARCHAR2 ****************/ @@ -2373,6 +2416,7 @@ : not defined : not defined : not defined + : not defined /**************** NCHAR ****************/ @@ -2427,6 +2471,7 @@ : not defined : not defined : not defined + : not defined /**************** ROWID ****************/ @@ -2481,6 +2526,7 @@ : not defined : not defined : not defined + : not defined /**************** LOB ****************/ @@ -2535,6 +2581,7 @@ : not defined : not defined : not defined + : not defined /**************** JSON ****************/ @@ -2589,6 +2636,7 @@ : not defined : not defined : not defined + : not defined /**************** GEOMETRY ****************/ @@ -2643,6 +2691,7 @@ : defined : not defined : not defined + : not defined /**************** UDT ****************/ @@ -2697,6 +2746,7 @@ : not defined : not defined : not defined + : not defined /**************** DECIMAL_INT ****************/ @@ -2751,4 +2801,60 @@ : not defined : not defined : defined + : not defined + +/**************** COLLECTION ****************/ + + : defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined diff --git a/unittest/share/test_defined_func_by_type.result b/unittest/share/test_defined_func_by_type.result index a772a4826d..7ec6b17a65 100644 --- a/unittest/share/test_defined_func_by_type.result +++ b/unittest/share/test_defined_func_by_type.result @@ -51,6 +51,7 @@ : defined : not defined : defined + : defined /**************** TINYINT ****************/ @@ -105,6 +106,7 @@ : not defined : not defined : not defined + : not defined /**************** SMALLINT ****************/ @@ -159,6 +161,7 @@ : not defined : not defined : not defined + : not defined /**************** MEDIUMINT ****************/ @@ -213,6 +216,7 @@ : not defined : not defined : not defined + : not defined /**************** INT ****************/ @@ -267,6 +271,7 @@ : not defined : not defined : not defined + : not defined /**************** BIGINT ****************/ @@ -321,6 +326,7 @@ : not defined : not defined : not defined + : not defined /**************** TINYINT UNSIGNED ****************/ @@ -375,6 +381,7 @@ : not defined : not defined : not defined + : not defined /**************** SMALLINT UNSIGNED ****************/ @@ -429,6 +436,7 @@ : not defined : not defined : not defined + : not defined /**************** MEDIUMINT UNSIGNED ****************/ @@ -483,6 +491,7 @@ : not defined : not defined : not defined + : not defined /**************** INT UNSIGNED ****************/ @@ -537,6 +546,7 @@ : not defined : not defined : not defined + : not defined /**************** BIGINT UNSIGNED ****************/ @@ -591,6 +601,7 @@ : not defined : not defined : not defined + : not defined /**************** FLOAT ****************/ @@ -645,6 +656,7 @@ : not defined : not defined : not defined + : not defined /**************** DOUBLE ****************/ @@ -699,6 +711,7 @@ : not defined : not defined : not defined + : not defined /**************** FLOAT UNSIGNED ****************/ @@ -753,6 +766,7 @@ : not defined : not defined : not defined + : not defined /**************** DOUBLE UNSIGNED ****************/ @@ -807,6 +821,7 @@ : not defined : not defined : not defined + : not defined /**************** DECIMAL ****************/ @@ -861,6 +876,7 @@ : not defined : not defined : not defined + : not defined /**************** DECIMAL UNSIGNED ****************/ @@ -915,6 +931,7 @@ : not defined : not defined : not defined + : not defined /**************** DATETIME ****************/ @@ -969,6 +986,7 @@ : not defined : not defined : not defined + : not defined /**************** TIMESTAMP ****************/ @@ -1023,6 +1041,7 @@ : not defined : not defined : not defined + : not defined /**************** DATE ****************/ @@ -1077,6 +1096,7 @@ : not defined : not defined : not defined + : not defined /**************** TIME ****************/ @@ -1131,6 +1151,7 @@ : not defined : not defined : not defined + : not defined /**************** YEAR ****************/ @@ -1185,6 +1206,7 @@ : not defined : not defined : not defined + : not defined /**************** VARCHAR ****************/ @@ -1239,6 +1261,7 @@ : not defined : not defined : not defined + : not defined /**************** CHAR ****************/ @@ -1293,6 +1316,7 @@ : not defined : not defined : not defined + : not defined /**************** HEX_STRING ****************/ @@ -1347,6 +1371,7 @@ : not defined : not defined : not defined + : not defined /**************** EXT ****************/ @@ -1401,6 +1426,7 @@ : defined : not defined : defined + : defined /**************** UNKNOWN ****************/ @@ -1455,6 +1481,7 @@ : not defined : not defined : not defined + : not defined /**************** TINYTEXT ****************/ @@ -1509,6 +1536,7 @@ : not defined : not defined : not defined + : not defined /**************** TEXT ****************/ @@ -1563,6 +1591,7 @@ : not defined : not defined : not defined + : not defined /**************** MEDIUMTEXT ****************/ @@ -1617,6 +1646,7 @@ : not defined : not defined : not defined + : not defined /**************** LONGTEXT ****************/ @@ -1671,6 +1701,7 @@ : not defined : not defined : not defined + : not defined /**************** BIT ****************/ @@ -1725,6 +1756,7 @@ : not defined : not defined : not defined + : not defined /**************** ENUM ****************/ @@ -1779,6 +1811,7 @@ : not defined : not defined : not defined + : not defined /**************** SET ****************/ @@ -1833,6 +1866,7 @@ : not defined : not defined : not defined + : not defined /**************** ENUM_INNER ****************/ @@ -1887,6 +1921,7 @@ : not defined : not defined : not defined + : not defined /**************** SET_INNER ****************/ @@ -1941,6 +1976,7 @@ : not defined : not defined : not defined + : not defined /**************** TIMESTAMP_WITH_TIME_ZONE ****************/ @@ -1995,6 +2031,7 @@ : not defined : not defined : not defined + : not defined /**************** TIMESTAMP_WITH_LOCAL_TIME_ZONE ****************/ @@ -2049,6 +2086,7 @@ : not defined : not defined : not defined + : not defined /**************** TIMESTAMP ****************/ @@ -2103,6 +2141,7 @@ : not defined : not defined : not defined + : not defined /**************** RAW ****************/ @@ -2157,6 +2196,7 @@ : not defined : not defined : not defined + : not defined /**************** INTERVAL_YEAR_TO_MONTH ****************/ @@ -2211,6 +2251,7 @@ : not defined : not defined : not defined + : not defined /**************** INTERVAL_DAY_TO_SECOND ****************/ @@ -2265,6 +2306,7 @@ : not defined : not defined : not defined + : not defined /**************** NUMBER_FLOAT ****************/ @@ -2319,6 +2361,7 @@ : not defined : not defined : not defined + : not defined /**************** NVARCHAR2 ****************/ @@ -2373,6 +2416,7 @@ : not defined : not defined : not defined + : not defined /**************** NCHAR ****************/ @@ -2427,6 +2471,7 @@ : not defined : not defined : not defined + : not defined /**************** ROWID ****************/ @@ -2481,6 +2526,7 @@ : not defined : not defined : not defined + : not defined /**************** LOB ****************/ @@ -2535,6 +2581,7 @@ : not defined : not defined : not defined + : not defined /**************** JSON ****************/ @@ -2589,6 +2636,7 @@ : not defined : not defined : not defined + : not defined /**************** GEOMETRY ****************/ @@ -2643,6 +2691,7 @@ : defined : not defined : not defined + : not defined /**************** UDT ****************/ @@ -2697,6 +2746,7 @@ : not defined : not defined : not defined + : not defined /**************** DECIMAL_INT ****************/ @@ -2751,4 +2801,60 @@ : not defined : not defined : defined + : not defined + +/**************** COLLECTION ****************/ + + : defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined + : not defined diff --git a/unittest/share/test_geo_3d.cpp b/unittest/share/test_geo_3d.cpp new file mode 100644 index 0000000000..1f555a1ea1 --- /dev/null +++ b/unittest/share/test_geo_3d.cpp @@ -0,0 +1,434 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#include +#define private public +#define protected public +#include "lib/geo/ob_geo_3d.h" +#include "lib/geo/ob_wkt_parser.h" +#undef private +#undef protected + +#include + +namespace oceanbase { +namespace common { +class TestGeo3D : public ::testing::Test +{ +public: + TestGeo3D() + {} + ~TestGeo3D() + {} + + ObString to_hex(const ObString &str) { + uint64_t out_str_len = str.length() * 2; + int64_t pos = 0; + char *data = static_cast(allocator_.alloc(out_str_len)); + hex_print(str.ptr(), str.length(), data, out_str_len, pos); + return ObString(out_str_len, data); + } + + ObString mock_to_wkb(ObGeometry *geo) { + ObString wkb; + if (OB_NOT_NULL(geo) && !geo->is_tree()) { + ObIWkbGeometry *geo_bin = reinterpret_cast(geo); + wkb = geo_bin->data_; + } + return wkb; + } + + void compare_3d_to_2d_result(ObGeoType geo_type, ObString &wkb_3d, ObString &wkb_2d); + void compare_to_3d_wkt_result(ObGeoType geo_type, ObString &wkt_3d, ObString &wkt_3d_res); + void check_wkb_is_valid_3d(ObString &wkt, bool is_valid); + void check_reserver_coordinate(ObString &wkt); + // construct data + template + int append_val(ObStringBuffer &buf, T t, ObGeoWkbByteOrder bo); + int append_pointz(ObStringBuffer &buf, double x, double y, double z, ObGeoWkbByteOrder bo); + int mock_get_tenant_srs_item(ObIAllocator &allocator, uint64_t srs_id, const ObSrsItem *&srs_item); +private: + ObArenaAllocator allocator_; + // disallow copy + DISALLOW_COPY_AND_ASSIGN(TestGeo3D); +}; + +template +int TestGeo3D::append_val(ObStringBuffer &buf, T t, ObGeoWkbByteOrder bo) +{ + INIT_SUCC(ret); + if (OB_FAIL(buf.reserve(sizeof(T)))) { + } else { + char *ptr = buf.ptr() + buf.length(); + ObGeoWkbByteOrderUtil::write(ptr, t, bo); + ret = buf.set_length(buf.length() + sizeof(T)); + } + return ret; +} + +template<> +int TestGeo3D::append_val(ObStringBuffer &buf, uint8_t t, ObGeoWkbByteOrder bo) +{ + return buf.append(reinterpret_cast(&t), sizeof(uint8_t)); +} + +int TestGeo3D::append_pointz(ObStringBuffer &buf, double x, double y, double z, ObGeoWkbByteOrder bo) +{ + INIT_SUCC(ret); + if (OB_FAIL(append_val(buf, x, bo))) { + } else if (OB_FAIL(append_val(buf, y, bo))) { + } else if (OB_FAIL(append_val(buf, z, bo))) { + } + return ret; +} + +void TestGeo3D::compare_3d_to_2d_result(ObGeoType geo_type, ObString &wkt_3d, ObString &wkb_2d) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo_3d = NULL; + ObGeometry *geo_2d = NULL; + ASSERT_EQ(OB_SUCCESS, ObWktParser::parse_wkt(allocator, wkt_3d, geo_3d, true, false)); + ASSERT_TRUE(NULL != geo_3d); + ASSERT_EQ(geo_3d->type(), geo_type); + ASSERT_EQ(OB_SUCCESS, static_cast(geo_3d)->to_2d_geo(allocator, geo_2d)); + ASSERT_TRUE(NULL != geo_2d); + ASSERT_EQ(geo_2d->type(), static_cast(static_cast(geo_type) - 1000)); + ObString wkb_2d_res = to_hex(mock_to_wkb(geo_2d)); + ASSERT_EQ(wkb_2d_res, wkb_2d); +} + +void TestGeo3D::compare_to_3d_wkt_result(ObGeoType geo_type, ObString &wkt_3d, ObString &wkt_3d_res) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo_3d = NULL; + ASSERT_EQ(OB_SUCCESS, ObWktParser::parse_wkt(allocator, wkt_3d, geo_3d, true, false)); + ASSERT_TRUE(NULL != geo_3d); + ASSERT_EQ(geo_3d->type(), geo_type); + ObString wkt; + ASSERT_EQ(OB_SUCCESS, static_cast(geo_3d)->to_wkt(allocator, wkt)); + std::cout<length(), geo->val()); + ObGeometry3D geo_3d; + geo_3d.set_data(wkb); + bool is_valid = false; + if (OB_SUCCESS == geo_3d.check_wkb_valid()) { + is_valid = true; + } else { + is_valid = false; + } + // std::cout<length(), geo->val()); + ObString wkb_copy; + ob_write_string(allocator, wkb, wkb_copy); + ObGeometry3D geo_3d; + geo_3d.set_data(wkb); + ASSERT_EQ(OB_SUCCESS, geo_3d.reverse_coordinate()); + ASSERT_NE(0, MEMCMP(geo_3d.val(), wkb_copy.ptr(), wkb.length())); + // ASSERT_EQ(OB_SUCCESS, geo_3d.to_wkt(allocator,res_wkt)); + // std::cout<<"wkt: "<(buf, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_val(buf, static_cast(ObGeoType::LINESTRINGZ), bo)); + ASSERT_EQ(OB_SUCCESS, append_val(buf, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_pointz(buf, 1, 1, 1, bo)); + geo_3d.set_data(buf.string()); + ASSERT_NE(OB_SUCCESS, geo_3d.check_wkb_valid()); + + // linestring + ASSERT_EQ(OB_SUCCESS, append_val(buf, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_val(buf, static_cast(ObGeoType::LINESTRINGZ), bo)); + ASSERT_EQ(OB_SUCCESS, append_val(buf, 2, bo)); + ASSERT_EQ(OB_SUCCESS, append_pointz(buf, 1, 1, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_pointz(buf, 1, 2, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_pointz(buf, 1, 3, 1, bo)); + geo_3d.set_data(buf.string()); + ASSERT_NE(OB_SUCCESS, geo_3d.check_wkb_valid()); + + // polygon + buf.reset(); + ASSERT_EQ(OB_SUCCESS, append_val(buf, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_val(buf, static_cast(ObGeoType::POLYGONZ), bo)); + ASSERT_EQ(OB_SUCCESS, append_val(buf, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_val(buf, 3, bo)); + ASSERT_EQ(OB_SUCCESS, append_pointz(buf, 1, 1, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_pointz(buf, 1, 2, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_pointz(buf, 1, 3, 1, bo)); + geo_3d.set_data(buf.string()); + ASSERT_NE(OB_SUCCESS, geo_3d.check_wkb_valid()); +} + +TEST_F(TestGeo3D, test_check_wkb_1) +{ + // point + ObString wkt_2d = ObString::make_string("POINT(1 1)"); + check_wkb_is_valid_3d(wkt_2d, false); + ObString wkt_3d = ObString::make_string("POINT Z (1 1 1)"); + check_wkb_is_valid_3d(wkt_3d, true); + // linestring + wkt_2d = ObString::make_string("LINESTRING (1 1,1 2)"); + check_wkb_is_valid_3d(wkt_2d, false); + wkt_3d = ObString::make_string("LINESTRING Z (1 1 1,1 2 1)"); + check_wkb_is_valid_3d(wkt_3d, true); + // polygon + wkt_3d = ObString::make_string("POLYGONZ((0 0 1,10 0 2 ,10 10 2,0 10 2,0 0 1))"); + check_wkb_is_valid_3d(wkt_3d, true); + wkt_2d = ObString::make_string("POLYGON((0 0,10 0 ,10 10,0 10,0 0))"); + check_wkb_is_valid_3d(wkt_2d, false); + // multi point + wkt_3d = ObString::make_string("MULTIPOINTZ((0 0 0), (2 0 1))"); + check_wkb_is_valid_3d(wkt_3d, true); + wkt_2d = ObString::make_string("MULTIPOINT((0 0), (2 0))"); + check_wkb_is_valid_3d(wkt_2d, false); + // multi linestring + wkt_3d = ObString::make_string("MULTILINESTRING Z ((0 0 1,2 0 2),(1 1 3,2 2 4))"); + check_wkb_is_valid_3d(wkt_3d, true); + wkt_2d = ObString::make_string("MULTILINESTRING((0 0,2 0),(1 1,2 2))"); + check_wkb_is_valid_3d(wkt_2d, false); + // multi polygon + wkt_3d = ObString::make_string("MULTIPOLYGON Z (((0 0 3,10 0 3,10 10 3,0 10 3,0 0 3)),((2 2 3,2 5 3,5 5 3,5 2 3,2 2 3)))"); + check_wkb_is_valid_3d(wkt_3d, true); + wkt_2d = ObString::make_string("MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)),((2 2,2 5,5 5,5 2,2 2)))"); + check_wkb_is_valid_3d(wkt_2d, false); + // collectionz + wkt_3d = ObString::make_string("GEOMETRYCOLLECTION Z (POINT Z (1 1 1),LINESTRING Z (0 0 2,1 1 3),POLYGON Z ((0 0 1" + ",10 0 2,10 10 2,0 10 2,0 0 1),(2 2 5,2 5 4,5 5 3,5 2 3,2 2 5)),GEOMETRYCOLLECTION Z" + " (MULTIPOINT Z ((0 0 0),(2 0 1)),MULTILINESTRING Z ((0 0 1,2 0 2),(1 1 3,2 2 4)),MULTIP" + "OLYGON Z (((0 0 3,10 0 3,10 10 3,0 10 3,0 0 3),(2 2 3,2 5 3,5 5 3,5 2 3,2 2 3)))))"); + check_wkb_is_valid_3d(wkt_3d, true); + wkt_2d = ObString::make_string("GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1),POLYGON((0 0" + ",10 0,10 10,0 10,0 0),(2 2,2 5,5 5,5 2,2 2)),GEOMETRYCOLLECTION" + " (MULTIPOINT(0 0,2 0),MULTILINESTRING((0 0,2 0),(1 1,2 2)),MULTIP" + "OLYGON(((0 0,10 0,10 10,0 10,0 0),(2 2,2 5,5 5,5 2,2 2)))))"); + check_wkb_is_valid_3d(wkt_2d, false); +} + +TEST_F(TestGeo3D, test_reserve_coordinate) +{ + ObString wkt_3d = ObString::make_string("POINT Z (1 2 1)"); + check_reserver_coordinate(wkt_3d); + wkt_3d = ObString::make_string("LINESTRING Z (1 2 1,3 4 1)"); + check_reserver_coordinate(wkt_3d); + wkt_3d = ObString::make_string("POLYGONZ((0 1 1,10 0 2 ,10 5 2,0 10 2,0 1 1))"); + check_reserver_coordinate(wkt_3d); + wkt_3d = ObString::make_string("MULTIPOINTZ((0 1 0), (2 0 1))"); + check_reserver_coordinate(wkt_3d); + wkt_3d = ObString::make_string("MULTILINESTRING Z ((0 1 1,2 0 2),(1 2 3,2 3 4))"); + check_reserver_coordinate(wkt_3d); + wkt_3d = ObString::make_string("MULTIPOLYGON Z (((0 1 3,10 0 3,10 5 3,0 10 3,0 1 3)),((2 2 3,2 5 3,5 5 3,5 2 3,2 2 3)))"); + check_reserver_coordinate(wkt_3d); + wkt_3d = ObString::make_string("GEOMETRYCOLLECTION Z (POINT Z (1 2 1),LINESTRING Z (0 2 2,1 3 3),POLYGON Z ((0 1 1" + ",10 0 2,10 5 2,0 10 2,0 1 1),(2 1 5,2 5 4,5 4 3,5 2 3,2 1 5)),GEOMETRYCOLLECTION Z" + " (MULTIPOINT Z (0 1 0,2 0 1),MULTILINESTRING Z ((0 1 1,2 0 2),(1 2 3,2 3 4)),MULTIP" + "OLYGON Z (((0 1 3,10 0 3,10 5 3,0 10 3,0 1 3),(2 1 3,2 5 3,5 10 3,5 2 3,2 1 3)))))"); + check_reserver_coordinate(wkt_3d); +} + +TEST_F(TestGeo3D, test_coordinate_range) +{ + const ObSrsItem *srs_item = NULL; + ObArenaAllocator allocator(ObModIds::TEST); + ASSERT_EQ(OB_SUCCESS, mock_get_tenant_srs_item(allocator, 4326, srs_item)); + ObStringBuffer buf(&allocator); + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian; + ObGeometry3D geo_3d; + // point valid + ASSERT_EQ(OB_SUCCESS, append_val(buf, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_val(buf, static_cast(ObGeoType::POINTZ), bo)); + ASSERT_EQ(OB_SUCCESS, append_pointz(buf, 180 * srs_item->angular_unit(), 89 * srs_item->angular_unit(), 1, bo)); + geo_3d.set_data(buf.string()); + ObGeoCoordRangeResult result; + ASSERT_EQ(OB_SUCCESS, geo_3d.check_3d_coordinate_range(srs_item, true, result)); + ASSERT_EQ(result.is_lati_out_range_, false); + ASSERT_EQ(result.is_long_out_range_, false); + // point invalid + buf.reset(); + ASSERT_EQ(OB_SUCCESS, append_val(buf, 1, bo)); + ASSERT_EQ(OB_SUCCESS, append_val(buf, static_cast(ObGeoType::POINTZ), bo)); + ASSERT_EQ(OB_SUCCESS, append_pointz(buf, 181 * srs_item->angular_unit(), 89 * srs_item->angular_unit(), 1, bo)); + geo_3d.set_data(buf.string()); + ObGeoCoordRangeResult result1; + ASSERT_EQ(OB_SUCCESS, geo_3d.check_3d_coordinate_range(srs_item, true, result)); + ASSERT_EQ(result.is_lati_out_range_, false); + ASSERT_EQ(result.is_long_out_range_, true); + ASSERT_TRUE(std::abs(result.value_out_range_ - 181) < 0.001); +} + +} // namespace common +} // namespace oceanbase + +int main(int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + system("rm -f test_geo_3d.log"); + OB_LOGGER.set_file_name("test_geo_3d.log"); + OB_LOGGER.set_log_level("INFO"); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/unittest/share/test_geo_bin.cpp b/unittest/share/test_geo_bin.cpp index 82fe4c6bfa..1bb791faef 100644 --- a/unittest/share/test_geo_bin.cpp +++ b/unittest/share/test_geo_bin.cpp @@ -13,6 +13,7 @@ #include #define BOOST_GEOMETRY_DISABLE_DEPRECATED_03_WARNING 1 #define BOOST_ALLOW_DEPRECATED_HEADERS 1 +#define USING_LOG_PREFIX LIB #include #define private public #include "lib/geo/ob_geo_bin.h" @@ -29,12 +30,22 @@ #include "lib/geo/ob_geo_reverse_coordinate_visitor.h" #include "lib/geo/ob_srs_info.h" #include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_sdo_geo_func_to_wkb.h" +#include "lib/geo/ob_sdo_geo_object.h" #include "observer/omt/ob_tenant_srs.h" +#include "lib/geo/ob_geo_3d.h" #include "share/schema/ob_multi_version_schema_service.h" #include "lib/random/ob_random.h" +#include "lib/string/ob_hex_utils_base.h" +#include "lib/geo/ob_wkb_to_json_visitor.h" +#include "lib/geo/ob_wkb_byte_order_visitor.h" +#include "lib/geo/ob_geo_interior_point_visitor.h" +#include "lib/geo/ob_wkt_parser.h" +#include "lib/geo/ob_geo_mvt_encode_visitor.h" #undef private #include +#include namespace oceanbase { @@ -160,13 +171,14 @@ int append_double(ObJsonBuffer& data, double val, ObGeoWkbByteOrder bo = ObGeoWk } void append_random_inner_point(ObJsonBuffer& data, common::ObVector& xv, common::ObVector& yv, - GeogValueValidType type = GeogValueValidType::NOT_DEFINED) + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { if (type == GeogValueValidType::NOT_DEFINED) { double x = static_cast(rand())/static_cast(rand()); double y = static_cast(rand())/static_cast(rand()); - ASSERT_EQ(OB_SUCCESS, append_double(data, x)); - ASSERT_EQ(OB_SUCCESS, append_double(data, y)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); xv.push_back(x); yv.push_back(y); } else if (type == GeogValueValidType::IN_RANGE) { @@ -175,8 +187,8 @@ void append_random_inner_point(ObJsonBuffer& data, common::ObVector& xv, x *= srs_item->angular_unit(); double y = fmod(static_cast(rand())/static_cast(rand()), static_cast(90)); y *= srs_item->angular_unit(); - ASSERT_EQ(OB_SUCCESS, append_double(data, x)); - ASSERT_EQ(OB_SUCCESS, append_double(data, y)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); xv.push_back(x); yv.push_back(y); } else { @@ -185,8 +197,8 @@ void append_random_inner_point(ObJsonBuffer& data, common::ObVector& xv, x += static_cast(180); double y = static_cast(rand())/static_cast(rand()); y += static_cast(90); - ASSERT_EQ(OB_SUCCESS, append_double(data, x)); - ASSERT_EQ(OB_SUCCESS, append_double(data, y)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); xv.push_back(x); yv.push_back(y); } @@ -201,39 +213,112 @@ void append_random_point(ObJsonBuffer& data, common::ObVector& xv, commo } void append_ring(ObJsonBuffer& data, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, - GeogValueValidType type = GeogValueValidType::NOT_DEFINED) + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { - ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum, bo)); for (int k = 0; k < pnum; k++) { if (type == GeogValueValidType::OUT_RANGE && k == pnum - 1) { - append_random_inner_point(data, xv, yv, GeogValueValidType::OUT_RANGE); + append_random_inner_point(data, xv, yv, GeogValueValidType::OUT_RANGE, bo); } else { - append_random_inner_point(data, xv, yv, type); + append_random_inner_point(data, xv, yv, type, bo); } - } } void append_line(ObJsonBuffer& data, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, - GeogValueValidType type = GeogValueValidType::NOT_DEFINED) + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { - ASSERT_EQ(OB_SUCCESS, append_bo(data)); - ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING)); - append_ring(data, pnum, xv, yv, type); + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING, bo)); + append_ring(data, pnum, xv, yv, type, bo); +} + +void append_random_inner_point_3d(ObJsonBuffer& data, common::ObVector& xv, common::ObVector& yv, + common::ObVector& zv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_TRUE(srs_item != NULL); + double x = fmod(static_cast(rand())/static_cast(rand()), static_cast(180)); + x *= srs_item->angular_unit(); + double y = fmod(static_cast(rand())/static_cast(rand()), static_cast(90)); + y *= srs_item->angular_unit(); + double z = fmod(static_cast(rand())/static_cast(rand()), static_cast(180)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, z, bo)); + xv.push_back(x); + yv.push_back(y); + zv.push_back(z); +} + +void append_line_3d(ObJsonBuffer& data, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + common::ObVector& zv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRINGZ, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum, bo)); + for (int k = 0; k < pnum; k++) { + append_random_inner_point_3d(data, xv, yv, zv, type, bo); + } +} + +void append_ring_3d(ObJsonBuffer& data, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + common::ObVector& zv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum, bo)); + for (int k = 0; k < pnum; k++) { + append_random_inner_point_3d(data, xv, yv, zv, type, bo); + } +} + +void append_poly_3d(ObJsonBuffer& data, uint32_t lnum, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + common::ObVector& zv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGONZ, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum, bo)); + // push rings + for (int j = 0; j < lnum; j++) { + append_ring_3d(data, pnum, xv, yv, zv, type, bo); + } +} + +void append_multi_line_3d(ObJsonBuffer& data, uint32_t lnum, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + common::ObVector& zv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTILINESTRINGZ, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum, bo)); + // push lines + for (int j = 0; j < lnum; j++) { + append_line_3d(data, pnum, xv, yv, zv, type, bo); + } } void append_poly(ObJsonBuffer& data, uint32_t lnum, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, - GeogValueValidType type = GeogValueValidType::NOT_DEFINED) + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { - ASSERT_EQ(OB_SUCCESS, append_bo(data)); - ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON)); - ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum)); + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum, bo)); // push rings for (int j = 0; j < lnum; j++) { if (type == GeogValueValidType::OUT_RANGE && j == lnum - 1) { - append_ring(data, pnum, xv, yv, GeogValueValidType::OUT_RANGE); + append_ring(data, pnum, xv, yv, GeogValueValidType::OUT_RANGE, bo); } else { - append_ring(data, pnum, xv, yv, type); + append_ring(data, pnum, xv, yv, type, bo); } } } @@ -254,14 +339,214 @@ void append_multi_point(ObJsonBuffer& data, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, - GeogValueValidType type = GeogValueValidType::NOT_DEFINED) + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) { - ASSERT_EQ(OB_SUCCESS, append_bo(data)); - ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTILINESTRING)); - ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum)); + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTILINESTRING, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum, bo)); // push lines for (int j = 0; j < lnum; j++) { - append_line(data, pnum, xv, yv, type); + append_line(data, pnum, xv, yv, type, bo); + } +} + +void append_rectangle(ObJsonBuffer& data, common::ObVector& xv, common::ObVector& yv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + uint32_t pnum = 5; + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum, bo)); + ASSERT_TRUE(srs_item != NULL); + + double lower_left_x = fmod(static_cast(rand())/static_cast(rand()), static_cast(180)); + lower_left_x *= srs_item->angular_unit(); + double lower_left_y = fmod(static_cast(rand())/static_cast(rand()), static_cast(90)); + lower_left_y *= srs_item->angular_unit(); + xv.push_back(lower_left_x); + yv.push_back(lower_left_y); + + double upper_right_x = fmod(static_cast(rand())/static_cast(rand()), static_cast(180)); + upper_right_x *= srs_item->angular_unit(); + double upper_right_y = fmod(static_cast(rand())/static_cast(rand()), static_cast(90)); + upper_right_y *= srs_item->angular_unit(); + xv.push_back(upper_right_x); + yv.push_back(upper_right_y); + + ASSERT_EQ(OB_SUCCESS, append_double(data, lower_left_x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, lower_left_y, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, upper_right_x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, lower_left_y, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, upper_right_x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, upper_right_y, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, lower_left_x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, upper_right_y, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, lower_left_x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, lower_left_y, bo)); +} + +void append_sdo_multi_point(ObJsonBuffer& data, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOINT, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum, bo)); + for (int i = 0; i < pnum; i++) { + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT, bo)); + append_random_inner_point(data, xv, yv, type, bo); + } +} + +void append_sdo_multi_point_3d(ObJsonBuffer& data, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + common::ObVector& zv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOINTZ, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum, bo)); + for (int i = 0; i < pnum; i++) { + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINTZ, bo)); + append_random_inner_point_3d(data, xv, yv, zv, type, bo); + } +} + +void append_sdo_multi_poly_3d(ObJsonBuffer& data, uint32_t lnum, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + common::ObVector& zv, + common::ObVector& pnumv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOLYGONZ, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum, bo)); + uint32_t fix_poly_num = 1; + // push rings + for (int j = 0; j < lnum; j++) { + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGONZ, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, fix_poly_num, bo)); + append_ring_3d(data, pnum, xv, yv, zv, type, bo); + pnumv.push_back(pnum); + // to do : rectangle + } +} + +void append_sdo_multi_poly(ObJsonBuffer& data, uint32_t lnum, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + common::ObVector& pnumv, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOLYGON, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum, bo)); + uint32_t fix_poly_num = 1; + // push rings + for (int j = 0; j < lnum; j++) { + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, fix_poly_num, bo)); + if (rand() % 2) { + append_ring(data, pnum, xv, yv, type, bo); // 1604 + pnumv.push_back(pnum); + } else { + append_rectangle(data, xv, yv, type, bo); // 84 + pnumv.push_back(2); + } + } +} + +void append_sdo_collection(ObJsonBuffer& data, uint32_t lnum, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + common::ObVector& types, + common::ObVector& pnums, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::GEOMETRYCOLLECTION, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum, bo)); + for (int j = 0; j < lnum; j++) { + if (rand() % 5 == 0) { + // point + double x = fmod(static_cast(rand())/static_cast(rand()), static_cast(180)); + x *= srs_item->angular_unit(); + double y = fmod(static_cast(rand())/static_cast(rand()), static_cast(90)); + y *= srs_item->angular_unit(); + xv.push_back(x); + yv.push_back(y); + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + types.push_back(ObGeoType::POINT); + pnums.push_back(1); + } else if (rand() % 5 == 1) { + // multipoint with pnum point + append_sdo_multi_point(data, pnum, xv, yv, type, bo); + types.push_back(ObGeoType::MULTILINESTRING); + pnums.push_back(pnum); + } else if (rand() % 5 == 2) { + // ring with pnum point + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 1, bo)); + append_ring(data, pnum, xv, yv, type, bo); + types.push_back(ObGeoType::POLYGON); + pnums.push_back(pnum); + } else if (rand() % 5 == 3) { + // rectangle + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 1, bo)); + append_rectangle(data, xv, yv, type, bo); + types.push_back(ObGeoType::POLYGON); + pnums.push_back(2); + } else { + // linestring with pnum point + append_line(data, pnum, xv, yv, type, bo); + types.push_back(ObGeoType::LINESTRING); + pnums.push_back(pnum); + } + } +} + +void append_sdo_collection_3d(ObJsonBuffer& data, uint32_t lnum, uint32_t pnum, common::ObVector& xv, common::ObVector& yv, + common::ObVector& zv, + common::ObVector& types, + common::ObVector& pnums, + GeogValueValidType type = GeogValueValidType::NOT_DEFINED, + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::GEOMETRYCOLLECTIONZ, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum, bo)); + for (int j = 0; j < lnum; j++) { + if (j % 4 == 0) { + // point + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINTZ, bo)); + append_random_inner_point_3d(data, xv, yv, zv, type, bo); + types.push_back(ObGeoType::POINTZ); + pnums.push_back(1); + } else if (j % 4 == 1) { + // multipoint with pnum point + append_sdo_multi_point_3d(data, pnum, xv, yv, zv,type, bo); + types.push_back(ObGeoType::MULTIPOINTZ); + pnums.push_back(pnum); + } else if (j % 4 == 2) { + // polygon + append_poly_3d(data, 1, 5, xv, yv, zv, type, bo); + types.push_back(ObGeoType::POLYGONZ); + pnums.push_back(5); + } else { + // linestring with pnum point + append_line_3d(data, pnum, xv, yv, zv, type, bo); + types.push_back(ObGeoType::LINESTRINGZ); + pnums.push_back(pnum); + } } } @@ -319,6 +604,235 @@ TEST_F(TestGeoBin, point) ASSERT_EQ(4.444, p2.get<1>()); } +TEST_F(TestGeoBin, wkb_to_json_visitor_point) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ObString res; + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 1.323)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 999.5456)); + + ObIWkbGeomPoint iwkb_geom; + iwkb_geom.set_data(data.string()); + ObWkbToJsonVisitor visitor(&allocator); + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json: " << std::string(res.ptr(), res.length()) << std::endl; + + visitor.reset(); + res.reset(); + ObIWkbGeogPoint iwkb_geog; + iwkb_geog.set_data(data.string()); + ASSERT_EQ(OB_SUCCESS, iwkb_geog.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json: " << std::string(res.ptr(), res.length()) << std::endl; + +} + +TEST_F(TestGeoBin, wkb_to_json_visitor_linestring) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ObString res; + uint32_t num = 5; + common::ObVector xv; + common::ObVector yv; + append_line(data, num, xv, yv); + + ObIWkbGeomLineString iwkb_geom; + iwkb_geom.set_data(data.string()); + ObWkbToJsonVisitor visitor(&allocator); + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json: " << std::string(res.ptr(), res.length()) << std::endl; + + visitor.reset(); + res.reset(); + ObIWkbGeogLineString iwkb_geog; + iwkb_geog.set_data(data.string()); + ASSERT_EQ(OB_SUCCESS, iwkb_geog.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json: " << std::string(res.ptr(), res.length()) << std::endl; +} + +TEST_F(TestGeoBin, wkb_to_json_visitor_polygon) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObString res; + ObJsonBuffer data(&allocator); + common::ObVector xv; + common::ObVector yv; + uint32_t rnum = 3; + uint32_t pnum = 2; + append_poly(data, rnum, pnum, xv, yv); + + ObIWkbGeogPolygon iwkb_geog_poly; + iwkb_geog_poly.set_data(data.string()); + ObWkbToJsonVisitor visitor(&allocator); + ASSERT_EQ(OB_SUCCESS, iwkb_geog_poly.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json: " << std::string(res.ptr(), res.length()) << std::endl; + + visitor.reset(); + res.reset(); + ObIWkbGeomPolygon iwkb_geom_poly; + iwkb_geom_poly.set_data(data.string()); + ASSERT_EQ(OB_SUCCESS, iwkb_geom_poly.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json: " << std::string(res.ptr(), res.length()) << std::endl; +} + +TEST_F(TestGeoBin, wkb_to_json_visitor_multi_point) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ObString res; + uint32_t num = 2; + common::ObVector xv; + common::ObVector yv; + append_multi_point(data, num, xv, yv); + + ObIWkbGeogMultiPoint iwkb_geog; + iwkb_geog.set_data(data.string()); + ObWkbToJsonVisitor visitor(&allocator); + ASSERT_EQ(OB_SUCCESS, iwkb_geog.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json:" << std::string(res.ptr(), res.length()) << std::endl; + + ObIWkbGeomMultiPoint iwkb_geom; + iwkb_geom.set_data(data.string()); + visitor.reset(); + res.reset(); + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json:" << std::string(res.ptr(), res.length()) << std::endl; +} + +TEST_F(TestGeoBin, wkb_to_json_visitor_multi_line) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ObString res; + uint32_t pnum = 2; + uint32_t lnum = 3; + common::ObVector xv; + common::ObVector yv; + append_multi_line(data, lnum, pnum, xv, yv); + + ObIWkbGeogMultiLineString iwkb_geog; + iwkb_geog.set_data(data.string()); + ObWkbToJsonVisitor visitor(&allocator); + ASSERT_EQ(OB_SUCCESS, iwkb_geog.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json:" << std::string(res.ptr(), res.length()) << std::endl; + + ObIWkbGeomMultiLineString iwkb_geom; + iwkb_geom.set_data(data.string()); + visitor.reset(); + res.reset(); + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json:" << std::string(res.ptr(), res.length()) << std::endl; +} + +TEST_F(TestGeoBin, wkb_to_json_visitor_multi_poly) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ObString res; + uint32_t polynum = 2; + uint32_t lnum = 3; + uint32_t pnum = 2; + common::ObVector xv[polynum]; + common::ObVector yv[polynum]; + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOLYGON)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, polynum)); + for (int i = 0; i < polynum; i++) { + append_poly(data, lnum, pnum, xv[i], yv[i]); + } + + ObIWkbGeogMultiPolygon iwkb_geog; + iwkb_geog.set_data(data.string()); + ObWkbToJsonVisitor visitor(&allocator); + ASSERT_EQ(OB_SUCCESS, iwkb_geog.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json:" << std::string(res.ptr(), res.length()) << std::endl; + + ObIWkbGeomMultiPolygon iwkb_geom; + iwkb_geom.set_data(data.string()); + visitor.reset(); + res.reset(); + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json:" << std::string(res.ptr(), res.length()) << std::endl; +} + +TEST_F(TestGeoBin, wkb_to_json_visitor_geom_collection) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ObString res; + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::GEOMETRYCOLLECTION)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 7)); + common::ObVector xv[7]; + common::ObVector yv[7]; + // point + append_random_point(data, xv[0], yv[0]); + // line + append_line(data, 2, xv[1], yv[1]); + // polygon + append_poly(data, 3, 2, xv[2], yv[2]); + // multipoint + append_multi_point(data, 3, xv[3], yv[3]); + // multiline + append_multi_line(data, 2, 2, xv[4], yv[4]); + // multipolygon + int64_t polygon_num = 2; + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOLYGON)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, polygon_num)); + for (int i = 0; i < polygon_num; i++) { + append_poly(data, 3, 2, xv[5], yv[5]); + } + // empty geometry + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::GEOMETRYCOLLECTION)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 0)); + + ObIWkbGeogCollection iwkb_geog; + iwkb_geog.set_data(data.string()); + ObWkbToJsonVisitor visitor(&allocator); + ASSERT_EQ(OB_SUCCESS, iwkb_geog.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json:" << std::string(res.ptr(), res.length()) << std::endl; + + ObIWkbGeomCollection iwkb_geom; + iwkb_geom.set_data(data.string()); + visitor.reset(); + res.reset(); + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + visitor.get_geojson(res); + ASSERT_EQ(false, res.empty()); + std::cout << "geo json:" << std::string(res.ptr(), res.length()) << std::endl; +} + TEST_F(TestGeoBin, linestring) { ObArenaAllocator allocator(ObModIds::TEST); @@ -1813,6 +2327,214 @@ TEST_F(TestGeoBin, intersection_ml) } } +TEST_F(TestGeoBin, mvt_encode_visitor_point) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 2)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 3)); + ObVector expect; + expect.push_back(9); + expect.push_back(4); + expect.push_back(6); + + ObIWkbGeomPoint iwkb_geom; + iwkb_geom.set_data(data.string()); + ObGeoMvtEncodeVisitor visitor; + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + ObVector &res = visitor.get_encode_buffer(); + ASSERT_EQ(expect.size(), res.size()); + for (int i = 0; i < res.size(); i++) { + ASSERT_EQ(expect.at(i), res.at(i)); + } +} + +TEST_F(TestGeoBin, mvt_encode_visitor_line) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 1)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 1)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 3)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 3)); + + ObVector expect; + expect.push_back(9); + expect.push_back(2); + expect.push_back(2); + expect.push_back(10); + expect.push_back(4); + expect.push_back(4); + + ObIWkbGeomLineString iwkb_geom; + iwkb_geom.set_data(data.string()); + ObGeoMvtEncodeVisitor visitor; + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + ObVector &res = visitor.get_encode_buffer(); + ASSERT_EQ(expect.size(), res.size()); + for (int i = 0; i < res.size(); i++) { + ASSERT_EQ(expect.at(i), res.at(i)); + } +} + +TEST_F(TestGeoBin, mvt_encode_visitor_multipoint) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOINT)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 3)); // point number + + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 1)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 1)); + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 2)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 2)); + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 3)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 3)); + + ObVector expect; + expect.push_back(25); + expect.push_back(2); + expect.push_back(2); + expect.push_back(2); + expect.push_back(2); + expect.push_back(2); + expect.push_back(2); + + ObIWkbGeomMultiPoint iwkb_geom; + iwkb_geom.set_data(data.string()); + ObGeoMvtEncodeVisitor visitor; + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + ObVector &res = visitor.get_encode_buffer(); + ASSERT_EQ(expect.size(), res.size()); + for (int i = 0; i < res.size(); i++) { + ASSERT_EQ(expect.at(i), res.at(i)); + } +} + +TEST_F(TestGeoBin, mvt_encode_visitor_multiline) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTILINESTRING)); + uint32_t lnum = 2; + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum)); + + uint32_t pnum = 3; + for (uint32_t i = 0; i < lnum; i++) { + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 1)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 1)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 3)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 3)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 5)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 5)); + } + ObVector expect; + expect.push_back(9); // move to + expect.push_back(2); + expect.push_back(2); + expect.push_back(18); // line to + expect.push_back(4); + expect.push_back(4); + expect.push_back(4); + expect.push_back(4); + expect.push_back(9); + expect.push_back(7); + expect.push_back(7); + expect.push_back(18); + expect.push_back(4); + expect.push_back(4); + expect.push_back(4); + expect.push_back(4); + + ObIWkbGeomMultiLineString iwkb_geom; + iwkb_geom.set_data(data.string()); + ObGeoMvtEncodeVisitor visitor; + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + ObVector &res = visitor.get_encode_buffer(); + ASSERT_EQ(expect.size(), res.size()); + for (int i = 0; i < res.size(); i++) { + ASSERT_EQ(expect.at(i), res.at(i)); + } +} + + +TEST_F(TestGeoBin, mvt_encode_visitor_poly) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 4)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 160)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 200)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 310)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 20)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 20)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 20)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 160)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 200)); + + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 4)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 160)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 200)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 260)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 40)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 70)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 40)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 160)); + ASSERT_EQ(OB_SUCCESS, append_double(data, 200)); + + /* POLYGON((160 200,310 20,20 20,160 200),(160 200,260 40,70 40,160 200)) */ + + ObVector expect; + expect.push_back(9); // move to + expect.push_back(320); + expect.push_back(400); + expect.push_back(18); // line to + expect.push_back(300); + expect.push_back(359); + expect.push_back(579); + expect.push_back(0); + expect.push_back(15); + + expect.push_back(9); // move to + expect.push_back(280); + expect.push_back(360); + expect.push_back(18); // line to + expect.push_back(200); + expect.push_back(319); + expect.push_back(379); + expect.push_back(0); + expect.push_back(15); + + ObIWkbGeomPolygon iwkb_geom; + iwkb_geom.set_data(data.string()); + ObGeoMvtEncodeVisitor visitor; + ASSERT_EQ(OB_SUCCESS, iwkb_geom.do_visit(visitor)); + ObVector &res = visitor.get_encode_buffer(); + ASSERT_EQ(expect.size(), res.size()); + for (int i = 0; i < res.size(); i++) { + ASSERT_EQ(expect.at(i), res.at(i)); + } +} + TEST_F(TestGeoBin, wkb_size_visitor_point) { ObArenaAllocator allocator(ObModIds::TEST); @@ -4515,14 +5237,875 @@ TEST_F(TestGeoBin, mbr_polygon_2) ASSERT_EQ(ObGeoTypeUtil::get_mbr_polygon(allocator, &srsbound_max, iwkb_geogp2, geop2), OB_EMPTY_RESULT); } +/*********************************************************/ +/* test for ObSdoGeoToWkb */ +/*********************************************************/ + +TEST_F(TestGeoBin, sdo_point) { + ObArenaAllocator allocator(ObModIds::TEST); + ObGeoStringBuffer data(&allocator); + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + double x = 19; + double y = 9.5456; + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); // 00 + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + ObString res = data.string(); + + // case 1: SDO_ELEM_INFO = NULL, SDO_POINT_TYPE = (x, y, NULL) + ObSdoPoint point(x, y); + ObSdoGeoObject geo(ObGeoType::POINT, point); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); + + // case 2: SDO_ELEM_INFO = (1,1,1), SDO_ORDINATES = (x, y) + ObArray elem_info; + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + + ObArray ordinate; + ASSERT_EQ(OB_SUCCESS, ordinate.push_back(x)); + ASSERT_EQ(OB_SUCCESS, ordinate.push_back(y)); + + // ObSdoGeoToWkb trans2(&allocator); + ObSdoGeoObject geo2(ObGeoType::POINT, elem_info, ordinate); + ObString wkb2; + trans.reset(); + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo2, wkb2)); + ASSERT_EQ(wkb2 == res, true); +} + +TEST_F(TestGeoBin, sdo_point_3d) { + ObArenaAllocator allocator(ObModIds::TEST); + ObGeoStringBuffer data(&allocator); + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + double x = 19; + double y = 9.5456; + double z = 18.5; + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); // 00 + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINTZ, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, z, bo)); + ObString res = data.string(); + + // case 1: SDO_ELEM_INFO = NULL, SDO_POINT_TYPE = (x, y, NULL) + ObSdoPoint point(x, y, z); + ObSdoGeoObject geo(ObGeoType::POINTZ, point, 0); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); + + // case 2: SDO_ELEM_INFO = (1,1,1), SDO_ORDINATES = (x, y) + ObArray elem_info; + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + + ObArray ordinate; + ASSERT_EQ(OB_SUCCESS, ordinate.push_back(x)); + ASSERT_EQ(OB_SUCCESS, ordinate.push_back(y)); + ASSERT_EQ(OB_SUCCESS, ordinate.push_back(z)); + // ObSdoGeoToWkb trans2(&allocator); + ObSdoGeoObject geo2(ObGeoType::POINTZ, elem_info, ordinate); + ObString wkb2; + trans.reset(); + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo2, wkb2)); + ASSERT_EQ(wkb2 == res, true); + + ObGeometry3D geo_3d; + geo_3d.set_data(wkb2); + ObSdoGeoObject geo3; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_sdo_geometry(geo3)); + ASSERT_EQ(geo == geo3, true); + + ObString geo_json; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_geo_json(&allocator, geo_json)); + std::cout << "geo json: " << std::string(geo_json.ptr(), geo_json.length()) << std::endl; +} + +TEST_F(TestGeoBin, sdo_linestring) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + uint32_t num = 1000000; + common::ObVector xv; + common::ObVector yv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_line(data, num, xv, yv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(2)); + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + ObArray ordinate; + for (uint32_t k = 0; k < num; k++) { + ordinate.push_back(xv[k]); + ordinate.push_back(yv[k]); + } + ObSdoGeoObject geo(ObGeoType::LINESTRING, elem_info, ordinate); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); +} + +TEST_F(TestGeoBin, sdo_linestring_3d) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + uint32_t num = 10; + common::ObVector xv; + common::ObVector yv; + common::ObVector zv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_line_3d(data, num, xv, yv, zv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(2)); + ASSERT_EQ(OB_SUCCESS, elem_info.push_back(1)); + ObArray ordinate; + for (uint32_t k = 0; k < num; k++) { + ordinate.push_back(xv[k]); + ordinate.push_back(yv[k]); + ordinate.push_back(zv[k]); + } + ObSdoGeoObject geo(ObGeoType::LINESTRINGZ, elem_info, ordinate, 0); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); + ObGeometry3D geo_3d; + geo_3d.set_data(wkb); + ObSdoGeoObject geo3; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_sdo_geometry(geo3)); + ASSERT_EQ(geo == geo3, true); + + ObString geo_json; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_geo_json(&allocator, geo_json)); + std::cout << "geo json: " << std::string(geo_json.ptr(), geo_json.length()) << std::endl; +} + +TEST_F(TestGeoBin, sdo_polygon) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + // 1 exterior line [lnum] inner line, every line has [pnum] point + uint32_t pnum = 100; + uint32_t lnum = 10001; + common::ObVector xv; + common::ObVector yv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_poly(data, lnum, pnum, xv, yv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ObArray ordinate; + size_t x_idx = 0; + size_t y_idx = 0; + for (uint64_t j = 0; j < lnum; j++) { + elem_info.push_back(ordinate.size() + 1); + if (j == 0) { + elem_info.push_back(1003); // ext ring + } else { + elem_info.push_back(2003); // inner ring + } + + elem_info.push_back(1); + + for (uint32_t k = 0; k < pnum; k++) { + ordinate.push_back(xv[x_idx++]); + ordinate.push_back(yv[y_idx++]); + } + } + + ObSdoGeoObject geo(ObGeoType::POLYGON, elem_info, ordinate); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); +} + + +TEST_F(TestGeoBin, sdo_polygon_3d) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + // 1 exterior line [lnum] inner line, every line has [pnum] point + uint32_t pnum = 5; + uint32_t lnum = 3; + common::ObVector xv; + common::ObVector yv; + common::ObVector zv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_poly_3d(data, lnum, pnum, xv, yv, zv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ObArray ordinate; + size_t x_idx = 0; + size_t y_idx = 0; + size_t z_idx = 0; + for (uint64_t j = 0; j < lnum; j++) { + elem_info.push_back(ordinate.size() + 1); + if (j == 0) { + elem_info.push_back(1003); // ext ring + } else { + elem_info.push_back(2003); // inner ring + } + + elem_info.push_back(1); + + for (uint32_t k = 0; k < pnum; k++) { + ordinate.push_back(xv[x_idx++]); + ordinate.push_back(yv[y_idx++]); + ordinate.push_back(zv[z_idx++]); + } + } + + ObSdoGeoObject geo(ObGeoType::POLYGONZ, elem_info, ordinate, 0); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); + ObGeometry3D geo_3d; + geo_3d.set_data(wkb); + ObSdoGeoObject geo3; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_sdo_geometry(geo3)); + ASSERT_EQ(geo == geo3, true); + + ObString geo_json; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_geo_json(&allocator, geo_json)); + std::cout << "geo json: " << std::string(geo_json.ptr(), geo_json.length()) << std::endl; +} + +TEST_F(TestGeoBin, sdo_multipoint) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + uint32_t num = 1000000; + common::ObVector xv; + common::ObVector yv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_sdo_multi_point(data, num, xv, yv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ObArray ordinate; + for (uint32_t k = 0; k < num; k++) { + elem_info.push_back(k * 2 + 1); + elem_info.push_back(1); + elem_info.push_back(1); + ordinate.push_back(xv[k]); + ordinate.push_back(yv[k]); + } + ObSdoGeoObject geo(ObGeoType::MULTIPOINT, elem_info, ordinate); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); +} + +TEST_F(TestGeoBin, sdo_multipoint_3d) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + uint32_t num = 10; + common::ObVector xv; + common::ObVector yv; + common::ObVector zv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_sdo_multi_point_3d(data, num, xv, yv, zv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ObArray ordinate; + elem_info.push_back(1); + elem_info.push_back(1); + elem_info.push_back(num); + for (uint32_t k = 0; k < num; k++) { + ordinate.push_back(xv[k]); + ordinate.push_back(yv[k]); + ordinate.push_back(zv[k]); + } + ObSdoGeoObject geo(ObGeoType::MULTIPOINTZ, elem_info, ordinate, 0); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); + ObGeometry3D geo_3d; + geo_3d.set_data(wkb); + ObSdoGeoObject geo3; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_sdo_geometry(geo3)); + ASSERT_EQ(geo == geo3, true); + + ObString geo_json; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_geo_json(&allocator, geo_json)); + std::cout << "geo json: " << std::string(geo_json.ptr(), geo_json.length()) << std::endl; +} + +TEST_F(TestGeoBin, sdo_multilinestring) { + get_srs_item(allocator_, 4326, srs_item); + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + // 1 exterior line 100 inner line, every line has 100 point + uint32_t pnum = 100; + uint32_t lnum = 10000; + common::ObVector xv; + common::ObVector yv; + append_multi_line(data, lnum, pnum, xv, yv, type, bo); + ObString res = data.string(); + + // + ObArray elem_info; + ObArray ordinate; + uint64_t index = 1; + for (size_t k = 0; k < lnum; k++) { + elem_info.push_back(index); + index += pnum * 2; + elem_info.push_back(2); + elem_info.push_back(1); + for (size_t j = 0; j < pnum; ++j) { + ordinate.push_back(xv[k * pnum + j]); + ordinate.push_back(yv[k * pnum + j]); + } + } + + ObSdoGeoObject geo(ObGeoType::MULTILINESTRING, elem_info, ordinate); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); +} + +TEST_F(TestGeoBin, sdo_multilinestring_3d) { + get_srs_item(allocator_, 4326, srs_item); + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + // 1 exterior line 100 inner line, every line has 100 point + uint32_t pnum = 10; + uint32_t lnum = 2; + common::ObVector xv; + common::ObVector yv; + common::ObVector zv; + append_multi_line_3d(data, lnum, pnum, xv, yv, zv, type, bo); + ObString res = data.string(); + + // + ObArray elem_info; + ObArray ordinate; + uint64_t index = 1; + for (size_t k = 0; k < lnum; k++) { + elem_info.push_back(index); + index += pnum * 3; + elem_info.push_back(2); + elem_info.push_back(1); + for (size_t j = 0; j < pnum; ++j) { + ordinate.push_back(xv[k * pnum + j]); + ordinate.push_back(yv[k * pnum + j]); + ordinate.push_back(zv[k * pnum + j]); + } + } + + ObSdoGeoObject geo(ObGeoType::MULTILINESTRINGZ, elem_info, ordinate, 0); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); + ObGeometry3D geo_3d; + geo_3d.set_data(wkb); + ObSdoGeoObject geo3; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_sdo_geometry(geo3)); + ASSERT_EQ(geo == geo3, true); + + ObString geo_json; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_geo_json(&allocator, geo_json)); + std::cout << "geo json: " << std::string(geo_json.ptr(), geo_json.length()) << std::endl; +} + +TEST_F(TestGeoBin, sdo_multipolygon) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + // 1 exterior line [lnum] inner polygon, every polygon has [pnum] point + uint32_t pnum = 100; + uint32_t lnum = 10001; + common::ObVector xv; + common::ObVector yv; + common::ObVector pnumv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_sdo_multi_poly(data, lnum, pnum, xv, yv, pnumv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ObArray ordinate; + size_t x_idx = 0; + size_t y_idx = 0; + int rec_num = 0; + uint64_t ordinate_sum = 1; + for (uint64_t j = 0; j < lnum; j++) { + if (j == 0) { + elem_info.push_back(1); + } else { + ordinate_sum += pnumv[j - 1] * 2; + elem_info.push_back(ordinate_sum); + } + elem_info.push_back(1003); + + if (pnumv[j] == 2) { + elem_info.push_back(3); // rectangle + ++rec_num; + } else { + elem_info.push_back(1); + } + + for (uint32_t k = 0; k < pnumv[j]; k++) { + ordinate.push_back(xv[x_idx++]); + ordinate.push_back(yv[y_idx++]); + } + } + ObSdoGeoObject geo(ObGeoType::MULTIPOLYGON, elem_info, ordinate); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); +} + +TEST_F(TestGeoBin, sdo_multipolygon_3d) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + // 1 exterior line [lnum] inner polygon, every polygon has [pnum] point + uint32_t pnum = 5; + uint32_t lnum = 3; + common::ObVector xv; + common::ObVector yv; + common::ObVector zv; + common::ObVector pnumv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_sdo_multi_poly_3d(data, lnum, pnum, xv, yv, zv, pnumv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ObArray ordinate; + size_t x_idx = 0; + size_t y_idx = 0; + size_t z_idx = 0; + int rec_num = 0; + uint64_t ordinate_sum = 1; + for (uint64_t j = 0; j < lnum; j++) { + if (j == 0) { + elem_info.push_back(1); + } else { + ordinate_sum += pnumv[j - 1] * 3; + elem_info.push_back(ordinate_sum); + } + elem_info.push_back(1003); + // to do : rectangle + elem_info.push_back(1); + + for (uint32_t k = 0; k < pnumv[j]; k++) { + ordinate.push_back(xv[x_idx++]); + ordinate.push_back(yv[y_idx++]); + ordinate.push_back(zv[z_idx++]); + } + } + ObSdoGeoObject geo(ObGeoType::MULTIPOLYGONZ, elem_info, ordinate, 0); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb == res, true); + ObGeometry3D geo_3d; + geo_3d.set_data(wkb); + ObSdoGeoObject geo3; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_sdo_geometry(geo3)); + ASSERT_EQ(geo == geo3, true); + + ObString geo_json; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_geo_json(&allocator, geo_json)); + std::cout << "geo json: " << std::string(geo_json.ptr(), geo_json.length()) << std::endl; +} + +TEST_F(TestGeoBin, sdo_collection) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + // [lnum] geometry + uint32_t lnum = 1024; + uint32_t pnum = 100; + common::ObVector xv; + common::ObVector yv; + common::ObVector types; + common::ObVector pnumv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_sdo_collection(data, lnum, pnum, xv, yv, types, pnumv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ObArray ordinate; + size_t x_idx = 0; + size_t y_idx = 0; + int rec_num = 0; + uint64_t ordinate_sum = 1; + for (uint64_t j = 0; j < lnum; j++) { + elem_info.push_back(ordinate.size() + 1); + if (types[j] == ObGeoType::POINT) { + elem_info.push_back(1); + elem_info.push_back(1); + } else if (types[j] == ObGeoType::MULTILINESTRING) { + elem_info.push_back(1); + elem_info.push_back(pnum); + } else if (types[j] == ObGeoType::LINESTRING) { + elem_info.push_back(2); + elem_info.push_back(1); + } else if (types[j] == ObGeoType::POLYGON) { + elem_info.push_back(1003); + if (pnumv[j] == 2) { + elem_info.push_back(3); // rectangle + ++rec_num; + } else { + elem_info.push_back(1); + } + } + for (uint32_t k = 0; k < pnumv[j]; k++) { + ordinate.push_back(xv[x_idx++]); + ordinate.push_back(yv[y_idx++]); + } + } + ObSdoGeoObject geo(ObGeoType::GEOMETRYCOLLECTION, elem_info, ordinate); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb, res); + ASSERT_EQ(wkb == res, true); +} + +TEST_F(TestGeoBin, sdo_collection_3d) { + get_srs_item(allocator_, 4326, srs_item); + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + // [lnum] geometry + uint32_t lnum = 24; + uint32_t pnum = 6; + common::ObVector xv; + common::ObVector yv; + common::ObVector zv; + common::ObVector types; + common::ObVector pnumv; + GeogValueValidType type = GeogValueValidType::IN_RANGE; + ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::BigEndian; + append_sdo_collection_3d(data, lnum, pnum, xv, yv, zv, types, pnumv, type, bo); + ObString res = data.string(); + + ObArray elem_info; + ObArray ordinate; + size_t x_idx = 0; + size_t y_idx = 0; + size_t z_idx = 0; + int rec_num = 0; + uint64_t ordinate_sum = 1; + for (uint64_t j = 0; j < lnum; j++) { + elem_info.push_back(ordinate.size() + 1); + if (types[j] == ObGeoType::POINTZ) { + elem_info.push_back(1); + elem_info.push_back(1); + } else if (types[j] == ObGeoType::MULTIPOINTZ) { + elem_info.push_back(1); + elem_info.push_back(pnum); + } else if (types[j] == ObGeoType::LINESTRINGZ) { + elem_info.push_back(2); + elem_info.push_back(1); + } else if (types[j] == ObGeoType::POLYGONZ) { + elem_info.push_back(1003); + elem_info.push_back(1); + // to do rectangle + } + for (uint32_t k = 0; k < pnumv[j]; k++) { + ordinate.push_back(xv[x_idx++]); + ordinate.push_back(yv[y_idx++]); + ordinate.push_back(zv[z_idx++]); + } + } + ObSdoGeoObject geo(ObGeoType::GEOMETRYCOLLECTIONZ, elem_info, ordinate, 0); + ObSdoGeoToWkb trans(&allocator); + ObString wkb; + ASSERT_EQ(OB_SUCCESS, trans.translate(&geo, wkb)); + ASSERT_EQ(wkb, res); + ASSERT_EQ(wkb == res, true); + ObGeometry3D geo_3d; + geo_3d.set_data(wkb); + ObSdoGeoObject geo3; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_sdo_geometry(geo3)); + ASSERT_EQ(geo == geo3, true); + + ObString geo_json; + ASSERT_EQ(OB_SUCCESS, geo_3d.to_geo_json(&allocator, geo_json)); + std::cout << "geo json: " << std::string(geo_json.ptr(), geo_json.length()) << std::endl; +} +/******************************************************************/ +/* test for ObWkbByteOrderVisitor */ +/******************************************************************/ +ObString to_hex(const ObString &str) { + uint64_t out_str_len = str.length() * 2; + int64_t pos = 0; + char *data = static_cast(allocator_.alloc(out_str_len)); + hex_print(str.ptr(), str.length(), data, out_str_len, pos); + return ObString(out_str_len, data); +} + +void mock_wkb_collection(ObJsonBuffer& data, ObGeoWkbByteOrder bo) { + int geo_num = 6; + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::GEOMETRYCOLLECTION, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, geo_num, bo)); + double x = 1.234; + double y = 5.678; + // point + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + // line with 2 point + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2, bo)); + for (int i = 0; i < 2; ++i) { + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + } + // polygon with 2 ring (1 polygon ring ,1 rectangle ring) + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 5, bo)); + for (int i = 0; i < 5; ++i) { + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + } + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2, bo)); + for (int i = 0; i < 2; ++i) { + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + } + // multipoint with 2 point + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOINT, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2, bo)); + for (int i = 0; i < 2; ++i) { + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + } + // multilinestring with 2 linestring + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTILINESTRING, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2, bo)); + for (int j = 0; j < 2; ++j) { + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2, bo)); + for (int i = 0; i < 2; ++i) { + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + } + } + // multipolygon with 2 polygon + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOLYGON, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2, bo)); + for (int j = 0; j < 2; ++j) { + ASSERT_EQ(OB_SUCCESS, append_bo(data, bo)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2, bo)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 5, bo)); + for (int i = 0; i < 5; ++i) { + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + } + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 2, bo)); + for (int i = 0; i < 2; ++i) { + ASSERT_EQ(OB_SUCCESS, append_double(data, x, bo)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y, bo)); + } + } +} + +TEST_F(TestGeoBin, big_endian_collection) { + int ret = 1; + ObArenaAllocator allocator(ObModIds::TEST); + + ObJsonBuffer big_data(&allocator); + mock_wkb_collection(big_data, ObGeoWkbByteOrder::BigEndian); + ObString big_wkb = big_data.string(); + + ObJsonBuffer little_data(&allocator); + mock_wkb_collection(little_data, ObGeoWkbByteOrder::LittleEndian); + ObString res_little_wkb = little_data.string(); + + ObGeometry *geo = NULL; + ASSERT_EQ(ObGeoTypeUtil::create_geo_by_type(allocator, ObGeoType::GEOMETRYCOLLECTION, false, true, geo), OB_SUCCESS); + ASSERT_EQ(geo != NULL, true); + geo->set_data(big_wkb); + ObWkbByteOrderVisitor be_visitor(&allocator, ObGeoWkbByteOrder::LittleEndian); + ASSERT_EQ(geo->do_visit(be_visitor), OB_SUCCESS); + ObString cal_little_wkb = be_visitor.get_wkb(); + ASSERT_EQ(res_little_wkb == cal_little_wkb , true) << res_little_wkb.length() << cal_little_wkb.length(); +} + +/************************************************ +** test for ObGeoInteriorPointVisitor +************************************************/ +TEST_F(TestGeoBin, interior_point_vistor_point) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo = NULL; + ObGeometry *interior_point = NULL; + ASSERT_EQ(ObWktParser::parse_wkt(allocator, "POINT(10 0)", geo, true, false), OB_SUCCESS); + ObGeoInteriorPointVisitor visitor(&allocator); + ASSERT_EQ(geo->do_visit(visitor), OB_SUCCESS); + ASSERT_EQ(visitor.get_interior_point(interior_point) , OB_SUCCESS); + ASSERT_EQ(interior_point->type(), ObGeoType::POINT); + ObCartesianPoint *pt = reinterpret_cast(interior_point); + ASSERT_EQ(pt->x(), 10); + ASSERT_EQ(pt->y(), 0); +} + +TEST_F(TestGeoBin, interior_point_vistor_line) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo = NULL; + ObGeometry *interior_point = NULL; + ASSERT_EQ(ObWktParser::parse_wkt(allocator, "LINESTRING(0 0, 5 0, 10 0)", geo, true, false), OB_SUCCESS); + ObGeoInteriorPointVisitor visitor(&allocator); + ASSERT_EQ(geo->do_visit(visitor), OB_SUCCESS); + ASSERT_EQ(visitor.get_interior_point(interior_point) , OB_SUCCESS); + ASSERT_EQ(interior_point->type(), ObGeoType::POINT); + ObCartesianPoint *pt = reinterpret_cast(interior_point); + ASSERT_EQ(pt->x(), 5); + ASSERT_EQ(pt->y(), 0); +} + +TEST_F(TestGeoBin, interior_point_vistor_poly) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo = NULL; + ObGeometry *interior_point = NULL; + ASSERT_EQ(ObWktParser::parse_wkt(allocator, "POLYGON((" + "182635.760119718 141846.477712277,182826.153168283 141974.473039044," + "182834.952846998 141857.67730337,182862.151853936 141851.277537031," + "182860.551912351 141779.280165725,182824.553226698 141748.881275618," + "182814.953577191 141758.480925126,182766.155358861 141721.682268681," + "182742.156235092 141744.881421657,182692.558045971 141716.882443927," + "182635.760119718 141846.477712277))", geo, true, false), OB_SUCCESS); + ObGeoInteriorPointVisitor visitor(&allocator); + ASSERT_EQ(geo->do_visit(visitor), OB_SUCCESS); + ASSERT_EQ(visitor.get_interior_point(interior_point) , OB_SUCCESS); + ASSERT_EQ(interior_point->type(), ObGeoType::POINT); + ObCartesianPoint *pt = reinterpret_cast(interior_point); + ASSERT_DOUBLE_EQ(pt->x(), 182755.89202988159); + ASSERT_DOUBLE_EQ(pt->y(), 141812.87893900101); +} + +TEST_F(TestGeoBin, interior_point_vistor_empty) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo = NULL; + ObGeometry *interior_point = NULL; + ASSERT_EQ(ObWktParser::parse_wkt(allocator, "GEOMETRYCOLLECTION EMPTY", geo, true, false), OB_SUCCESS); + ObGeoInteriorPointVisitor visitor(&allocator); + ASSERT_EQ(geo->do_visit(visitor), OB_SUCCESS); + ASSERT_EQ(visitor.get_interior_point(interior_point) , OB_SUCCESS); + ASSERT_EQ(interior_point->type(), ObGeoType::GEOMETRYCOLLECTION); + ASSERT_EQ(interior_point->is_empty(), true); +} + +void elevation_visitor_checker(ObIAllocator &allocator, const ObString &wkt1, const ObString &wkt2, const ObString &cal_wkt, const ObString &real_wkt) +{ + const double TOLERANCE = 0.00001; + ObGeometry *geo1 = nullptr; + ASSERT_EQ(ObWktParser::parse_wkt(allocator, wkt1, geo1, true, false), OB_SUCCESS); + ASSERT_EQ(ObGeoTypeUtil::is_3d_geo_type(geo1->type()), true); + ObGeometry *geo2 = nullptr; + ASSERT_EQ(ObWktParser::parse_wkt(allocator, wkt2, geo2, true, false), OB_SUCCESS); + ASSERT_EQ(ObGeoTypeUtil::is_3d_geo_type(geo2->type()), true); + ObGeometry *geo_cal = nullptr; + ASSERT_EQ(ObWktParser::parse_wkt(allocator, cal_wkt, geo_cal, true, false), OB_SUCCESS); + ASSERT_EQ(ObGeoTypeUtil::is_3d_geo_type(geo_cal->type()), false); + + ObGeoElevationVisitor visitor(allocator, nullptr); + ObGeometry *res_geo = nullptr; + ASSERT_EQ(visitor.init(*geo1, *geo2), OB_SUCCESS); + ASSERT_EQ(geo_cal->do_visit(visitor), OB_SUCCESS); + ASSERT_EQ(visitor.get_geometry_3D(res_geo), OB_SUCCESS); + ObString wkt; + ObGeometry3D *geo_3d = static_cast(res_geo); + ASSERT_EQ(geo_3d->to_wkt(allocator, wkt), OB_SUCCESS); + ASSERT_EQ(wkt == real_wkt, true); +} + +TEST_F(TestGeoBin, elevation_visitor) { + ObArenaAllocator allocator(ObModIds::TEST); + elevation_visitor_checker(allocator, "LINESTRING Z (0 0 0, 10 10 10)", "GEOMETRYCOLLECTION Z EMPTY", + "MULTIPOINT(-1 11, 11 11, 0 10, 5 10, 10 10, 0 5, 5 5, 10 5, 0 0, 5 0, 10 0, -1 -1, 5 -1, 11 -1)", + "MULTIPOINT Z (-1 11 5,11 11 10,0 10 5,5 10 5,10 10 10,0 5 5,5 5 5,10 5 5,0 0 0,5 0 5,10 0 5,-1 -1 0,5 -1 5,11 -1 5)"); + elevation_visitor_checker(allocator, "POLYGON Z ((1 6 50, 9 6 60, 9 4 50, 1 4 40, 1 6 50))", "GEOMETRYCOLLECTION Z EMPTY", + "MULTIPOINT(0 10,5 10,10 10,0 5,5 5,10 5,0 4,5 4,10 4,0 0,5 0,10 0)", + "MULTIPOINT Z (0 10 50,5 10 50,10 10 60,0 5 50,5 5 50,10 5 50,0 4 40,5 4 50,10 4 50,0 0 40,5 0 50,10 0 50)"); + elevation_visitor_checker(allocator, "MULTILINESTRING Z ((0 0 0, 10 10 8), (1 2 2, 9 8 6))", "GEOMETRYCOLLECTION Z EMPTY", + "MULTIPOINT(-1 11,11 11,0 10,5 10,10 10,0 5,5 5,10 5,0 0,5 0,10 0,-1 -1,5 -1,11 -1)", + "MULTIPOINT Z (-1 11 4,11 11 7,0 10 4,5 10 4,10 10 7,0 5 4,5 5 4,10 5 4,0 0 1,5 0 4,10 0 4,-1 -1 1,5 -1 4,11 -1 4)"); + elevation_visitor_checker(allocator, "LINESTRING Z (0 0 0, 10 10 8)", "LINESTRING Z (1 2 2, 9 8 6)", + "MULTIPOINT(-1 11,11 11,0 10,5 10,10 10,0 5,5 5,10 5,0 0,5 0,10 0,-1 -1,5 -1,11 -1)", + "MULTIPOINT Z (-1 11 4,11 11 7,0 10 4,5 10 4,10 10 7,0 5 4,5 5 4,10 5 4,0 0 1,5 0 4,10 0 4,-1 -1 1,5 -1 4,11 -1 4)"); + elevation_visitor_checker(allocator, "LINESTRING Z (0 5 0, 10 5 10)", "GEOMETRYCOLLECTION Z EMPTY", + "MULTIPOINT(0 10,5 10,10 10,0 5,5 5,10 5,0 0,5 0,10 0)", + "MULTIPOINT Z (0 10 0,5 10 5,10 10 10,0 5 0,5 5 5,10 5 10,0 0 0,5 0 5,10 0 10)"); + elevation_visitor_checker(allocator, "LINESTRING Z (5 0 0, 5 10 10)", "GEOMETRYCOLLECTION Z EMPTY", + "MULTIPOINT(0 10,5 10,10 10,0 5,5 5,10 5,0 0,5 0,10 0)", + "MULTIPOINT Z (0 10 10,5 10 10,10 10 10,0 5 5,5 5 5,10 5 5,0 0 0,5 0 0,10 0 0)"); + elevation_visitor_checker(allocator, "POINT Z (5 5 5)", "GEOMETRYCOLLECTION Z EMPTY", + "MULTIPOINT(0 9,5 9,9 9,0 5,5 5,9 5,0 0,5 0,9 0)", + "MULTIPOINT Z (0 9 5,5 9 5,9 9 5,0 5 5,5 5 5,9 5 5,0 0 5,5 0 5,9 0 5)"); + elevation_visitor_checker(allocator, "MULTIPOINT Z ((5 5 5), (5 5 9))", "GEOMETRYCOLLECTION Z EMPTY", + "MULTIPOINT(0 9,5 9,9 9,0 5,5 5,9 5,0 0,5 0,9 0)", + "MULTIPOINT Z (0 9 7,5 9 7,9 9 7,0 5 7,5 5 7,9 5 7,0 0 7,5 0 7,9 0 7)"); + elevation_visitor_checker(allocator, "LINESTRING Z (0 0 0, 10 10 10)", "GEOMETRYCOLLECTION Z EMPTY", + "LINESTRING (1 1, 9 9)", + "LINESTRING Z (1 1 0,9 9 10)"); + elevation_visitor_checker(allocator, "LINESTRING Z (0 0 0, 10 10 10)", "GEOMETRYCOLLECTION Z EMPTY", + "POLYGON ((1 9, 9 9, 9 1, 1 1, 1 9))", + "POLYGON Z ((1 9 5,9 9 10,9 1 5,1 1 0,1 9 5))"); +} } // namespace common } // namespace oceanbase int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); - // system("rm -f test_geo_bin.log"); - // OB_LOGGER.set_file_name("test_geo_bin.log"); - // OB_LOGGER.set_log_level("INFO"); + system("rm -f test_geo_bin.log"); + OB_LOGGER.set_file_name("test_geo_bin.log"); + OB_LOGGER.set_log_level("DEBUG"); return RUN_ALL_TESTS(); } \ No newline at end of file diff --git a/unittest/share/test_geo_common.cpp b/unittest/share/test_geo_common.cpp index a3809502ee..613489a6de 100644 --- a/unittest/share/test_geo_common.cpp +++ b/unittest/share/test_geo_common.cpp @@ -14,8 +14,14 @@ #include "lib/geo/ob_geo_common.h" #include "lib/geo/ob_geo_utils.h" #include "lib/json_type/ob_json_common.h" +#include "rpc/obmysql/ob_mysql_global.h" +#include "src/pl/ob_pl_user_type.h" +#include "src/pl/ob_pl_allocator.h" +#include "src/sql/engine/expr/ob_expr_sql_udt_utils.h" #define private public #undef private +using namespace oceanbase::pl; +using namespace oceanbase::sql; namespace oceanbase { namespace common { @@ -143,6 +149,158 @@ TEST_F(TestGeoCommon, test_wkb_byte_order_util) } } +void double_to_number(double d, ObArenaAllocator &allocator, number::ObNumber &num) +{ + char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE] = {0}; + uint64_t length = ob_gcvt(d, ob_gcvt_arg_type::OB_GCVT_ARG_DOUBLE, + sizeof(buf) - 1, buf, NULL); + ObString str(sizeof(buf), static_cast(length), buf); + ObPrecision res_precision = PRECISION_UNKNOWN_YET; + ObScale res_scale = -1; + ASSERT_EQ(num.from_sci_opt(str.ptr(), str.length(), allocator, &res_precision, &res_scale), OB_SUCCESS); +} + +void build_obj_uint64(uint64_t num, ObArenaAllocator &allocator, ObObj &res) { + number::ObNumber nmb; + ASSERT_EQ(nmb.from(num, allocator), OB_SUCCESS); + res.set_number(nmb); +} + +void build_obj_double(double num, ObArenaAllocator &allocator, ObObj &res) { + number::ObNumber nmb; + double_to_number(num, allocator, nmb); + res.set_number(nmb); +} + +void mock_write_sdo_elem_info(ObArray &elem_info, common::ObIAllocator &ctx_allocator, common::ObObj &result) +{ + pl::ObPLVArray *elem_array = reinterpret_cast(ctx_allocator.alloc(sizeof(pl::ObPLVArray))); + ASSERT_EQ(elem_array != NULL, true); + pl::ObPLCollAllocator *coll_allocator = reinterpret_cast(ctx_allocator.alloc(sizeof(pl::ObPLCollAllocator))); + ASSERT_EQ(coll_allocator != NULL, true); + + elem_array = new (elem_array) pl::ObPLVArray(300029); + coll_allocator = new (coll_allocator) pl::ObPLCollAllocator(elem_array); + elem_array->set_allocator(coll_allocator); + ObIAllocator *allocator = coll_allocator->get_allocator(); + uint64_t elem_cnt = elem_info.size(); + ASSERT_EQ(allocator != NULL, true); + ObObj *array_data = reinterpret_cast(allocator->alloc(sizeof(ObObj) * elem_cnt)); + ASSERT_EQ(array_data != NULL, true); + number::ObNumber elem_num; + for (uint64_t i = 0; i < elem_cnt; ++i) { + ASSERT_EQ(elem_num.from(elem_info[i], *allocator), OB_SUCCESS); + array_data[i].set_number(ObNumberType, elem_num); + } + + ObElemDesc elem_desc; + elem_array->set_capacity(elem_cnt); + elem_array->set_column_count(elem_cnt); + elem_array->set_count(elem_cnt); + elem_array->set_data(array_data); + elem_desc.set_pl_type(PL_VARRAY_TYPE); + elem_desc.set_not_null(false); + elem_desc.set_field_count(elem_cnt); + elem_array->set_element_desc(elem_desc); + elem_array->set_first(1); + elem_array->set_last(elem_cnt); + result.set_extend(reinterpret_cast(elem_array), elem_array->get_type()); +} + +void mock_write_sdo_ordinates(ObArray &ordinate, common::ObIAllocator &ctx_allocator, common::ObObj &result) +{ + pl::ObPLVArray *elem_array = reinterpret_cast(ctx_allocator.alloc(sizeof(pl::ObPLVArray))); + ASSERT_EQ(elem_array != NULL, true); + pl::ObPLCollAllocator *coll_allocator = reinterpret_cast(ctx_allocator.alloc(sizeof(pl::ObPLCollAllocator))); + ASSERT_EQ(coll_allocator != NULL, true); + + elem_array = new (elem_array) pl::ObPLVArray(300028); + coll_allocator = new (coll_allocator) pl::ObPLCollAllocator(elem_array); + elem_array->set_allocator(coll_allocator); + ObIAllocator *allocator = coll_allocator->get_allocator(); + uint64_t ori_size = ordinate.size(); + ASSERT_EQ(allocator != NULL, true); + ObObj *array_data = reinterpret_cast(allocator->alloc(sizeof(ObObj) * ori_size)); + ASSERT_EQ(array_data != NULL, true); + number::ObNumber elem_num; + for (uint64_t i = 0; i < ori_size; ++i) { + ASSERT_EQ(ObJsonBaseUtil::double_to_number(ordinate[i], *allocator, elem_num), OB_SUCCESS); + array_data[i].set_number(ObNumberType, elem_num); + } + + ObElemDesc elem_desc; + elem_array->set_capacity(ori_size); + elem_array->set_column_count(ori_size); + elem_array->set_count(ori_size); + elem_array->set_data(array_data); + elem_desc.set_pl_type(PL_VARRAY_TYPE); + elem_desc.set_not_null(false); + elem_desc.set_field_count(ori_size); + elem_array->set_element_desc(elem_desc); + elem_array->set_first(1); + elem_array->set_last(ori_size); + result.set_extend(reinterpret_cast(elem_array), elem_array->get_type()); +} + +TEST_F(TestGeoCommon, sql_udt_to_wkt) +{ + int ret = 0; + ObArenaAllocator allocator(ObModIds::TEST); + ObObj gtype; + build_obj_uint64(2001, allocator, gtype); + ObObj srid; + build_obj_uint64(4326, allocator, srid); + ObObj point_x; + build_obj_double(1.23, allocator, point_x); + ObObj point_y; + build_obj_double(4.56, allocator, point_y); + ObObj point_z; + build_obj_double(7.89, allocator, point_z); + + QualifiedMap map; + ASSERT_EQ(map.create(7, ObModIds::TEST), OB_SUCCESS); + ASSERT_EQ(map.set_refactored("SDO_GTYPE", >ype), OB_SUCCESS); + ASSERT_EQ(map.set_refactored("SDO_SRID", &srid), OB_SUCCESS); + ASSERT_EQ(map.set_refactored("SDO_POINT.X", &point_x), OB_SUCCESS); + ASSERT_EQ(map.set_refactored("SDO_POINT.Y", &point_y), OB_SUCCESS); + ASSERT_EQ(map.set_refactored("SDO_POINT.Z", &point_z), OB_SUCCESS); + + ObString ewkt; + ASSERT_EQ(ObGeoTypeUtil::sql_geo_obj_to_ewkt(map, allocator, ewkt), OB_SUCCESS); + ASSERT_EQ(ewkt == "SRID=4326;POINT(1.23 4.56)", true) << ewkt.ptr(); + + ObObj elem_info_pl; + ObObj elem_info_obj; + ObArray elem_info; + ASSERT_EQ(elem_info.push_back(1), OB_SUCCESS); + ASSERT_EQ(elem_info.push_back(1), OB_SUCCESS); + ASSERT_EQ(elem_info.push_back(1), OB_SUCCESS); + mock_write_sdo_elem_info(elem_info, allocator, elem_info_pl); + ObString elem_info_str; + ASSERT_EQ(ObSqlUdtUtils::cast_pl_varray_to_sql_varray(allocator, elem_info_str, elem_info_pl), OB_SUCCESS); + elem_info_obj.set_sql_collection(elem_info_str.ptr(), elem_info_str.length(), 30027); + + ObObj ordinate_pl; + ObObj ordinate_obj; + ObArray ordinates; + ASSERT_EQ(ordinates.push_back(9.87), OB_SUCCESS); + ASSERT_EQ(ordinates.push_back(6.54), OB_SUCCESS); + mock_write_sdo_ordinates(ordinates, allocator, ordinate_pl); + ObString ordinates_str; + ASSERT_EQ(ObSqlUdtUtils::cast_pl_varray_to_sql_varray(allocator, ordinates_str, ordinate_pl), OB_SUCCESS); + ordinate_obj.set_sql_collection(ordinates_str.ptr(), ordinates_str.length(), 30028); + + QualifiedMap map2; + ASSERT_EQ(map2.create(7, ObModIds::TEST), OB_SUCCESS); + ASSERT_EQ(map2.set_refactored("SDO_GTYPE", >ype), OB_SUCCESS); + ASSERT_EQ(map2.set_refactored("SDO_ELEM_INFO", &elem_info_obj), OB_SUCCESS); + ASSERT_EQ(map2.set_refactored("SDO_ORDINATES", &ordinate_obj), OB_SUCCESS); + + ObString ewkt2; + ASSERT_EQ(ObGeoTypeUtil::sql_geo_obj_to_ewkt(map2, allocator, ewkt2), OB_SUCCESS); + ASSERT_EQ(ewkt2 == "SRID=NULL;POINT(9.87 6.54)", true) << ewkt2.ptr(); +} + } // namespace common } // namespace oceanbase diff --git a/unittest/share/test_geo_func_box.cpp b/unittest/share/test_geo_func_box.cpp new file mode 100644 index 0000000000..1edbd957e7 --- /dev/null +++ b/unittest/share/test_geo_func_box.cpp @@ -0,0 +1,468 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#include +#include +#include +#include +#include +#define private public +#include "lib/geo/ob_geo_bin.h" +#include "lib/geo/ob_geo_tree.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" +#include "lib/geo/ob_geo_tree_traits.h" +#include "lib/geo/ob_geo_bin_traits.h" +#include "lib/geo/ob_geo_func_register.h" +#include "lib/geo/ob_geo_func_box.h" +#include "lib/geo/ob_geo_func_utils.h" +#include "lib/json_type/ob_json_common.h" +#include "lib/random/ob_random.h" +#undef private + +#include +#include +#include +#include + +namespace bg = boost::geometry; +using namespace oceanbase::common; + +namespace oceanbase +{ + +namespace common +{ + +class TestGeoFuncBox : public ::testing::Test +{ +public: + TestGeoFuncBox() + {} + ~TestGeoFuncBox() + {} + virtual void SetUp() + {} + virtual void TearDown() + {} + + static void SetUpTestCase() + {} + + static void TearDownTestCase() + {} + +private: + // disallow copy + DISALLOW_COPY_AND_ASSIGN(TestGeoFuncBox); +}; + +int append_bo(ObJsonBuffer &data, ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + uint8_t sbo = static_cast(bo); + return data.append(reinterpret_cast(&sbo), sizeof(uint8_t)); +} + +int append_type(ObJsonBuffer &data, ObGeoType type, ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + INIT_SUCC(ret); + uint32_t stype = static_cast(type); + if (OB_FAIL(data.reserve(sizeof(uint32_t)))) { + } else { + char *ptr = data.ptr() + data.length(); + ObGeoWkbByteOrderUtil::write(ptr, stype, bo); + ret = data.set_length(data.length() + sizeof(uint32_t)); + } + return ret; +} + +int append_uint32(ObJsonBuffer &data, uint32_t val, ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + INIT_SUCC(ret); + if (OB_FAIL(data.reserve(sizeof(uint32_t)))) { + } else { + char *ptr = data.ptr() + data.length(); + ObGeoWkbByteOrderUtil::write(ptr, val, bo); + ret = data.set_length(data.length() + sizeof(uint32_t)); + } + return ret; +} + +int append_double(ObJsonBuffer &data, double val, ObGeoWkbByteOrder bo = ObGeoWkbByteOrder::LittleEndian) +{ + INIT_SUCC(ret); + if (OB_FAIL(data.reserve(sizeof(double)))) { + } else { + char *ptr = data.ptr() + data.length(); + ObGeoWkbByteOrderUtil::write(ptr, val, bo); + ret = data.set_length(data.length() + sizeof(double)); + } + return ret; +} + +void create_point(ObJsonBuffer &data, double x, double y) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POINT)); + ASSERT_EQ(OB_SUCCESS, append_double(data, x)); + ASSERT_EQ(OB_SUCCESS, append_double(data, y)); +} + +void create_line(ObJsonBuffer &data, std::vector > &value) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, value.size())); + for (auto &p : value) { + ASSERT_EQ(OB_SUCCESS, append_double(data, p.first)); + ASSERT_EQ(OB_SUCCESS, append_double(data, p.second)); + } +} + +void create_polygon(ObJsonBuffer &data, int lnum, int pnum, std::vector > &value) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum)); + int i = 0; + for (int l = 0; l < lnum; l++) { + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum)); + for (int p = 0; p < pnum; p++) { + ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].first)); + ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].second)); + i++; + } + } +} + +void create_multipoint(ObJsonBuffer &data, std::vector > &value) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOINT)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, value.size())); + for (auto &p : value) { + create_point(data, p.first, p.second); + } +} + +void create_multiline(ObJsonBuffer &data, int lnum, int pnum, std::vector > &value) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTILINESTRING)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, lnum)); + int i = 0; + for (int l = 0; l < lnum; l++) { + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::LINESTRING)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum)); + for (int p = 0; p < pnum; p++) { + ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].first)); + ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].second)); + i++; + } + } +} + +// anum: polygon num; rnum: ring num per polygon; pnum: point num per ring +void create_multipolygon( + ObJsonBuffer &data, int anum, int rnum, int pnum, std::vector > &value) +{ + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::MULTIPOLYGON)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, anum)); + int i = 0; + for (int a = 0; a < anum; a++) { + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::POLYGON)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, rnum)); + for (int r = 0; r < rnum; r++) { + ASSERT_EQ(OB_SUCCESS, append_uint32(data, pnum)); + for (int p = 0; p < pnum; p++) { + ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].first)); + ASSERT_EQ(OB_SUCCESS, append_double(data, value[i].second)); + i++; + } + } + } +} + +template +bool is_geo_equal(GEO1 &geo1, GEO2 &geo2) +{ + std::stringstream left; + std::stringstream right; + left << bg::dsv(geo1); + right << bg::dsv(geo2); + if (left.str() == right.str()) { + return true; + } + std::cout << left.str() << std::endl; + std::cout << right.str() << std::endl; + return false; +} + +typedef bg::strategy::within::geographic_winding ObPlPaStrategy; +typedef bg::strategy::intersection::geographic_segments<> ObLlLaAaStrategy; + +typedef bg::model::d2::point_xy point_geom_t; +typedef bg::model::multi_point mpoint_geom_t; +typedef bg::model::linestring line_geom_t; +typedef bg::model::multi_linestring mline_geom_t; +typedef bg::model::polygon polygon_geom_t; +typedef bg::model::multi_polygon mpolygon_geom_t; + +typedef bg::model::d2::point_xy > point_geog_t; +typedef bg::model::multi_point mpoint_geog_t; +typedef bg::model::linestring line_geog_t; +typedef bg::model::multi_linestring mline_geog_t; +typedef bg::model::polygon polygon_geog_t; +typedef bg::model::multi_polygon mpolygon_geog_t; + +TEST_F(TestGeoFuncBox, geom_point) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + double x = 1.2; + double y = 3.5; + create_point(data, x, y); + ObIWkbGeomPoint p; + p.set_data(data.string()); + + ObGeoEvalCtx gis_context(&allocator); + gis_context.ut_set_geo_count(1); + gis_context.ut_set_geo_arg(0, &p); + ObGeogBox *result = NULL; + int ret = ObGeoFunc::geo_func::eval(gis_context, result); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_TRUE(result != NULL); + ASSERT_EQ(x, result->xmax); + ASSERT_EQ(x, result->xmin); + ASSERT_EQ(y, result->ymax); + ASSERT_EQ(y, result->ymin); +} + +TEST_F(TestGeoFuncBox, geom_linestring) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + std::vector > val; + val.push_back(std::make_pair(1.5, 1.2)); + val.push_back(std::make_pair(2.0, 4.0)); + create_line(data, val); + ObIWkbGeomLineString line; + line.set_data(data.string()); + + ObGeoEvalCtx gis_context(&allocator); + gis_context.ut_set_geo_count(1); + gis_context.ut_set_geo_arg(0, &line); + ObGeogBox *result = NULL; + int ret = ObGeoFunc::geo_func::eval(gis_context, result); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_TRUE(result != NULL); + ASSERT_EQ(2.0, result->xmax); + ASSERT_EQ(1.5, result->xmin); + ASSERT_EQ(4.0, result->ymax); + ASSERT_EQ(1.2, result->ymin); +} + +TEST_F(TestGeoFuncBox, geom_polygon) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + std::vector > pol_val; + pol_val.push_back(std::make_pair(1, 1)); + pol_val.push_back(std::make_pair(1, 3)); + pol_val.push_back(std::make_pair(3, 3)); + pol_val.push_back(std::make_pair(3, 1)); + pol_val.push_back(std::make_pair(1, 1)); + create_polygon(data, 1, 5, pol_val); + ObIWkbGeomPolygon poly; + poly.set_data(data.string()); + + ObGeoEvalCtx gis_context(&allocator); + gis_context.ut_set_geo_count(1); + gis_context.ut_set_geo_arg(0, &poly); + ObGeogBox *result = NULL; + int ret = ObGeoFunc::geo_func::eval(gis_context, result); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_TRUE(result != NULL); + ASSERT_EQ(1.0, result->xmin); + ASSERT_EQ(3.0, result->xmax); + ASSERT_EQ(1.0, result->ymin); + ASSERT_EQ(3.0, result->ymax); +} + +TEST_F(TestGeoFuncBox, geom_multipoint) +{ + ObArenaAllocator allocator(ObModIds::TEST); + + ObJsonBuffer data1(&allocator); + std::vector > val; + val.push_back(std::make_pair(1.0, 1.0)); + val.push_back(std::make_pair(1.0, 0.0)); + val.push_back(std::make_pair(1.0, 2.0)); + create_multipoint(data1, val); + ObIWkbGeomMultiPoint multi_point; + multi_point.set_data(data1.string()); + + ObGeoEvalCtx gis_context(&allocator); + gis_context.ut_set_geo_count(1); + gis_context.ut_set_geo_arg(0, &multi_point); + ObGeogBox *result = NULL; + int ret = ObGeoFunc::geo_func::eval(gis_context, result); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_TRUE(result != NULL); + ASSERT_EQ(1.0, result->xmin); + ASSERT_EQ(1.0, result->xmax); + ASSERT_EQ(0.0, result->ymin); + ASSERT_EQ(2.0, result->ymax); +} + +TEST_F(TestGeoFuncBox, geom_multilinestring) +{ + ObArenaAllocator allocator(ObModIds::TEST); + + ObJsonBuffer data1(&allocator); + std::vector > val; + val.push_back(std::make_pair(0.0, 0.0)); + val.push_back(std::make_pair(1.0, 1.0)); + val.push_back(std::make_pair(1.0, 1.0)); + val.push_back(std::make_pair(2.0, 2.0)); + val.push_back(std::make_pair(2.0, 2.0)); + val.push_back(std::make_pair(3.0, 3.0)); + create_multiline(data1, 3, 2, val); + ObIWkbGeomMultiLineString multi_line; + multi_line.set_data(data1.string()); + + ObGeoEvalCtx gis_context(&allocator); + gis_context.ut_set_geo_count(1); + gis_context.ut_set_geo_arg(0, &multi_line); + ObGeogBox *result = NULL; + int ret = ObGeoFunc::geo_func::eval(gis_context, result); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_TRUE(result != NULL); + ASSERT_EQ(0.0, result->xmin); + ASSERT_EQ(3.0, result->xmax); + ASSERT_EQ(0.0, result->ymin); + ASSERT_EQ(3.0, result->ymax); +} + +TEST_F(TestGeoFuncBox, geom_multipolygon) +{ + ObArenaAllocator allocator(ObModIds::TEST); + + ObJsonBuffer data1(&allocator); + std::vector > val; + val.push_back(std::make_pair(1.0, 1.0)); + val.push_back(std::make_pair(1.0, 3.0)); + val.push_back(std::make_pair(3.0, 3.0)); + val.push_back(std::make_pair(3.0, 1.0)); + val.push_back(std::make_pair(1.0, 1.0)); + val.push_back(std::make_pair(4.0, 4.0)); + val.push_back(std::make_pair(4.0, 6.0)); + val.push_back(std::make_pair(6.0, 6.0)); + val.push_back(std::make_pair(6.0, 4.0)); + val.push_back(std::make_pair(4.0, 4.0)); + create_multipolygon(data1, 2, 1, 5, val); + ObIWkbGeomMultiPolygon multi_poly; + multi_poly.set_data(data1.string()); + + ObGeoEvalCtx gis_context(&allocator); + gis_context.ut_set_geo_count(1); + gis_context.ut_set_geo_arg(0, &multi_poly); + ObGeogBox *result = NULL; + int ret = ObGeoFunc::geo_func::eval(gis_context, result); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_TRUE(result != NULL); + ASSERT_EQ(1.0, result->xmin); + ASSERT_EQ(6.0, result->xmax); + ASSERT_EQ(1.0, result->ymin); + ASSERT_EQ(6.0, result->ymax); +} + +TEST_F(TestGeoFuncBox, geom_collection) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObJsonBuffer data(&allocator); + ASSERT_EQ(OB_SUCCESS, append_bo(data)); + ASSERT_EQ(OB_SUCCESS, append_type(data, ObGeoType::GEOMETRYCOLLECTION)); + ASSERT_EQ(OB_SUCCESS, append_uint32(data, 6)); + + create_point(data, 1.2, 3.5); + + std::vector > line_val; + line_val.push_back(std::make_pair(1.5, 1.2)); + line_val.push_back(std::make_pair(2.0, 4.0)); + create_line(data, line_val); + + std::vector > pol_val; + pol_val.push_back(std::make_pair(1, 1)); + pol_val.push_back(std::make_pair(1, 3)); + pol_val.push_back(std::make_pair(3, 3)); + pol_val.push_back(std::make_pair(3, 1)); + pol_val.push_back(std::make_pair(1, 1)); + create_polygon(data, 1, 5, pol_val); + + std::vector > mpt_val; + mpt_val.push_back(std::make_pair(1.0, 1.0)); + mpt_val.push_back(std::make_pair(1.0, 0.0)); + mpt_val.push_back(std::make_pair(1.0, 2.0)); + create_multipoint(data, mpt_val); + + std::vector > mpl_val; + mpl_val.push_back(std::make_pair(0.0, 0.0)); + mpl_val.push_back(std::make_pair(1.0, 1.0)); + mpl_val.push_back(std::make_pair(1.0, 1.0)); + mpl_val.push_back(std::make_pair(2.0, 2.0)); + mpl_val.push_back(std::make_pair(2.0, 2.0)); + mpl_val.push_back(std::make_pair(3.0, 3.0)); + create_multiline(data, 3, 2, mpl_val); + + std::vector > mpy_val; + mpy_val.push_back(std::make_pair(1.0, 1.0)); + mpy_val.push_back(std::make_pair(1.0, 3.0)); + mpy_val.push_back(std::make_pair(3.0, 3.0)); + mpy_val.push_back(std::make_pair(3.0, 1.0)); + mpy_val.push_back(std::make_pair(1.0, 1.0)); + mpy_val.push_back(std::make_pair(4.0, 4.0)); + mpy_val.push_back(std::make_pair(4.0, 6.0)); + mpy_val.push_back(std::make_pair(6.0, 6.0)); + mpy_val.push_back(std::make_pair(6.0, 4.0)); + mpy_val.push_back(std::make_pair(4.0, 4.0)); + create_multipolygon(data, 2, 1, 5, mpy_val); + + ObIWkbGeomCollection collection; + collection.set_data(data.string()); + + ObGeoEvalCtx gis_context(&allocator); + gis_context.ut_set_geo_count(1); + gis_context.ut_set_geo_arg(0, &collection); + ObGeogBox *result = NULL; + int ret = ObGeoFunc::geo_func::eval(gis_context, result); + ASSERT_EQ(OB_SUCCESS, ret); + ASSERT_TRUE(result != NULL); + ASSERT_EQ(0.0, result->xmin); + ASSERT_EQ(6.0, result->xmax); + ASSERT_EQ(0.0, result->ymin); + ASSERT_EQ(6.0, result->ymax); +} + +} // namespace common +} // namespace oceanbase + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + // system("rm -f test_geo_func_box.log"); + // OB_LOGGER.set_file_name("test_geo_func_box.log"); + // OB_LOGGER.set_log_level("INFO"); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/unittest/share/test_geo_func_union.cpp b/unittest/share/test_geo_func_union.cpp index e1803fc921..e9bca08e0f 100644 --- a/unittest/share/test_geo_func_union.cpp +++ b/unittest/share/test_geo_func_union.cpp @@ -2164,7 +2164,6 @@ TEST_F(TestGeoFuncUnion, gc_split) ASSERT_EQ(true, is_geo_equal(*res_multi_line, *multi_line_tree)); ASSERT_EQ(true, is_geo_equal(*res_multi_poly, *multi_poly_tree)); } - } // namespace common } // namespace oceanbase diff --git a/unittest/share/test_geo_tree.cpp b/unittest/share/test_geo_tree.cpp index f8f3854075..b546505cb8 100644 --- a/unittest/share/test_geo_tree.cpp +++ b/unittest/share/test_geo_tree.cpp @@ -20,6 +20,13 @@ #include "lib/geo/ob_geo_bin_traits.h" #include "lib/json_type/ob_json_common.h" #include "lib/random/ob_random.h" +#include "lib/geo/ob_geo_utils.h" +#include "lib/geo/ob_geo_box_clip_visitor.h" +#include "lib/geo/ob_geo_to_tree_visitor.h" +#include "lib/geo/ob_geo_to_wkt_visitor.h" +#include "sql/engine/expr/ob_geo_expr_utils.h" +#include "lib/geo/ob_wkt_parser.h" +#include "lib/geo/ob_geo_common.h" #undef private #include @@ -624,7 +631,304 @@ TEST_F(TestGeoTree, intersection_op) } } +void wkt_to_tree_geo(const ObString &wkt, ObArenaAllocator &allocator, ObGeometry *&geo_tree) +{ + ObGeometry *geo = nullptr; + ASSERT_EQ(ObWktParser::parse_wkt(allocator, wkt, geo, true, false), OB_SUCCESS); + ObGeoToTreeVisitor tree_visitor(&allocator); + ASSERT_EQ(geo->do_visit(tree_visitor), OB_SUCCESS); + geo_tree = tree_visitor.get_geometry(); +} +void tree_geo_to_wkt(ObArenaAllocator &allocator, ObGeometry *geo_tree, ObString &wkt_cal) +{ + bool is_geo_empty = false; + ASSERT_EQ(sql::ObGeoExprUtils::check_empty(geo_tree, is_geo_empty), OB_SUCCESS); + if (is_geo_empty) { + wkt_cal = "EMPTY"; + } else { + ObGeometry *geo_bin = NULL; + ASSERT_EQ(ObGeoTypeUtil::tree_to_bin(allocator, geo_tree, geo_bin, nullptr), OB_SUCCESS); + ObGeoToWktVisitor visitor(&allocator); + ASSERT_EQ(geo_bin->do_visit(visitor), OB_SUCCESS); + visitor.get_wkt(wkt_cal); + } +} + +void clip_visitor_test(const ObString &wkt, const ObString &wkt_res, ObGeogBox &box) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo_tree = nullptr; + wkt_to_tree_geo(wkt, allocator, geo_tree); + + ObGeometry *geo_res = nullptr; + ObGeoBoxClipVisitor clip_visitor(box, allocator); + ASSERT_EQ(geo_tree->do_visit(clip_visitor), OB_SUCCESS); + ASSERT_EQ(clip_visitor.get_geometry(geo_res), OB_SUCCESS); + ASSERT_EQ(geo_res == nullptr, false); + + ObString wkt_cal; + tree_geo_to_wkt(allocator, geo_res, wkt_cal); + ASSERT_EQ(wkt_cal == wkt_res, true); +} + +TEST_F(TestGeoTree, clip_visitor) +{ + ObGeogBox box1 = {0, 10, 0, 10, 0, 0}; + // linestring + clip_visitor_test("LINESTRING(1 1,1 9,9 9,9 1)", "LINESTRING(1 1,1 9,9 9,9 1)", box1); + clip_visitor_test("LINESTRING(-1 -9,-1 11,9 11)", "EMPTY", box1); + clip_visitor_test("LINESTRING(-1 5,5 5,9 9)", "LINESTRING(0 5,5 5,9 9)", box1); + clip_visitor_test("LINESTRING(5 5,8 5,12 5)", "LINESTRING(5 5,8 5,10 5)", box1); + clip_visitor_test("LINESTRING(5 -1,5 5,1 2,-3 2,1 6)", "MULTILINESTRING((5 0,5 5,1 2,0 2),(0 5,1 6))", box1); + clip_visitor_test("LINESTRING(0 3,0 5,0 7)", "EMPTY", box1); + clip_visitor_test("LINESTRING(0 3,0 5,-1 7)", "EMPTY", box1); + clip_visitor_test("LINESTRING(0 3,0 5,2 7)", "LINESTRING(0 5,2 7)", box1); + clip_visitor_test("LINESTRING(2 1,0 0,1 2)", "LINESTRING(2 1,0 0,1 2)", box1); + clip_visitor_test("LINESTRING(3 3,0 3,0 5,2 7)", "MULTILINESTRING((3 3,0 3),(0 5,2 7))", box1); + clip_visitor_test("LINESTRING(5 5,10 5,20 5)", "LINESTRING(5 5,10 5)", box1); + clip_visitor_test("LINESTRING(3 3,0 6,3 9)", "LINESTRING(3 3,0 6,3 9)", box1); + clip_visitor_test("LINESTRING(-1 -1,3 1,3 3,-1 -1)", "LINESTRING(1 0,3 1,3 3,0 0)", box1); + + // polygon + clip_visitor_test("POLYGON((5 5,5 6,6 6,6 5,5 5))", "POLYGON((5 5,5 6,6 6,6 5,5 5))", box1); + clip_visitor_test("POLYGON((15 15,15 16,16 16,16 15,15 15))", "EMPTY", box1); + clip_visitor_test("POLYGON((-1 -1,-1 11,11 11,11 -1,-1 -1))", "POLYGON((0 0,0 10,10 10,10 0,0 0))", box1); + clip_visitor_test("POLYGON((-1 -1,-1 5,5 5,5 -1,-1 -1))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", box1); + clip_visitor_test("POLYGON((-2 -2,-2 5,5 5,5 -2,-2 -2), (3 3,4 4,4 2,3 3))", "POLYGON((0 0,0 5,5 5,5 0,0 0),(3 3,4 4,4 2,3 3))", box1); + clip_visitor_test("POLYGON((-2 -2,-2 5,5 5,5 -2,-2 -2), (-1 -1,3 1,3 3,-1 -1))", + "POLYGON((0 0,0 5,5 5,5 0,1 0,3 1,3 3,0 0))", box1); + clip_visitor_test("POLYGON((0 0,10 0,5 10,0 0))", "POLYGON((0 0,5 10,10 0,0 0))", box1); + clip_visitor_test("POLYGON((5 10,0 0,10 0,5 10))", "POLYGON((0 0,5 10,10 0,0 0))", box1); + clip_visitor_test("POLYGON((-5 -5,5 5,5 -5,-5 -5))", "POLYGON((0 0,5 5,5 0,0 0))", box1); + clip_visitor_test("POLYGON((0 0,0 10,10 10,0 0))", "POLYGON((0 0,0 10,10 10,0 0))", box1); + clip_visitor_test("POLYGON((0 5,0 10,10 10,0 5))", "POLYGON((0 5,0 10,10 10,0 5))", box1); + clip_visitor_test("POLYGON((0 10,10 10,5 0,0 10))", "POLYGON((0 10,10 10,5 0,0 10))", box1); + clip_visitor_test("POLYGON((0 10,10 10,5 5,0 10))", "POLYGON((0 10,10 10,5 5,0 10))", box1); + clip_visitor_test("POLYGON((0 10,5 10,0 5,0 10))", "POLYGON((0 5,0 10,5 10,0 5))", box1); + clip_visitor_test("POLYGON((0 10,10 5,0 5,0 10))", "POLYGON((0 5,0 10,10 5,0 5))", box1); + clip_visitor_test("POLYGON((0 10,10 0,0 5,0 10))", "POLYGON((0 5,0 10,10 0,0 5))", box1); + clip_visitor_test("POLYGON((0 10,5 0,0 5,0 10))", "POLYGON((0 5,0 10,5 0,0 5))", box1); + clip_visitor_test("POLYGON((0 10,5 5,0 5,0 10))", "POLYGON((0 5,0 10,5 5,0 5))", box1); + clip_visitor_test("POLYGON((0 10,7 7,3 3,0 10))", "POLYGON((0 10,7 7,3 3,0 10))", box1); + clip_visitor_test("POLYGON((0 10,5 5,5 0,0 10))", "POLYGON((0 10,5 5,5 0,0 10))", box1); + clip_visitor_test("POLYGON((0 10,10 5,5 0,0 10))", "POLYGON((0 10,10 5,5 0,0 10))", box1); + clip_visitor_test("POLYGON((2 5,5 10,7 5,2 5))", + "POLYGON((2 5,5 10,7 5,2 5))", box1); + clip_visitor_test("POLYGON((0 5,5 10,5 5,0 5))", + "POLYGON((0 5,5 10,5 5,0 5))", box1); + clip_visitor_test("POLYGON((0 5,5 10,10 5,0 5))", + "POLYGON((0 5,5 10,10 5,0 5))", box1); + clip_visitor_test("POLYGON((0 5,5 7,10 5,0 5))", + "POLYGON((0 5,5 7,10 5,0 5))", box1); + clip_visitor_test("POLYGON((-5 10,0 15,0 10,-5 10))", "EMPTY", box1); + clip_visitor_test("POLYGON((-5 10,0 5,-5 0,-5 10))", "EMPTY", box1); + clip_visitor_test("POLYGON((-5 5,0 10,0 0,-5 5))", "EMPTY", box1); + clip_visitor_test("POLYGON((-5 5,0 10,0 5,-5 5))", "EMPTY", box1); + clip_visitor_test("POLYGON((-5 5,0 7,0 3,-5 5))", "EMPTY", box1); + clip_visitor_test("POLYGON((5 5,-5 0,-5 10,5 5))", + "POLYGON((0 2.5,0 7.5,5 5,0 2.5))", box1); + clip_visitor_test("POLYGON((5 0,-5 0,-5 10,5 0))", + "POLYGON((0 0,0 5,5 0,0 0))", box1); + clip_visitor_test("POLYGON((10 0,-10 0,-10 10,10 0))", + "POLYGON((0 0,0 5,10 0,0 0))", box1); + clip_visitor_test("POLYGON((5 0,-5 5,-5 10,5 0))", + "POLYGON((0 2.5,0 5,5 0,0 2.5))", box1); + clip_visitor_test("POLYGON((10 5,-10 0,-10 10,10 5))", + "POLYGON((0 2.5,0 7.5,10 5,0 2.5))", box1); + clip_visitor_test("POLYGON((10 10,-10 0,-10 5,10 10))", + "POLYGON((0 5,0 7.5,10 10,0 5))", box1); + clip_visitor_test("POLYGON((5 5,-5 -5,-5 15,5 5))", + "POLYGON((0 0,0 10,5 5,0 0))", box1); + clip_visitor_test("POLYGON((10 5,-10 -5,-10 15,10 5))", + "POLYGON((0 0,0 10,10 5,0 0))", box1); + clip_visitor_test("POLYGON((5 0,-5 0,-5 20,5 0))", + "POLYGON((0 0,0 10,5 0,0 0))", box1); + clip_visitor_test("POLYGON((10 0,-10 0,-10 20,10 0))", + "POLYGON((0 0,0 10,10 0,0 0))", box1); + clip_visitor_test("POLYGON((5 5,-10 5,0 15,5 5))", + "POLYGON((0 5,0 10,2.5 10,5 5,0 5))", box1); + clip_visitor_test("POLYGON((5 5,-5 -5,0 15,5 5))", + "POLYGON((0 0,0 10,2.5 10,5 5,0 0))", box1); + clip_visitor_test("POLYGON((5 5,-15 -20,-15 30,5 5))", + "POLYGON((0 0,0 10,1 10,5 5,1 0,0 0))", box1); + clip_visitor_test("POLYGON((5 7,5 3,-5 5,5 7))", + "POLYGON((0 4,0 6,5 7,5 3,0 4))", box1); + clip_visitor_test("POLYGON((5 7,5 3,-5 13,5 7))", + "POLYGON((0 8,0 10,5 7,5 3,0 8))", box1); + clip_visitor_test("POLYGON((6 6,4 4,-4 14,6 6))", + "POLYGON((0 9,0 10,1.0000000000000007 10,6 6,4 4,0 9))", box1); + clip_visitor_test("POLYGON((-2 -2,-2 12,12 12,12 -2,-2 -2),(-1 -1,11 -1,11 11,-1 11,-1 -1))", + "EMPTY", box1); + clip_visitor_test("POLYGON((-2 -2,-2 12,12 12,12 -2,-2 -2),(1 1,9 1,9 9,1 9,1 1))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(1 1,9 1,9 9,1 9,1 1))", box1); + clip_visitor_test("POLYGON((5 5,15 5,15 -5,5 -5,5 5),(8 1,8 -1,9 -1,9 1,8 1))", + "POLYGON((5 0,5 5,10 5,10 0,9 0,9 1,8 1,8 0,5 0))", box1); + clip_visitor_test("POLYGON((-6 5,5 5,5 -6,-6 5))", + "POLYGON((0 0,0 5,5 5,5 0,0 0))", box1); + clip_visitor_test("POLYGON((-15 -15,-15 15,15 15,15 -15,-15 -15),(-5 5,-5 -5,5 -5,5 5,-5 5))", + "POLYGON((0 5,0 10,10 10,10 0,5 0,5 5,0 5))", box1); + clip_visitor_test("POLYGON((-15 -15,-15 15,15 15,15 -15,-15 -15),(-6 5,5 -6,5 5,-6 5))", + "POLYGON((0 5,0 10,10 10,10 0,5 0,5 5,0 5))", box1); + clip_visitor_test("POLYGON((-15 -15,-15 15,15 15,15 -15,-15 -15),(-5 5,-6 5,-6 6,-5 6,-5 5))", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", box1); + clip_visitor_test("POLYGON((-15 -15,-15 15,15 15,15 -15,-15 -15),(0 5,-1 5,-1 6,0 6,0 5))", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", box1); + ObGeogBox box2 = {10, 100, 10, 100, 0, 0}; + clip_visitor_test("POLYGON((50 50,200 50,200 200,50 200,50 50))", // CCW + "POLYGON((50 50,50 100,100 100,100 50,50 50))", box2); + clip_visitor_test("POLYGON((50 50,50 200,200 200,200 50,50 50))", // CW + "POLYGON((50 50,50 100,100 100,100 50,50 50))", box2); + // box1 + clip_visitor_test("POLYGON(" + "(-10 2,-10 8,8 8,8 2,-10 2)," // CW + "(-5 6,-5 4,5 4,5 6,-5 6)" // CCW + ")", + "POLYGON((0 2,0 4,5 4,5 6,0 6,0 8,8 8,8 2,0 2))", box1); + clip_visitor_test("POLYGON(" + "(-10 2,-10 8,8 8,8 2,-10 2)," // CW + "(-5 6,5 6,5 4,-5 4,-5 6)" // CW + ")", + "POLYGON((0 2,0 4,5 4,5 6,0 6,0 8,8 8,8 2,0 2))", box1); + clip_visitor_test("POLYGON(" + "(-10 2,8 2,8 8,-10 8,-10 2)," // CCW + "(-5 6,5 6,5 4,-5 4,-5 6)" // CW + ")", + "POLYGON((0 2,0 4,5 4,5 6,0 6,0 8,8 8,8 2,0 2))", box1); + clip_visitor_test("POLYGON(" + "(-10 -10,-10 20,20 20,20 -10,-10 -10)," // CW + "(-5 -5,0 -5,0 0,-5 0,-5 -5)" // CCW + ")", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", box1); + ObGeogBox box3 = {3.0481343214686657e-14, 20000000.000000, -20000000.000000, -1.000000, 0, 0}; + clip_visitor_test("POLYGON((3.0481343214686657e-14 -20000000, 200000000 -20000000, 200000000 -1, 3.0481343214686657e-14 -1, 3.0481343214686657e-14 -20000000))", + "POLYGON((0.000000000000030481343214686657 -20000000,0.000000000000030481343214686657 -1,20000000 -1,20000000 -20000000,0.000000000000030481343214686657 -20000000))", box3); + // EMPTY + clip_visitor_test("GEOMETRYCOLLECTION EMPTY", "EMPTY", box1); +} + +void affine_visitor_test(const ObString &wkt, const ObString &wkt_res, ObAffineMatrix &affine) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo_tree = nullptr; + wkt_to_tree_geo(wkt, allocator, geo_tree); + ASSERT_EQ(ObGeoMVTUtil::affine_transformation(geo_tree, affine), OB_SUCCESS); + + ObString wkt_cal; + tree_geo_to_wkt(allocator, geo_tree, wkt_cal); + ASSERT_EQ(wkt_cal == wkt_res, true); +} + +TEST_F(TestGeoTree, affine_visitor) +{ + ObAffineMatrix affine = {1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 4096, 0}; + affine_visitor_test("MULTILINESTRING((1 1, 501 501, 1001 1001),(2 2, 502 502, 1002 1002))", + "MULTILINESTRING((1 4095,501 3595,1001 3095),(2 4094,502 3594,1002 3094))", affine); + affine_visitor_test("POLYGON ((0 0, 10 0, 10 5, 0 -5, 0 0))", + "POLYGON((0 4096,10 4096,10 4091,0 4101,0 4096))", affine); + ObAffineMatrix affine2 = {1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 100, 0}; + affine_visitor_test("LINESTRING(0 0, 2 20, -2 40, -4 60, 4 80, 0 100)", + "LINESTRING(0 100,2 80,-2 60,-4 40,4 20,0 0)", affine2); + ObAffineMatrix affine3 = {1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 10, 0}; + affine_visitor_test("POLYGON((10 10, 10 0, 0 0, 0 10, 10 10),(9 9, 1 9, 1 1, 9 1, 9 9),(8 8, 8 2, 2 2, 2 8, 8 8),(7 7, 7 3, 3 3, 3 7, 7 7))", + "POLYGON((10 0,10 10,0 10,0 0,10 0),(9 1,1 1,1 9,9 9,9 1),(8 2,8 8,2 8,2 2,8 2),(7 3,7 7,3 7,3 3,7 3))", affine3); + // POLYGON((-8231396.69199339 4979982.17443372,-8231396.69199339 4980355.83678553,-8231365.02893734 4980355.83678553,-8231365.02893734 4979982.17443372,-8231396.69199339 4979982.17443372)) + ObAffineMatrix affine4 = {0.41539995335806329, 0, 0, 0, -0.41539995335802404, 0, 0, 0, 1, 3422112.7441855143, 2068718.1395343679, 0}; + affine_visitor_test("MULTIPOLYGON(((-8231365.02893734 4980355.83678553,-8231394.82332406 4980186.31880185,-8231367.43081065 4979982.17443372,-8231396.69199339 4980227.59327083,-8231365.02893734 4980355.83678553)))", + "MULTIPOLYGON(((2804.095091749914 -121.44277270394377,2791.718504895922 -51.02501018997282,2803.097353688907 33.77655080938712,2790.942259743344 -68.17042267904617,2804.095091749914 -121.44277270394377)))", affine4); +} + +void grid_visitor_test(const ObString &wkt, const ObString &wkt_res, double size) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo_tree = nullptr; + wkt_to_tree_geo(wkt, allocator, geo_tree); + + ObGeoGrid grid = {0, 0, 0, 0, 0, 0}; + grid.x_size = grid.y_size = size; + ASSERT_EQ(ObGeoMVTUtil::snap_to_grid(geo_tree, grid, false), OB_SUCCESS); + + ObString wkt_cal; + tree_geo_to_wkt(allocator, geo_tree, wkt_cal); + ASSERT_EQ(wkt_cal == wkt_res, true); +} + +TEST_F(TestGeoTree, grid_visitor) +{ + grid_visitor_test("LINESTRING(0 100,2 80,-2 60,-4 40,4 20,0 0)", + "LINESTRING(0 100,2 80,-2 60,-4 40,4 20,0 0)", 1); + grid_visitor_test("LINESTRING(0 0,1 1,2 2,3 3,4 4,5 5)", "LINESTRING(0 0,2 2,4 4)", 2); + grid_visitor_test("POINT(5.1423999999 5.1423999999)", "POINT(5.1424 5.1424)", 0.0001); + grid_visitor_test("POINT(5 5)", "POINT(0 0)", 20); + grid_visitor_test("MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)))", "EMPTY", 20); + // different from PG, PG keeps duplicate point in multipoint + grid_visitor_test("MULTIPOINT(0 0,1 1, 2 2, 3 3, 4 4, 5 5)", "MULTIPOINT((0 0),(2 2),(4 4))", 2); + grid_visitor_test("MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(4 4, 4 5, 5 5, 5 4, 4 4)))", + "MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)))", 2); + grid_visitor_test("MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(4 4, 4 5, 5 5, 5 4, 4 4)))", + "EMPTY", 20); + grid_visitor_test("MULTIPOLYGON(((2804.095091749914 -121.44277270394377,2791.718504895922 -51.02501018997282,2803.097353688907 33.77655080938712,2790.942259743344 -68.17042267904617,2804.095091749914 -121.44277270394377)))", + "MULTIPOLYGON(((2804 -121,2792 -51,2803 34,2791 -68,2804 -121)))", 1); +} + +void simplify_visitor_test(const ObString &wkt, const ObString &wkt_res, double tolerance, bool keep_collapsed) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo_tree = nullptr; + wkt_to_tree_geo(wkt, allocator, geo_tree); + + ASSERT_EQ(ObGeoMVTUtil::simplify_geometry(geo_tree, tolerance, keep_collapsed), OB_SUCCESS); + + ObString wkt_cal; + tree_geo_to_wkt(allocator, geo_tree, wkt_cal); + ASSERT_EQ(wkt_cal == wkt_res, true); +} + +TEST_F(TestGeoTree, simplify_visitor) +{ + simplify_visitor_test("POLYGON((10 0,10 10,0 10,0 0,10 0),(9 1,1 1,1 9,9 9,9 1),(8 2,8 8,2 8,2 2,8 2),(7 3,7 7,3 7,3 3,7 3))", + "POLYGON((10 0,10 10,0 10,0 0,10 0),(9 1,1 1,1 9,9 9,9 1),(8 2,8 8,2 8,2 2,8 2),(7 3,7 7,3 7,3 3,7 3))", 0, false); + simplify_visitor_test("MULTILINESTRING((1 4095,501 3595,1001 3095),(2 4094,502 3594,1002 3094))", + "MULTILINESTRING((1 4095,1001 3095),(2 4094,1002 3094))", 0, false); + simplify_visitor_test("LINESTRING(0 0, 1 0, 1 1, 0 1, 0 0)", "LINESTRING(0 0,0 0)", 10, true); + simplify_visitor_test("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))", "POLYGON((0 0,1 0,1 1,0 0))", 10, true); + simplify_visitor_test("LINESTRING(0 0, 1 0, 1 1, 0 1, 0 0)", "EMPTY", 10, false); + simplify_visitor_test("POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))", "EMPTY", 10, false); + simplify_visitor_test("LINESTRING(0 0, 50 1.00001, 100 0)", "LINESTRING(0 0,50 1.00001,100 0)", 1, false); + simplify_visitor_test("LINESTRING(0 0,50 0.99999,100 0)", "LINESTRING(0 0,100 0)", 1, false); + simplify_visitor_test("POLYGON(" + "(0 0, 100 0, 100 100, 0 100, 0 0)," + "(1 1, 1 5, 5 5, 5 1, 1 1)," + "(20 20, 20 40, 40 40, 40 20, 20 20)" + ")", "POLYGON((0 0,100 0,100 100,0 100,0 0),(20 20,20 40,40 40,40 20,20 20))", 10, false); + simplify_visitor_test("POLYGON(" + "(0 0, 100 0, 100 100, 0 100, 0 0)," + "(20 20, 20 40, 40 40, 40 20, 20 20)," + "(1 1, 1 5, 5 5, 5 1, 1 1)" + ")", "POLYGON((0 0,100 0,100 100,0 100,0 0),(20 20,20 40,40 40,40 20,20 20))", 10, false); + simplify_visitor_test("POLYGON(" + "(0 0, 100 0, 100 100, 0 100, 0 0)," + "(20 20, 20 40, 40 40, 40 20, 20 20)," + "(1 1, 1 5, 5 5, 5 1, 1 1)" + ")", "EMPTY", 100, false); +} + +TEST_F(TestGeoTree, ewkt_with_null) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo_tree = nullptr; + wkt_to_tree_geo("POINT(1 1)", allocator, geo_tree); + geo_tree->set_srid(UINT32_MAX); + ObGeometry *geo_bin = NULL; + ASSERT_EQ(ObGeoTypeUtil::tree_to_bin(allocator, geo_tree, geo_bin, nullptr), OB_SUCCESS); + ObWkbBuffer buffer(allocator); + ASSERT_EQ(buffer.append(static_cast(UINT32_MAX)), OB_SUCCESS); + ASSERT_EQ(buffer.append(geo_bin->val(), geo_bin->length()), OB_SUCCESS); + ObString wkt_cal; + ASSERT_EQ(ObGeoTypeUtil::geo_to_ewkt(buffer.string(), wkt_cal, allocator, 14), OB_SUCCESS); + ObString wkt_res = "SRID=NULL;POINT(1 1)"; + ASSERT_EQ(wkt_cal == wkt_res, true); +} } // namespace common } // namespace oceanbase @@ -632,5 +936,8 @@ TEST_F(TestGeoTree, intersection_op) int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); + // system("rm -f test_geo_tree.log"); + // OB_LOGGER.set_file_name("test_geo_tree.log"); + OB_LOGGER.set_log_level("DEBUG"); return RUN_ALL_TESTS(); } diff --git a/unittest/share/test_wkt_parser.cpp b/unittest/share/test_wkt_parser.cpp index 6fdc2f0c80..a6a0d4fc7d 100644 --- a/unittest/share/test_wkt_parser.cpp +++ b/unittest/share/test_wkt_parser.cpp @@ -56,12 +56,35 @@ public: return wkb; } + void compare_wkt_parse_result(ObGeoType geotype, const ObString &wkt, const ObString &wkb_res); + void comapre_wkt_parse_wrong_result(const ObString &wkt); + private: ObArenaAllocator allocator_; // disallow copy DISALLOW_COPY_AND_ASSIGN(TestWktParser); }; +void TestWktParser::compare_wkt_parse_result(ObGeoType geotype, const ObString &wkt, const ObString &wkb_res) +{ + ObArenaAllocator allocator(ObModIds::TEST); + ObGeometry *geo = NULL; + ASSERT_EQ(OB_SUCCESS, ObWktParser::parse_wkt(allocator, wkt, geo, true, false)); + ASSERT_TRUE(NULL != geo); + ASSERT_EQ(geo->type(), geotype); + ObString wkb = to_hex(mock_to_wkb(geo)); + // std::cout<