diff options
author | marsaly <marsaly@yandex-team.com> | 2023-01-18 12:28:36 +0300 |
---|---|---|
committer | marsaly <marsaly@yandex-team.com> | 2023-01-18 12:28:36 +0300 |
commit | f23d6eff014dc53e1bc818d359d9afd11ba919c0 (patch) | |
tree | 26523db46897762055878f8f129efbfc5c3214b9 | |
parent | b1b9ed7fe8ec050a481ad42bed290404595b8089 (diff) | |
download | ydb-f23d6eff014dc53e1bc818d359d9afd11ba919c0.tar.gz |
Поддержка сравнения массивов ПГ
23 files changed, 1461 insertions, 106 deletions
diff --git a/contrib/libs/postgresql/src/include/catalog/pg_opfamily.dat b/contrib/libs/postgresql/src/include/catalog/pg_opfamily.dat new file mode 100644 index 0000000000..8e480efd28 --- /dev/null +++ b/contrib/libs/postgresql/src/include/catalog/pg_opfamily.dat @@ -0,0 +1,308 @@ +#---------------------------------------------------------------------- +# +# pg_opfamily.dat +# Initial contents of the pg_opfamily system catalog. +# +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_opfamily.dat +# +#---------------------------------------------------------------------- + +[ + +{ oid => '397', + opfmethod => 'btree', opfname => 'array_ops' }, +{ oid => '627', + opfmethod => 'hash', opfname => 'array_ops' }, +{ oid => '423', + opfmethod => 'btree', opfname => 'bit_ops' }, +{ oid => '424', oid_symbol => 'BOOL_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'bool_ops' }, +{ oid => '426', oid_symbol => 'BPCHAR_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'bpchar_ops' }, +{ oid => '427', + opfmethod => 'hash', opfname => 'bpchar_ops' }, +{ oid => '428', oid_symbol => 'BYTEA_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'bytea_ops' }, +{ oid => '429', + opfmethod => 'btree', opfname => 'char_ops' }, +{ oid => '431', + opfmethod => 'hash', opfname => 'char_ops' }, +{ oid => '434', + opfmethod => 'btree', opfname => 'datetime_ops' }, +{ oid => '435', + opfmethod => 'hash', opfname => 'date_ops' }, +{ oid => '1970', + opfmethod => 'btree', opfname => 'float_ops' }, +{ oid => '1971', + opfmethod => 'hash', opfname => 'float_ops' }, +{ oid => '1974', oid_symbol => 'NETWORK_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'network_ops' }, +{ oid => '1975', + opfmethod => 'hash', opfname => 'network_ops' }, +{ oid => '3550', + opfmethod => 'gist', opfname => 'network_ops' }, +{ oid => '3794', + opfmethod => 'spgist', opfname => 'network_ops' }, +{ oid => '1976', oid_symbol => 'INTEGER_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'integer_ops' }, +{ oid => '1977', + opfmethod => 'hash', opfname => 'integer_ops' }, +{ oid => '1982', + opfmethod => 'btree', opfname => 'interval_ops' }, +{ oid => '1983', + opfmethod => 'hash', opfname => 'interval_ops' }, +{ oid => '1984', + opfmethod => 'btree', opfname => 'macaddr_ops' }, +{ oid => '1985', + opfmethod => 'hash', opfname => 'macaddr_ops' }, +{ oid => '3371', + opfmethod => 'btree', opfname => 'macaddr8_ops' }, +{ oid => '3372', + opfmethod => 'hash', opfname => 'macaddr8_ops' }, +{ oid => '1988', + opfmethod => 'btree', opfname => 'numeric_ops' }, +{ oid => '1998', + opfmethod => 'hash', opfname => 'numeric_ops' }, +{ oid => '1989', oid_symbol => 'OID_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'oid_ops' }, +{ oid => '1990', + opfmethod => 'hash', opfname => 'oid_ops' }, +{ oid => '1991', + opfmethod => 'btree', opfname => 'oidvector_ops' }, +{ oid => '1992', + opfmethod => 'hash', opfname => 'oidvector_ops' }, +{ oid => '2994', + opfmethod => 'btree', opfname => 'record_ops' }, +{ oid => '6194', + opfmethod => 'hash', opfname => 'record_ops' }, +{ oid => '3194', + opfmethod => 'btree', opfname => 'record_image_ops' }, +{ oid => '1994', oid_symbol => 'TEXT_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'text_ops' }, +{ oid => '1995', + opfmethod => 'hash', opfname => 'text_ops' }, +{ oid => '1996', + opfmethod => 'btree', opfname => 'time_ops' }, +{ oid => '1997', + opfmethod => 'hash', opfname => 'time_ops' }, +{ oid => '1999', + opfmethod => 'hash', opfname => 'timestamptz_ops' }, +{ oid => '2000', + opfmethod => 'btree', opfname => 'timetz_ops' }, +{ oid => '2001', + opfmethod => 'hash', opfname => 'timetz_ops' }, +{ oid => '2002', + opfmethod => 'btree', opfname => 'varbit_ops' }, +{ oid => '2040', + opfmethod => 'hash', opfname => 'timestamp_ops' }, +{ oid => '2095', oid_symbol => 'TEXT_PATTERN_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'text_pattern_ops' }, +{ oid => '2097', oid_symbol => 'BPCHAR_PATTERN_BTREE_FAM_OID', + opfmethod => 'btree', opfname => 'bpchar_pattern_ops' }, +{ oid => '2099', + opfmethod => 'btree', opfname => 'money_ops' }, +{ oid => '2222', oid_symbol => 'BOOL_HASH_FAM_OID', + opfmethod => 'hash', opfname => 'bool_ops' }, +{ oid => '2223', + opfmethod => 'hash', opfname => 'bytea_ops' }, +{ oid => '2789', + opfmethod => 'btree', opfname => 'tid_ops' }, +{ oid => '2225', + opfmethod => 'hash', opfname => 'xid_ops' }, +{ oid => '5032', + opfmethod => 'hash', opfname => 'xid8_ops' }, +{ oid => '5067', + opfmethod => 'btree', opfname => 'xid8_ops' }, +{ oid => '2226', + opfmethod => 'hash', opfname => 'cid_ops' }, +{ oid => '2227', + opfmethod => 'hash', opfname => 'tid_ops' }, +{ oid => '2229', + opfmethod => 'hash', opfname => 'text_pattern_ops' }, +{ oid => '2231', + opfmethod => 'hash', opfname => 'bpchar_pattern_ops' }, +{ oid => '2235', + opfmethod => 'hash', opfname => 'aclitem_ops' }, +{ oid => '2593', + opfmethod => 'gist', opfname => 'box_ops' }, +{ oid => '2594', + opfmethod => 'gist', opfname => 'poly_ops' }, +{ oid => '2595', + opfmethod => 'gist', opfname => 'circle_ops' }, +{ oid => '1029', + opfmethod => 'gist', opfname => 'point_ops' }, +{ oid => '2745', + opfmethod => 'gin', opfname => 'array_ops' }, +{ oid => '2968', + opfmethod => 'btree', opfname => 'uuid_ops' }, +{ oid => '2969', + opfmethod => 'hash', opfname => 'uuid_ops' }, +{ oid => '3253', + opfmethod => 'btree', opfname => 'pg_lsn_ops' }, +{ oid => '3254', + opfmethod => 'hash', opfname => 'pg_lsn_ops' }, +{ oid => '3522', + opfmethod => 'btree', opfname => 'enum_ops' }, +{ oid => '3523', + opfmethod => 'hash', opfname => 'enum_ops' }, +{ oid => '3626', + opfmethod => 'btree', opfname => 'tsvector_ops' }, +{ oid => '3655', + opfmethod => 'gist', opfname => 'tsvector_ops' }, +{ oid => '3659', + opfmethod => 'gin', opfname => 'tsvector_ops' }, +{ oid => '3683', + opfmethod => 'btree', opfname => 'tsquery_ops' }, +{ oid => '3702', + opfmethod => 'gist', opfname => 'tsquery_ops' }, +{ oid => '3901', + opfmethod => 'btree', opfname => 'range_ops' }, +{ oid => '3903', + opfmethod => 'hash', opfname => 'range_ops' }, +{ oid => '3919', + opfmethod => 'gist', opfname => 'range_ops' }, +{ oid => '3474', + opfmethod => 'spgist', opfname => 'range_ops' }, +{ oid => '4015', + opfmethod => 'spgist', opfname => 'quad_point_ops' }, +{ oid => '4016', + opfmethod => 'spgist', opfname => 'kd_point_ops' }, +{ oid => '4017', oid_symbol => 'TEXT_SPGIST_FAM_OID', + opfmethod => 'spgist', opfname => 'text_ops' }, +{ oid => '4033', + opfmethod => 'btree', opfname => 'jsonb_ops' }, +{ oid => '4034', + opfmethod => 'hash', opfname => 'jsonb_ops' }, +{ oid => '4036', + opfmethod => 'gin', opfname => 'jsonb_ops' }, +{ oid => '4037', + opfmethod => 'gin', opfname => 'jsonb_path_ops' }, +{ oid => '4054', + opfmethod => 'brin', opfname => 'integer_minmax_ops' }, +{ oid => '4602', + opfmethod => 'brin', opfname => 'integer_minmax_multi_ops' }, +{ oid => '4572', + opfmethod => 'brin', opfname => 'integer_bloom_ops' }, +{ oid => '4055', + opfmethod => 'brin', opfname => 'numeric_minmax_ops' }, +{ oid => '4603', + opfmethod => 'brin', opfname => 'numeric_minmax_multi_ops' }, +{ oid => '4056', + opfmethod => 'brin', opfname => 'text_minmax_ops' }, +{ oid => '4573', + opfmethod => 'brin', opfname => 'text_bloom_ops' }, +{ oid => '4574', + opfmethod => 'brin', opfname => 'numeric_bloom_ops' }, +{ oid => '4058', + opfmethod => 'brin', opfname => 'timetz_minmax_ops' }, +{ oid => '4604', + opfmethod => 'brin', opfname => 'timetz_minmax_multi_ops' }, +{ oid => '4575', + opfmethod => 'brin', opfname => 'timetz_bloom_ops' }, +{ oid => '4059', + opfmethod => 'brin', opfname => 'datetime_minmax_ops' }, +{ oid => '4605', + opfmethod => 'brin', opfname => 'datetime_minmax_multi_ops' }, +{ oid => '4576', + opfmethod => 'brin', opfname => 'datetime_bloom_ops' }, +{ oid => '4062', + opfmethod => 'brin', opfname => 'char_minmax_ops' }, +{ oid => '4577', + opfmethod => 'brin', opfname => 'char_bloom_ops' }, +{ oid => '4064', + opfmethod => 'brin', opfname => 'bytea_minmax_ops' }, +{ oid => '4578', + opfmethod => 'brin', opfname => 'bytea_bloom_ops' }, +{ oid => '4065', + opfmethod => 'brin', opfname => 'name_minmax_ops' }, +{ oid => '4579', + opfmethod => 'brin', opfname => 'name_bloom_ops' }, +{ oid => '4068', + opfmethod => 'brin', opfname => 'oid_minmax_ops' }, +{ oid => '4606', + opfmethod => 'brin', opfname => 'oid_minmax_multi_ops' }, +{ oid => '4580', + opfmethod => 'brin', opfname => 'oid_bloom_ops' }, +{ oid => '4069', + opfmethod => 'brin', opfname => 'tid_minmax_ops' }, +{ oid => '4581', + opfmethod => 'brin', opfname => 'tid_bloom_ops' }, +{ oid => '4607', + opfmethod => 'brin', opfname => 'tid_minmax_multi_ops' }, +{ oid => '4070', + opfmethod => 'brin', opfname => 'float_minmax_ops' }, +{ oid => '4608', + opfmethod => 'brin', opfname => 'float_minmax_multi_ops' }, +{ oid => '4582', + opfmethod => 'brin', opfname => 'float_bloom_ops' }, +{ oid => '4074', + opfmethod => 'brin', opfname => 'macaddr_minmax_ops' }, +{ oid => '4609', + opfmethod => 'brin', opfname => 'macaddr_minmax_multi_ops' }, +{ oid => '4583', + opfmethod => 'brin', opfname => 'macaddr_bloom_ops' }, +{ oid => '4109', + opfmethod => 'brin', opfname => 'macaddr8_minmax_ops' }, +{ oid => '4610', + opfmethod => 'brin', opfname => 'macaddr8_minmax_multi_ops' }, +{ oid => '4584', + opfmethod => 'brin', opfname => 'macaddr8_bloom_ops' }, +{ oid => '4075', + opfmethod => 'brin', opfname => 'network_minmax_ops' }, +{ oid => '4611', + opfmethod => 'brin', opfname => 'network_minmax_multi_ops' }, +{ oid => '4102', + opfmethod => 'brin', opfname => 'network_inclusion_ops' }, +{ oid => '4585', + opfmethod => 'brin', opfname => 'network_bloom_ops' }, +{ oid => '4076', + opfmethod => 'brin', opfname => 'bpchar_minmax_ops' }, +{ oid => '4586', + opfmethod => 'brin', opfname => 'bpchar_bloom_ops' }, +{ oid => '4077', + opfmethod => 'brin', opfname => 'time_minmax_ops' }, +{ oid => '4612', + opfmethod => 'brin', opfname => 'time_minmax_multi_ops' }, +{ oid => '4587', + opfmethod => 'brin', opfname => 'time_bloom_ops' }, +{ oid => '4078', + opfmethod => 'brin', opfname => 'interval_minmax_ops' }, +{ oid => '4613', + opfmethod => 'brin', opfname => 'interval_minmax_multi_ops' }, +{ oid => '4588', + opfmethod => 'brin', opfname => 'interval_bloom_ops' }, +{ oid => '4079', + opfmethod => 'brin', opfname => 'bit_minmax_ops' }, +{ oid => '4080', + opfmethod => 'brin', opfname => 'varbit_minmax_ops' }, +{ oid => '4081', + opfmethod => 'brin', opfname => 'uuid_minmax_ops' }, +{ oid => '4614', + opfmethod => 'brin', opfname => 'uuid_minmax_multi_ops' }, +{ oid => '4589', + opfmethod => 'brin', opfname => 'uuid_bloom_ops' }, +{ oid => '4103', + opfmethod => 'brin', opfname => 'range_inclusion_ops' }, +{ oid => '4082', + opfmethod => 'brin', opfname => 'pg_lsn_minmax_ops' }, +{ oid => '4615', + opfmethod => 'brin', opfname => 'pg_lsn_minmax_multi_ops' }, +{ oid => '4590', + opfmethod => 'brin', opfname => 'pg_lsn_bloom_ops' }, +{ oid => '4104', + opfmethod => 'brin', opfname => 'box_inclusion_ops' }, +{ oid => '5000', + opfmethod => 'spgist', opfname => 'box_ops' }, +{ oid => '5008', + opfmethod => 'spgist', opfname => 'poly_ops' }, +{ oid => '4199', + opfmethod => 'btree', opfname => 'multirange_ops' }, +{ oid => '4225', + opfmethod => 'hash', opfname => 'multirange_ops' }, +{ oid => '6158', + opfmethod => 'gist', opfname => 'multirange_ops' }, + +] diff --git a/ydb/library/yql/parser/pg_catalog/CMakeLists.darwin.txt b/ydb/library/yql/parser/pg_catalog/CMakeLists.darwin.txt index 6b0dc697e2..46e12b4a6e 100644 --- a/ydb/library/yql/parser/pg_catalog/CMakeLists.darwin.txt +++ b/ydb/library/yql/parser/pg_catalog/CMakeLists.darwin.txt @@ -30,6 +30,7 @@ target_sources(yql-parser-pg_catalog.global PRIVATE ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/1ecd65c896f36a3990d870644a6da9c8.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/46b25697572e7e60703079b71cd18295.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/15e039bc35a86f84476091e328dd74ea.cpp + ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/cfe805d97f50bda16fa4bad21fa16589.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/ca7bb755fe32f897eb03cf6004d1ad2a.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/f2374a475345069a2bfd38b387dfa11a.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/462597d51509ecdc14b417ce082dc53b.cpp @@ -70,6 +71,13 @@ resources(yql-parser-pg_catalog.global pg_aggregate.dat ) resources(yql-parser-pg_catalog.global + ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/cfe805d97f50bda16fa4bad21fa16589.cpp + INPUTS + ${CMAKE_SOURCE_DIR}/contrib/libs/postgresql/src/include/catalog/pg_opfamily.dat + KEYS + pg_opfamily.dat +) +resources(yql-parser-pg_catalog.global ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/ca7bb755fe32f897eb03cf6004d1ad2a.cpp INPUTS ${CMAKE_SOURCE_DIR}/contrib/libs/postgresql/src/include/catalog/pg_opclass.dat diff --git a/ydb/library/yql/parser/pg_catalog/CMakeLists.linux-aarch64.txt b/ydb/library/yql/parser/pg_catalog/CMakeLists.linux-aarch64.txt index 21f796f0b4..56ead14794 100644 --- a/ydb/library/yql/parser/pg_catalog/CMakeLists.linux-aarch64.txt +++ b/ydb/library/yql/parser/pg_catalog/CMakeLists.linux-aarch64.txt @@ -32,6 +32,7 @@ target_sources(yql-parser-pg_catalog.global PRIVATE ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/1ecd65c896f36a3990d870644a6da9c8.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/46b25697572e7e60703079b71cd18295.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/15e039bc35a86f84476091e328dd74ea.cpp + ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/cfe805d97f50bda16fa4bad21fa16589.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/ca7bb755fe32f897eb03cf6004d1ad2a.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/f2374a475345069a2bfd38b387dfa11a.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/462597d51509ecdc14b417ce082dc53b.cpp @@ -72,6 +73,13 @@ resources(yql-parser-pg_catalog.global pg_aggregate.dat ) resources(yql-parser-pg_catalog.global + ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/cfe805d97f50bda16fa4bad21fa16589.cpp + INPUTS + ${CMAKE_SOURCE_DIR}/contrib/libs/postgresql/src/include/catalog/pg_opfamily.dat + KEYS + pg_opfamily.dat +) +resources(yql-parser-pg_catalog.global ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/ca7bb755fe32f897eb03cf6004d1ad2a.cpp INPUTS ${CMAKE_SOURCE_DIR}/contrib/libs/postgresql/src/include/catalog/pg_opclass.dat diff --git a/ydb/library/yql/parser/pg_catalog/CMakeLists.linux.txt b/ydb/library/yql/parser/pg_catalog/CMakeLists.linux.txt index 21f796f0b4..56ead14794 100644 --- a/ydb/library/yql/parser/pg_catalog/CMakeLists.linux.txt +++ b/ydb/library/yql/parser/pg_catalog/CMakeLists.linux.txt @@ -32,6 +32,7 @@ target_sources(yql-parser-pg_catalog.global PRIVATE ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/1ecd65c896f36a3990d870644a6da9c8.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/46b25697572e7e60703079b71cd18295.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/15e039bc35a86f84476091e328dd74ea.cpp + ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/cfe805d97f50bda16fa4bad21fa16589.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/ca7bb755fe32f897eb03cf6004d1ad2a.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/f2374a475345069a2bfd38b387dfa11a.cpp ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/462597d51509ecdc14b417ce082dc53b.cpp @@ -72,6 +73,13 @@ resources(yql-parser-pg_catalog.global pg_aggregate.dat ) resources(yql-parser-pg_catalog.global + ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/cfe805d97f50bda16fa4bad21fa16589.cpp + INPUTS + ${CMAKE_SOURCE_DIR}/contrib/libs/postgresql/src/include/catalog/pg_opfamily.dat + KEYS + pg_opfamily.dat +) +resources(yql-parser-pg_catalog.global ${CMAKE_BINARY_DIR}/ydb/library/yql/parser/pg_catalog/ca7bb755fe32f897eb03cf6004d1ad2a.cpp INPUTS ${CMAKE_SOURCE_DIR}/contrib/libs/postgresql/src/include/catalog/pg_opclass.dat diff --git a/ydb/library/yql/parser/pg_catalog/catalog.cpp b/ydb/library/yql/parser/pg_catalog/catalog.cpp index 1b992efa5c..50e6cdb031 100644 --- a/ydb/library/yql/parser/pg_catalog/catalog.cpp +++ b/ydb/library/yql/parser/pg_catalog/catalog.cpp @@ -8,8 +8,14 @@ namespace NYql::NPg { +constexpr ui32 InvalidOid = 0; constexpr ui32 AnyOid = 2276; constexpr ui32 AnyArrayOid = 2277; +//constexpr ui32 AnyElementOid = 2283; +//constexpr ui32 AnyNonArrayOid = 2776; +//constexpr ui32 AnyCompatibleOid = 5077; +//constexpr ui32 AnyCompatibleArrayOid = 5078; +//constexpr ui32 AnyCompatibleNonArrayOid = 5079; using TOperators = THashMap<ui32, TOperDesc>; @@ -21,11 +27,15 @@ using TCasts = THashMap<ui32, TCastDesc>; using TAggregations = THashMap<ui32, TAggregateDesc>; +// We parse OpFamilies' IDs for now. If we ever needed oid_symbol, +// create TOpFamilyDesc class alike other catalogs +using TOpFamilies = THashMap<TString, ui32>; + using TOpClasses = THashMap<std::pair<EOpClassMethod, ui32>, TOpClassDesc>; -using TAmOps = THashMap<std::tuple<TString, ui32, ui32, ui32>, TAmOpDesc>; +using TAmOps = THashMap<std::tuple<ui32, ui32, ui32, ui32>, TAmOpDesc>; -using TAmProcs = THashMap<std::tuple<TString, ui32, ui32, ui32>, TAmProcDesc>; +using TAmProcs = THashMap<std::tuple<ui32, ui32, ui32, ui32>, TAmProcDesc>; bool IsCompatibleTo(ui32 actualType, ui32 expectedType, const TTypes& types) { if (!actualType) { @@ -333,6 +343,7 @@ struct TLazyTypeInfo { TString ReceiveFunc; TString ModInFunc; TString ModOutFunc; + TString SubscriptFunc; }; class TTypesParser : public TParser { @@ -370,6 +381,26 @@ public: } else if (key == "typdelim") { Y_ENSURE(value.size() == 1); LastType.TypeDelim = value[0]; + } else if (key == "typtype") { + Y_ENSURE(value.size() == 1); + const auto typType = value[0]; + + LastType.TypType = + (typType == 'b') ? ETypType::Base : + (typType == 'c') ? ETypType::Composite : + (typType == 'd') ? ETypType::Domain : + (typType == 'e') ? ETypType::Enum : + (typType == 'm') ? ETypType::Multirange : + (typType == 'p') ? ETypType::Pseudo : + (typType == 'r') ? ETypType::Range : + ythrow yexception() << "Unknown typtype value: " << value; + } else if (key == "typcollation") { + // hardcode collations for now. There are only three of 'em in .dat file + LastType.TypeCollation = + (value == "default") ? DefaultCollationOid : + (value == "C") ? C_CollationOid : + (value == "POSIX") ? PosixCollationOid : + ythrow yexception() << "Unknown typcollation value: " << value; } else if (key == "typelem") { LastLazyTypeInfo.ElementType = value; // resolve later } else if (key == "typinput") { @@ -384,6 +415,8 @@ public: LastLazyTypeInfo.ModInFunc = value; // resolve later } else if (key == "typmodout") { LastLazyTypeInfo.ModOutFunc = value; // resolve later + } else if (key == "typsubscript") { + LastLazyTypeInfo.SubscriptFunc = value; // resolve later } else if (key == "typbyval") { if (value == "f") { LastType.PassByValue = false; @@ -498,6 +531,15 @@ public: } else { ythrow yexception() << "Unknown castmethod value: " << value; } + } else if (key == "castcontext") { + Y_ENSURE(value.size() == 1); + const auto castCtx = value[0]; + + LastCast.CoercionCode = + (castCtx == 'i') ? ECoercionCode::Implicit : + (castCtx == 'a') ? ECoercionCode::Assignment : + (castCtx == 'e') ? ECoercionCode::Explicit : + ythrow yexception() << "Unknown castcontext value: " << value; } } @@ -711,11 +753,59 @@ private: TString LastDeserializeFunc; }; +class TOpFamiliesParser : public TParser { +public: + TOpFamiliesParser(TOpFamilies& opFamilies) + : OpFamilies(opFamilies) + {} + + void OnKey(const TString& key, const TString& value) override { + if (key == "oid") { + LastOpfId = FromString<ui32>(value); + } else if (key == "opfmethod") { + if (value == "btree" || value == "hash") { + LastOpfMethod = value; + } else { + IsSupported = false; + } + } else if (key == "opfname") { + LastOpfName = value; + } + } + + void OnFinish() override { + if (IsSupported) { + Y_ENSURE(LastOpfId != InvalidOid); + + // TODO: log or throw if dict keys aren't unique + // opfamily references have opf_method/opf_name format in PG catalogs + OpFamilies[LastOpfMethod.append('/').append( + LastOpfName)] = LastOpfId; // LastOpfMethod is modified here. Use with caution till its reinit + } + + IsSupported = true; + LastOpfId = InvalidOid; + LastOpfMethod.clear(); + LastOpfName.clear(); + } + +private: + TOpFamilies& OpFamilies; + + ui32 LastOpfId = InvalidOid; + + TString LastOpfMethod; + TString LastOpfName; + bool IsSupported = true; +}; + class TOpClassesParser : public TParser { public: - TOpClassesParser(TOpClasses& opClasses, const THashMap<TString, ui32>& typeByName) - : OpClasses(opClasses) - , TypeByName(typeByName) + TOpClassesParser(TOpClasses& opClasses, const THashMap<TString, ui32>& typeByName, + const TOpFamilies &opFamilies) + : OpClasses(opClasses) + , TypeByName(typeByName) + , OpFamilies(opFamilies) {} void OnKey(const TString& key, const TString& value) override { @@ -735,40 +825,70 @@ public: LastOpClass.Name = value; } else if (key == "opcfamily") { LastOpClass.Family = value; + auto opFamilyPtr = OpFamilies.FindPtr(value); + + if (opFamilyPtr) { + LastOpClass.FamilyId = *opFamilyPtr; + } else { + IsSupported = false; + } + } else if (key == "opcdefault") { + IsDefault = (value[0] != 'f'); } } - void OnFinish() override { - if (IsSupported) { - Y_ENSURE(!LastOpClass.Name.empty()); - OpClasses[std::make_pair(LastOpClass.Method, LastOpClass.TypeId)] = LastOpClass; - } +void OnFinish() override { + // Only default opclasses are used so far + if (IsSupported && IsDefault) { + Y_ENSURE(!LastOpClass.Name.empty()); - IsSupported = true; - LastOpClass = TOpClassDesc(); + const auto key = std::make_pair(LastOpClass.Method, LastOpClass.TypeId); + + if (OpClasses.contains(key)) { + throw yexception() << "Duplicate opclass: (" << (key.first == EOpClassMethod::Btree ? "btree" : "hash") + << ", " << key.second << ")"; + } + OpClasses[key] = LastOpClass; } + IsSupported = true; + IsDefault = true; + LastOpClass = TOpClassDesc(); +} + private: TOpClasses& OpClasses; + const THashMap<TString, ui32>& TypeByName; + const TOpFamilies OpFamilies; + TOpClassDesc LastOpClass; bool IsSupported = true; + bool IsDefault = true; }; class TAmOpsParser : public TParser { public: TAmOpsParser(TAmOps& amOps, const THashMap<TString, ui32>& typeByName, const TTypes& types, - const THashMap<TString, TVector<ui32>>& operatorsByName, const TOperators& operators) + const THashMap<TString, TVector<ui32>>& operatorsByName, const TOperators& operators, + const TOpFamilies &opFamilies) : AmOps(amOps) , TypeByName(typeByName) , Types(types) , OperatorsByName(operatorsByName) , Operators(operators) + , OpFamilies(opFamilies) {} void OnKey(const TString& key, const TString& value) override { if (key == "amopfamily") { LastAmOp.Family = value; + auto opFamilyPtr = OpFamilies.FindPtr(value); + if (opFamilyPtr) { + LastAmOp.FamilyId = *opFamilyPtr; + } else { + IsSupported = false; + } } else if (key == "amoplefttype") { auto leftTypePtr = TypeByName.FindPtr(value); Y_ENSURE(leftTypePtr); @@ -787,49 +907,65 @@ public: } void OnFinish() override { - auto operIdPtr = OperatorsByName.FindPtr(LastOp); - Y_ENSURE(operIdPtr); - for (const auto& id : *operIdPtr) { - const auto& d = Operators.FindPtr(id); - Y_ENSURE(d); - if (d->Kind == EOperKind::Binary && - IsCompatibleTo(LastAmOp.LeftType, d->LeftType, Types) && - IsCompatibleTo(LastAmOp.RightType, d->RightType, Types)) { - Y_ENSURE(!LastAmOp.OperId); - LastAmOp.OperId = d->OperId; + if (IsSupported) { + auto operIdPtr = OperatorsByName.FindPtr(LastOp); + Y_ENSURE(operIdPtr); + for (const auto& id : *operIdPtr) { + const auto& d = Operators.FindPtr(id); + Y_ENSURE(d); + if (d->Kind == EOperKind::Binary && + IsCompatibleTo(LastAmOp.LeftType, d->LeftType, Types) && + IsCompatibleTo(LastAmOp.RightType, d->RightType, Types)) { + Y_ENSURE(!LastAmOp.OperId); + LastAmOp.OperId = d->OperId; + } } - } - Y_ENSURE(LastAmOp.OperId); - AmOps[std::make_tuple(LastAmOp.Family, LastAmOp.Strategy, LastAmOp.LeftType, LastAmOp.RightType)] = LastAmOp; + Y_ENSURE(LastAmOp.OperId); + AmOps[std::make_tuple(LastAmOp.FamilyId, LastAmOp.Strategy, LastAmOp.LeftType, LastAmOp.RightType)] = LastAmOp; + } LastAmOp = TAmOpDesc(); LastOp = ""; + IsSupported = true; } private: TAmOps& AmOps; + const THashMap<TString, ui32>& TypeByName; const TTypes& Types; const THashMap<TString, TVector<ui32>>& OperatorsByName; const TOperators& Operators; + const TOpFamilies& OpFamilies; + TAmOpDesc LastAmOp; TString LastOp; + bool IsSupported = true; }; class TAmProcsParser : public TParser { public: TAmProcsParser(TAmProcs& amProcs, const THashMap<TString, ui32>& typeByName, - const THashMap<TString, TVector<ui32>>& procByName, const TProcs& procs) + const THashMap<TString, TVector<ui32>>& procByName, const TProcs& procs, + const TOpFamilies& opFamilies) : AmProcs(amProcs) , TypeByName(typeByName) , ProcByName(procByName) , Procs(procs) + , OpFamilies(opFamilies) {} void OnKey(const TString& key, const TString& value) override { if (key == "amprocfamily") { LastAmProc.Family = value; + auto opFamilyPtr = OpFamilies.FindPtr(value); + + if (opFamilyPtr) { + LastAmProc.FamilyId = *opFamilyPtr; + } else { + IsSupported = false; + } } else if (key == "amproclefttype") { auto leftTypePtr = TypeByName.FindPtr(value); Y_ENSURE(leftTypePtr); @@ -846,31 +982,38 @@ public: } void OnFinish() override { - if (LastName.find('(') == TString::npos) { - auto procIdPtr = ProcByName.FindPtr(LastName); - Y_ENSURE(procIdPtr); - for (const auto& id : *procIdPtr) { - const auto& d = Procs.FindPtr(id); - Y_ENSURE(d); - Y_ENSURE(!LastAmProc.ProcId); - LastAmProc.ProcId = d->ProcId; - } + if (IsSupported) { + if (LastName.find('(') == TString::npos) { + auto procIdPtr = ProcByName.FindPtr(LastName); + Y_ENSURE(procIdPtr); + for (const auto& id : *procIdPtr) { + const auto& d = Procs.FindPtr(id); + Y_ENSURE(d); + Y_ENSURE(!LastAmProc.ProcId); + LastAmProc.ProcId = d->ProcId; + } - Y_ENSURE(LastAmProc.ProcId); - AmProcs[std::make_tuple(LastAmProc.Family, LastAmProc.ProcNum, LastAmProc.LeftType, LastAmProc.RightType)] = LastAmProc; + Y_ENSURE(LastAmProc.ProcId); + AmProcs[std::make_tuple(LastAmProc.FamilyId, LastAmProc.ProcNum, LastAmProc.LeftType, LastAmProc.RightType)] = LastAmProc; + } } LastAmProc = TAmProcDesc(); LastName = ""; + IsSupported = true; } private: TAmProcs& AmProcs; + const THashMap<TString, ui32>& TypeByName; const THashMap<TString, TVector<ui32>>& ProcByName; const TProcs& Procs; + const TOpFamilies& OpFamilies; + TAmProcDesc LastAmProc; TString LastName; + bool IsSupported = true; }; TOperators ParseOperators(const TString& dat, const THashMap<TString, ui32>& typeByName, @@ -911,25 +1054,35 @@ TCasts ParseCasts(const TString& dat, const THashMap<TString, ui32>& typeByName, return ret; } -TOpClasses ParseOpClasses(const TString& dat, const THashMap<TString, ui32>& typeByName) { +TOpFamilies ParseOpFamilies(const TString& dat) { + TOpFamilies ret; + TOpFamiliesParser parser(ret); + parser.Do(dat); + return ret; +} + +TOpClasses ParseOpClasses(const TString& dat, const THashMap<TString, ui32>& typeByName, + const TOpFamilies& opFamilies) { TOpClasses ret; - TOpClassesParser parser(ret, typeByName); + TOpClassesParser parser(ret, typeByName, opFamilies); parser.Do(dat); return ret; } TAmOps ParseAmOps(const TString& dat, const THashMap<TString, ui32>& typeByName, const TTypes& types, - const THashMap<TString, TVector<ui32>>& operatorsByName, const TOperators& operators) { + const THashMap<TString, TVector<ui32>>& operatorsByName, const TOperators& operators, + const TOpFamilies& opFamilies) { TAmOps ret; - TAmOpsParser parser(ret, typeByName, types, operatorsByName, operators); + TAmOpsParser parser(ret, typeByName, types, operatorsByName, operators, opFamilies); parser.Do(dat); return ret; } TAmProcs ParseAmProcs(const TString& dat, const THashMap<TString, ui32>& typeByName, - const THashMap<TString, TVector<ui32>>& procByName, const TProcs& procs) { + const THashMap<TString, TVector<ui32>>& procByName, const TProcs& procs, + const TOpFamilies& opFamilies) { TAmProcs ret; - TAmProcsParser parser(ret, typeByName, procByName, procs); + TAmProcsParser parser(ret, typeByName, procByName, procs, opFamilies); parser.Do(dat); return ret; } @@ -946,6 +1099,8 @@ struct TCatalog { Y_ENSURE(NResource::FindExact("pg_cast.dat", &castData)); TString aggData; Y_ENSURE(NResource::FindExact("pg_aggregate.dat", &aggData)); + TString opFamiliesData; + Y_ENSURE(NResource::FindExact("pg_opfamily.dat", &opFamiliesData)); TString opClassData; Y_ENSURE(NResource::FindExact("pg_opclass.dat", &opClassData)); TString amProcData; @@ -964,28 +1119,16 @@ struct TCatalog { } } - for (const auto& [k, v]: lazyTypeInfos) { - if (!v.ElementType) { - continue; - } - - auto elemTypePtr = TypeByName.FindPtr(v.ElementType); - Y_ENSURE(elemTypePtr); - auto typePtr = Types.FindPtr(k); - Y_ENSURE(typePtr); - typePtr->ElementTypeId = *elemTypePtr; - } - Procs = ParseProcs(procData, TypeByName); - for (const auto& [k, v]: Procs) { + for (const auto& [k, v] : Procs) { ProcByName[v.Name].push_back(k); } const ui32 cstringId = 2275; const ui32 byteaId = 17; const ui32 internalId = 2281; - for (const auto&[k, v] : lazyTypeInfos) { + for (const auto& [k, v] : lazyTypeInfos) { auto typePtr = Types.FindPtr(k); Y_ENSURE(typePtr); @@ -1048,6 +1191,23 @@ struct TCatalog { Y_ENSURE(modOutFuncPtr->ArgTypes.size() == 1); typePtr->TypeModOutFuncId = modOutFuncIdPtr->at(0); } + + if (v.SubscriptFunc) { + auto subscriptFuncIdPtr = ProcByName.FindPtr(v.SubscriptFunc); + Y_ENSURE(subscriptFuncIdPtr); + Y_ENSURE(subscriptFuncIdPtr->size() == 1); + auto subscriptFuncPtr = Procs.FindPtr(subscriptFuncIdPtr->at(0)); + Y_ENSURE(subscriptFuncPtr); + Y_ENSURE(subscriptFuncPtr->ArgTypes.size() == 1); + typePtr->TypeSubscriptFuncId = subscriptFuncIdPtr->at(0); + } + + if (v.ElementType) { + auto elemTypePtr = TypeByName.FindPtr(v.ElementType); + Y_ENSURE(elemTypePtr); + + typePtr->ElementTypeId = *elemTypePtr; + } } Casts = ParseCasts(castData, TypeByName, Types, ProcByName, Procs); @@ -1065,16 +1225,17 @@ struct TCatalog { AggregationsByName[v.Name].push_back(k); } - OpClasses = ParseOpClasses(opClassData, TypeByName); - AmOps = ParseAmOps(amOpData, TypeByName, Types, OperatorsByName, Operators); - AmProcs = ParseAmProcs(amProcData, TypeByName, ProcByName, Procs); - for (auto&[k, v] : Types) { + TOpFamilies opFamilies = ParseOpFamilies(opFamiliesData); + OpClasses = ParseOpClasses(opClassData, TypeByName, opFamilies); + AmOps = ParseAmOps(amOpData, TypeByName, Types, OperatorsByName, Operators, opFamilies); + AmProcs = ParseAmProcs(amProcData, TypeByName, ProcByName, Procs, opFamilies); + for (auto& [k, v] : Types) { if (v.TypeId != v.ArrayTypeId) { auto btreeOpClassPtr = OpClasses.FindPtr(std::make_pair(EOpClassMethod::Btree, v.TypeId)); if (btreeOpClassPtr) { - auto lessAmOpPtr = AmOps.FindPtr(std::make_tuple(btreeOpClassPtr->Family, ui32(EBtreeAmStrategy::Less), v.TypeId, v.TypeId)); + auto lessAmOpPtr = AmOps.FindPtr(std::make_tuple(btreeOpClassPtr->FamilyId, ui32(EBtreeAmStrategy::Less), v.TypeId, v.TypeId)); Y_ENSURE(lessAmOpPtr); - auto equalAmOpPtr = AmOps.FindPtr(std::make_tuple(btreeOpClassPtr->Family, ui32(EBtreeAmStrategy::Equal), v.TypeId, v.TypeId)); + auto equalAmOpPtr = AmOps.FindPtr(std::make_tuple(btreeOpClassPtr->FamilyId, ui32(EBtreeAmStrategy::Equal), v.TypeId, v.TypeId)); Y_ENSURE(equalAmOpPtr); auto lessOperPtr = Operators.FindPtr(lessAmOpPtr->OperId); Y_ENSURE(lessOperPtr); @@ -1083,14 +1244,14 @@ struct TCatalog { v.LessProcId = lessOperPtr->ProcId; v.EqualProcId = equalOperPtr->ProcId; - auto compareAmProcPtr = AmProcs.FindPtr(std::make_tuple(btreeOpClassPtr->Family, ui32(EBtreeAmProcNum::Compare), v.TypeId, v.TypeId)); + auto compareAmProcPtr = AmProcs.FindPtr(std::make_tuple(btreeOpClassPtr->FamilyId, ui32(EBtreeAmProcNum::Compare), v.TypeId, v.TypeId)); Y_ENSURE(compareAmProcPtr); v.CompareProcId = compareAmProcPtr->ProcId; } auto hashOpClassPtr = OpClasses.FindPtr(std::make_pair(EOpClassMethod::Hash, v.TypeId)); if (hashOpClassPtr) { - auto hashAmProcPtr = AmProcs.FindPtr(std::make_tuple(hashOpClassPtr->Family, ui32(EHashAmProcNum::Hash), v.TypeId, v.TypeId)); + auto hashAmProcPtr = AmProcs.FindPtr(std::make_tuple(hashOpClassPtr->FamilyId, ui32(EHashAmProcNum::Hash), v.TypeId, v.TypeId)); Y_ENSURE(hashAmProcPtr); v.HashProcId = hashAmProcPtr->ProcId; } @@ -1206,19 +1367,19 @@ bool HasType(const TStringBuf& name) { const TTypeDesc& LookupType(const TString& name) { const auto& catalog = TCatalog::Instance(); - auto typeIdPtr = catalog.TypeByName.FindPtr(name); + const auto typeIdPtr = catalog.TypeByName.FindPtr(name); if (!typeIdPtr) { throw yexception() << "No such type: " << name; } - auto typePtr = catalog.Types.FindPtr(*typeIdPtr); + const auto typePtr = catalog.Types.FindPtr(*typeIdPtr); Y_ENSURE(typePtr); return *typePtr; } const TTypeDesc& LookupType(ui32 typeId) { const auto& catalog = TCatalog::Instance(); - auto typePtr = catalog.Types.FindPtr(typeId); + const auto typePtr = catalog.Types.FindPtr(typeId); if (!typePtr) { throw yexception() << "No such type: " << typeId; } @@ -1331,19 +1492,25 @@ bool HasOpClass(EOpClassMethod method, ui32 typeId) { return catalog.OpClasses.contains(std::make_pair(method, typeId)); } -const TOpClassDesc& LookupOpClass(EOpClassMethod method, ui32 typeId) { +const TOpClassDesc* LookupDefaultOpClass(EOpClassMethod method, ui32 typeId) { const auto& catalog = TCatalog::Instance(); - auto opClassPtr = catalog.OpClasses.FindPtr(std::make_pair(method, typeId)); - if (!opClassPtr) { - throw yexception() << "No such opclass"; - } + const auto opClassPtr = catalog.OpClasses.FindPtr(std::make_pair(method, typeId)); + if (opClassPtr) + return opClassPtr; - return *opClassPtr; + throw yexception() << "No such opclass"; + + // TODO: support binary coercible and preferred types as define in PG's GetDefaultOpClass() +} + +bool HasAmOp(ui32 familyId, ui32 strategy, ui32 leftType, ui32 rightType) { + const auto &catalog = TCatalog::Instance(); + return catalog.AmOps.contains(std::make_tuple(familyId, strategy, leftType, rightType)); } -const TAmOpDesc& LookupAmOp(const TString& family, ui32 strategy, ui32 leftType, ui32 rightType) { +const TAmOpDesc& LookupAmOp(ui32 familyId, ui32 strategy, ui32 leftType, ui32 rightType) { const auto& catalog = TCatalog::Instance(); - auto amOpPtr = catalog.AmOps.FindPtr(std::make_tuple(family, strategy, leftType, rightType)); + const auto amOpPtr = catalog.AmOps.FindPtr(std::make_tuple(familyId, strategy, leftType, rightType)); if (!amOpPtr) { throw yexception() << "No such amop"; } @@ -1351,9 +1518,14 @@ const TAmOpDesc& LookupAmOp(const TString& family, ui32 strategy, ui32 leftType, return *amOpPtr; } -const TAmProcDesc& LookupAmProc(const TString& family, ui32 num, ui32 leftType, ui32 rightType) { +bool HasAmProc(ui32 familyId, ui32 num, ui32 leftType, ui32 rightType) { + const auto &catalog = TCatalog::Instance(); + return catalog.AmProcs.contains(std::make_tuple(familyId, num, leftType, rightType)); +} + +const TAmProcDesc& LookupAmProc(ui32 familyId, ui32 num, ui32 leftType, ui32 rightType) { const auto& catalog = TCatalog::Instance(); - auto amProcPtr = catalog.AmProcs.FindPtr(std::make_tuple(family, num, leftType, rightType)); + auto amProcPtr = catalog.AmProcs.FindPtr(std::make_tuple(familyId, num, leftType, rightType)); if (!amProcPtr) { throw yexception() << "No such amproc"; } diff --git a/ydb/library/yql/parser/pg_catalog/catalog.h b/ydb/library/yql/parser/pg_catalog/catalog.h index ad62ce037f..12cc8812f0 100644 --- a/ydb/library/yql/parser/pg_catalog/catalog.h +++ b/ydb/library/yql/parser/pg_catalog/catalog.h @@ -2,6 +2,7 @@ #include <util/generic/maybe.h> #include <util/generic/string.h> #include <util/generic/vector.h> +#include <util/stream/output.h> namespace NYql::NPg { @@ -38,6 +39,23 @@ struct TProcDesc { bool ReturnSet = false; }; +// Copied from pg_collation_d.h +constexpr ui32 InvalidCollationOid = 0; +constexpr ui32 DefaultCollationOid = 100; +constexpr ui32 C_CollationOid = 950; +constexpr ui32 PosixCollationOid = 951; + +// Copied from pg_type_d.h, TYPTYPE_* constants +enum class ETypType : char { + Base = 'b', + Composite = 'c', + Domain = 'd', + Enum = 'e', + Multirange = 'm', + Pseudo = 'p', + Range = 'r', +}; + struct TTypeDesc { ui32 TypeId = 0; ui32 ArrayTypeId = 0; @@ -47,18 +65,30 @@ struct TTypeDesc { char Category = '\0'; char TypeAlign = '\0'; char TypeDelim = ','; + + /* + * Collation: InvalidCollationOid if type cannot use collations, nonzero (typically + * DefaultCollationOid) for collatable base types, possibly some other + * OID for domains over collatable types + */ + ui32 TypeCollation = InvalidCollationOid; + ui32 InFuncId = 0; ui32 OutFuncId = 0; ui32 SendFuncId = 0; ui32 ReceiveFuncId = 0; ui32 TypeModInFuncId = 0; ui32 TypeModOutFuncId = 0; + ui32 TypeSubscriptFuncId = 0; i32 TypeLen = 0; // from opclass ui32 LessProcId = 0; ui32 EqualProcId = 0; ui32 CompareProcId = 0; ui32 HashProcId = 0; + + // If TypType is 'c', typrelid is the OID of the class' entry in pg_class. + ETypType TypType = ETypType::Base; }; enum class ECastMethod { @@ -67,11 +97,19 @@ enum class ECastMethod { Binary }; +enum class ECoercionCode : char { + Unknown = '?', // not specified + Implicit = 'i', // coercion in context of expression + Assignment = 'a', // coercion in context of assignment + Explicit = 'e', // explicit cast operation +}; + struct TCastDesc { ui32 SourceId = 0; ui32 TargetId = 0; ECastMethod Method = ECastMethod::Function; ui32 FunctionId = 0; + ECoercionCode CoercionCode = ECoercionCode::Unknown; }; enum class EAggKind { @@ -103,10 +141,12 @@ struct TOpClassDesc { ui32 TypeId = 0; TString Name; TString Family; + ui32 FamilyId = 0; }; struct TAmOpDesc { TString Family; + ui32 FamilyId = 0; ui32 Strategy = 0; ui32 LeftType = 0; ui32 RightType = 0; @@ -123,6 +163,7 @@ enum class EBtreeAmStrategy { struct TAmProcDesc { TString Family; + ui32 FamilyId = 0; ui32 ProcNum = 0; ui32 LeftType = 0; ui32 RightType = 0; @@ -158,11 +199,28 @@ bool HasAggregation(const TStringBuf& name); const TAggregateDesc& LookupAggregation(const TStringBuf& name, const TVector<ui32>& argTypeIds); bool HasOpClass(EOpClassMethod method, ui32 typeId); -const TOpClassDesc& LookupOpClass(EOpClassMethod method, ui32 typeId); +const TOpClassDesc* LookupDefaultOpClass(EOpClassMethod method, ui32 typeId); -const TAmOpDesc& LookupAmOp(const TString& family, ui32 strategy, ui32 leftType, ui32 rightType); -const TAmProcDesc& LookupAmProc(const TString& family, ui32 num, ui32 leftType, ui32 rightType); +bool HasAmOp(ui32 familyId, ui32 strategy, ui32 leftType, ui32 rightType); +const TAmOpDesc& LookupAmOp(ui32 familyId, ui32 strategy, ui32 leftType, ui32 rightType); + +bool HasAmProc(ui32 familyId, ui32 num, ui32 leftType, ui32 rightType); +const TAmProcDesc& LookupAmProc(ui32 familyId, ui32 num, ui32 leftType, ui32 rightType); bool IsCompatibleTo(ui32 actualType, ui32 expectedType); +inline bool IsArrayType(const TTypeDesc& typeDesc) noexcept { + return typeDesc.ArrayTypeId == typeDesc.TypeId; +} + +} + +template <> +inline void Out<NYql::NPg::ETypType>(IOutputStream& o, NYql::NPg::ETypType typType) { + o.Write(static_cast<std::underlying_type<NYql::NPg::ETypType>::type>(typType)); +} + +template <> +inline void Out<NYql::NPg::ECoercionCode>(IOutputStream& o, NYql::NPg::ECoercionCode coercionCode) { + o.Write(static_cast<std::underlying_type<NYql::NPg::ECoercionCode>::type>(coercionCode)); } diff --git a/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.darwin.txt b/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.darwin.txt index 4d95f99586..9caa9852f3 100644 --- a/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.darwin.txt +++ b/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.darwin.txt @@ -10,6 +10,7 @@ add_executable(ydb-library-yql-parser-pg_catalog-ut) target_include_directories(ydb-library-yql-parser-pg_catalog-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_catalog + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/include ) target_link_libraries(ydb-library-yql-parser-pg_catalog-ut PUBLIC contrib-libs-cxxsupp @@ -17,6 +18,7 @@ target_link_libraries(ydb-library-yql-parser-pg_catalog-ut PUBLIC library-cpp-cpuid_check cpp-testing-unittest_main yql-parser-pg_catalog + yql-parser-pg_wrapper ) target_link_options(ydb-library-yql-parser-pg_catalog-ut PRIVATE -Wl,-no_deduplicate @@ -26,6 +28,7 @@ target_link_options(ydb-library-yql-parser-pg_catalog-ut PRIVATE ) target_sources(ydb-library-yql-parser-pg_catalog-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_catalog/ut/catalog_ut.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_catalog/ut/catalog_consts_ut.cpp ) add_test( NAME diff --git a/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.linux-aarch64.txt b/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.linux-aarch64.txt index 661964561e..3e8d5bac42 100644 --- a/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.linux-aarch64.txt +++ b/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.linux-aarch64.txt @@ -10,6 +10,7 @@ add_executable(ydb-library-yql-parser-pg_catalog-ut) target_include_directories(ydb-library-yql-parser-pg_catalog-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_catalog + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/include ) target_link_libraries(ydb-library-yql-parser-pg_catalog-ut PUBLIC contrib-libs-linux-headers @@ -18,6 +19,7 @@ target_link_libraries(ydb-library-yql-parser-pg_catalog-ut PUBLIC library-cpp-lfalloc cpp-testing-unittest_main yql-parser-pg_catalog + yql-parser-pg_wrapper ) target_link_options(ydb-library-yql-parser-pg_catalog-ut PRIVATE -ldl @@ -31,6 +33,7 @@ target_link_options(ydb-library-yql-parser-pg_catalog-ut PRIVATE ) target_sources(ydb-library-yql-parser-pg_catalog-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_catalog/ut/catalog_ut.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_catalog/ut/catalog_consts_ut.cpp ) add_test( NAME diff --git a/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.linux.txt b/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.linux.txt index cbec079ba1..27da60823c 100644 --- a/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.linux.txt +++ b/ydb/library/yql/parser/pg_catalog/ut/CMakeLists.linux.txt @@ -10,6 +10,7 @@ add_executable(ydb-library-yql-parser-pg_catalog-ut) target_include_directories(ydb-library-yql-parser-pg_catalog-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_catalog + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/include ) target_link_libraries(ydb-library-yql-parser-pg_catalog-ut PUBLIC contrib-libs-linux-headers @@ -20,6 +21,7 @@ target_link_libraries(ydb-library-yql-parser-pg_catalog-ut PUBLIC library-cpp-cpuid_check cpp-testing-unittest_main yql-parser-pg_catalog + yql-parser-pg_wrapper ) target_link_options(ydb-library-yql-parser-pg_catalog-ut PRIVATE -ldl @@ -33,6 +35,7 @@ target_link_options(ydb-library-yql-parser-pg_catalog-ut PRIVATE ) target_sources(ydb-library-yql-parser-pg_catalog-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_catalog/ut/catalog_ut.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_catalog/ut/catalog_consts_ut.cpp ) add_test( NAME diff --git a/ydb/library/yql/parser/pg_catalog/ut/catalog_consts_ut.cpp b/ydb/library/yql/parser/pg_catalog/ut/catalog_consts_ut.cpp new file mode 100644 index 0000000000..ad178a2ca2 --- /dev/null +++ b/ydb/library/yql/parser/pg_catalog/ut/catalog_consts_ut.cpp @@ -0,0 +1,33 @@ +#include <ydb/library/yql/parser/pg_catalog/catalog.h> + +// see pg_attribute_printf macro in c.h +// should expand to nothing +#undef __GNUC__ +#undef __IBMC__ + +extern "C" { +#include "postgres.h" +#include "catalog/pg_collation_d.h" +#include "access/stratnum.h" + +#undef Min +#undef Max +} + +#include <library/cpp/testing/unittest/registar.h> + +Y_UNIT_TEST_SUITE(TConstantsTests) { + Y_UNIT_TEST(TestCollationConsts) { + UNIT_ASSERT(NYql::NPg::DefaultCollationOid == DEFAULT_COLLATION_OID); + UNIT_ASSERT(NYql::NPg::C_CollationOid == C_COLLATION_OID); + UNIT_ASSERT(NYql::NPg::PosixCollationOid == POSIX_COLLATION_OID); + } + + Y_UNIT_TEST(BTreeAmStrategyConsts) { + UNIT_ASSERT(static_cast<ui32>(NYql::NPg::EBtreeAmStrategy::Less) == BTLessStrategyNumber); + UNIT_ASSERT(static_cast<ui32>(NYql::NPg::EBtreeAmStrategy::LessOrEqual) == BTLessEqualStrategyNumber); + UNIT_ASSERT(static_cast<ui32>(NYql::NPg::EBtreeAmStrategy::Equal) == BTEqualStrategyNumber); + UNIT_ASSERT(static_cast<ui32>(NYql::NPg::EBtreeAmStrategy::GreaterOrEqual) == BTGreaterEqualStrategyNumber); + UNIT_ASSERT(static_cast<ui32>(NYql::NPg::EBtreeAmStrategy::Greater) == BTGreaterStrategyNumber); + } +} diff --git a/ydb/library/yql/parser/pg_catalog/ut/catalog_ut.cpp b/ydb/library/yql/parser/pg_catalog/ut/catalog_ut.cpp index 52dceecbd9..045518a3b9 100644 --- a/ydb/library/yql/parser/pg_catalog/ut/catalog_ut.cpp +++ b/ydb/library/yql/parser/pg_catalog/ut/catalog_ut.cpp @@ -26,6 +26,8 @@ Y_UNIT_TEST_SUITE(TTypesTests) { UNIT_ASSERT_VALUES_EQUAL(ret.ArrayTypeId, 1009); UNIT_ASSERT_VALUES_EQUAL(ret.Name, "text"); UNIT_ASSERT_VALUES_EQUAL(ret.ElementTypeId, 0); + UNIT_ASSERT_VALUES_EQUAL(ret.TypeCollation, DefaultCollationOid); + UNIT_ASSERT_VALUES_EQUAL(ret.TypType, ETypType::Base); UNIT_ASSERT(ret.LessProcId); UNIT_ASSERT(ret.EqualProcId); UNIT_ASSERT(ret.CompareProcId); @@ -36,6 +38,8 @@ Y_UNIT_TEST_SUITE(TTypesTests) { UNIT_ASSERT_VALUES_EQUAL(ret.ArrayTypeId, 1017); UNIT_ASSERT_VALUES_EQUAL(ret.Name, "point"); UNIT_ASSERT_VALUES_EQUAL(ret.ElementTypeId, LookupType("float8").TypeId); + UNIT_ASSERT_VALUES_EQUAL(ret.TypType, ETypType::Base); + UNIT_ASSERT(ret.TypeSubscriptFuncId); UNIT_ASSERT(!ret.LessProcId); UNIT_ASSERT(!ret.EqualProcId); UNIT_ASSERT(!ret.CompareProcId); @@ -46,6 +50,8 @@ Y_UNIT_TEST_SUITE(TTypesTests) { UNIT_ASSERT_VALUES_EQUAL(ret.ArrayTypeId, 1009); UNIT_ASSERT_VALUES_EQUAL(ret.Name, "_text"); UNIT_ASSERT_VALUES_EQUAL(ret.ElementTypeId, 25); + UNIT_ASSERT_VALUES_EQUAL(ret.TypeCollation, DefaultCollationOid); + UNIT_ASSERT_VALUES_EQUAL(ret.TypType, ETypType::Base); } } @@ -99,6 +105,7 @@ Y_UNIT_TEST_SUITE(TCastsTests) { auto ret = LookupCast(LookupType("int8").TypeId, LookupType("int4").TypeId); UNIT_ASSERT_VALUES_EQUAL(ret.SourceId, LookupType("int8").TypeId); UNIT_ASSERT_VALUES_EQUAL(ret.TargetId, LookupType("int4").TypeId); + UNIT_ASSERT_VALUES_EQUAL(ret.CoercionCode, ECoercionCode::Assignment); UNIT_ASSERT(ret.Method == ECastMethod::Function); UNIT_ASSERT_VALUES_UNEQUAL(ret.FunctionId, 0); @@ -171,20 +178,22 @@ Y_UNIT_TEST_SUITE(TAggregationsTests) { Y_UNIT_TEST_SUITE(TOpClassesTests) { Y_UNIT_TEST(TestMissing) { - UNIT_ASSERT_EXCEPTION(LookupOpClass(EOpClassMethod::Btree, LookupType("json").TypeId), yexception); + UNIT_ASSERT_EXCEPTION(LookupDefaultOpClass(EOpClassMethod::Btree, LookupType("json").TypeId), yexception); } Y_UNIT_TEST(TestOk) { - auto ret = LookupOpClass(EOpClassMethod::Btree, LookupType("int4").TypeId); + auto ret = *LookupDefaultOpClass(EOpClassMethod::Btree, LookupType("int4").TypeId); UNIT_ASSERT(ret.Method == EOpClassMethod::Btree); UNIT_ASSERT_VALUES_EQUAL(ret.TypeId, LookupType("int4").TypeId); UNIT_ASSERT_VALUES_EQUAL(ret.Name, "int4_ops"); UNIT_ASSERT_VALUES_EQUAL(ret.Family, "btree/integer_ops"); + UNIT_ASSERT_VALUES_EQUAL(ret.FamilyId, 1976); - ret = LookupOpClass(EOpClassMethod::Hash, LookupType("int4").TypeId); + ret = *LookupDefaultOpClass(EOpClassMethod::Hash, LookupType("int4").TypeId); UNIT_ASSERT(ret.Method == EOpClassMethod::Hash); UNIT_ASSERT_VALUES_EQUAL(ret.TypeId, LookupType("int4").TypeId); UNIT_ASSERT_VALUES_EQUAL(ret.Name, "int4_ops"); UNIT_ASSERT_VALUES_EQUAL(ret.Family, "hash/integer_ops"); + UNIT_ASSERT_VALUES_EQUAL(ret.FamilyId, 1977); } } diff --git a/ydb/library/yql/parser/pg_wrapper/CMakeLists.darwin.txt b/ydb/library/yql/parser/pg_wrapper/CMakeLists.darwin.txt index dae4e344ea..624d3a5aa7 100644 --- a/ydb/library/yql/parser/pg_wrapper/CMakeLists.darwin.txt +++ b/ydb/library/yql/parser/pg_wrapper/CMakeLists.darwin.txt @@ -132,6 +132,7 @@ target_sources(yql-parser-pg_wrapper PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/parser.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/thread_inits.c ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/type_cache.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/port/pg_crc32c_sse42.c ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/port/pg_crc32c_sse42_choose.c ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/access/brin/brin.c diff --git a/ydb/library/yql/parser/pg_wrapper/CMakeLists.linux-aarch64.txt b/ydb/library/yql/parser/pg_wrapper/CMakeLists.linux-aarch64.txt index d02e7246d8..27c23b07fd 100644 --- a/ydb/library/yql/parser/pg_wrapper/CMakeLists.linux-aarch64.txt +++ b/ydb/library/yql/parser/pg_wrapper/CMakeLists.linux-aarch64.txt @@ -131,6 +131,7 @@ target_sources(yql-parser-pg_wrapper PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/parser.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/thread_inits.c ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/type_cache.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/access/brin/brin.c ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/access/brin/brin_bloom.c ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/access/brin/brin_inclusion.c diff --git a/ydb/library/yql/parser/pg_wrapper/CMakeLists.linux.txt b/ydb/library/yql/parser/pg_wrapper/CMakeLists.linux.txt index af95f6e790..23b996059d 100644 --- a/ydb/library/yql/parser/pg_wrapper/CMakeLists.linux.txt +++ b/ydb/library/yql/parser/pg_wrapper/CMakeLists.linux.txt @@ -133,6 +133,7 @@ target_sources(yql-parser-pg_wrapper PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/parser.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/thread_inits.c ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/type_cache.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/port/pg_crc32c_sse42.c ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/port/pg_crc32c_sse42_choose.c ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/access/brin/brin.c diff --git a/ydb/library/yql/parser/pg_wrapper/parser.cpp b/ydb/library/yql/parser/pg_wrapper/parser.cpp index 2bf1b7ebd9..4dbee8cd7d 100644 --- a/ydb/library/yql/parser/pg_wrapper/parser.cpp +++ b/ydb/library/yql/parser/pg_wrapper/parser.cpp @@ -52,6 +52,7 @@ extern "C" { extern __thread Latch LocalLatchData; extern void destroy_timezone_hashtable(); +extern void destroy_typecache_hashtable(); extern void free_current_locale_conv(); const char *progname; @@ -302,6 +303,8 @@ extern "C" void setup_pg_thread_cleanup() { struct TThreadCleanup { ~TThreadCleanup() { destroy_timezone_hashtable(); + destroy_typecache_hashtable(); + free_current_locale_conv(); ResourceOwnerDelete(CurrentResourceOwner); MemoryContextDelete(TopMemoryContext); diff --git a/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/lsyscache.c b/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/lsyscache.c index efeb31ffb6..9c1c51e287 100644 --- a/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/lsyscache.c +++ b/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/lsyscache.c @@ -161,8 +161,8 @@ get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, * Returns InvalidOid if there is no pg_amop entry for the given keys. */ Oid -get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, - int16 strategy) +get_opfamily_member_original(Oid opfamily, Oid lefttype, Oid righttype, + int16 strategy) { HeapTuple tp; Form_pg_amop amop_tup; @@ -791,7 +791,7 @@ comparison_ops_are_compatible(Oid opno1, Oid opno2) * Returns InvalidOid if there is no pg_amproc entry for the given keys. */ Oid -get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum) +get_opfamily_proc_original(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum) { HeapTuple tp; Form_pg_amproc amproc_tup; @@ -1253,7 +1253,7 @@ get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype) * operator given the operator oid. */ RegProcedure -get_opcode(Oid opno) +get_opcode_original(Oid opno) { HeapTuple tp; @@ -2757,15 +2757,17 @@ get_array_type(Oid typid) Oid get_promoted_array_type(Oid typid) { - Oid array_type = get_array_type(typid); + Oid array_type = get_array_type(typid); - if (OidIsValid(array_type)) - return array_type; - if (OidIsValid(get_element_type(typid))) - return typid; - return InvalidOid; + if (OidIsValid(array_type)) + return array_type; + if (OidIsValid(get_element_type(typid))) + return typid; + return InvalidOid; } +extern Oid get_base_element_type(Oid typid); + /* * get_base_element_type * Given the type OID, get the typelem, looking "through" any domain @@ -2776,7 +2778,7 @@ get_promoted_array_type(Oid typid) * about the typmod of the array. */ Oid -get_base_element_type(Oid typid) +get_base_element_type_original(Oid typid) { /* * We loop to find the bottom base type in a stack of domains. diff --git a/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/typcache.c b/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/typcache.c index abe0c08313..6860026d04 100644 --- a/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/typcache.c +++ b/ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/typcache.c @@ -289,14 +289,14 @@ static void load_typcache_tupdesc(TypeCacheEntry *typentry); static void load_rangetype_info(TypeCacheEntry *typentry); static void load_multirangetype_info(TypeCacheEntry *typentry); static void load_domaintype_info(TypeCacheEntry *typentry); -static int dcs_cmp(const void *a, const void *b); +static int dcs_cmp(const void *a, const void *b); static void decr_dcc_refcount(DomainConstraintCache *dcc); static void dccref_deletion_callback(void *arg); static List *prep_domain_constraints(List *constraints, MemoryContext execctx); -static bool array_element_has_equality(TypeCacheEntry *typentry); -static bool array_element_has_compare(TypeCacheEntry *typentry); -static bool array_element_has_hashing(TypeCacheEntry *typentry); -static bool array_element_has_extended_hashing(TypeCacheEntry *typentry); +bool array_element_has_equality(TypeCacheEntry *typentry); +bool array_element_has_compare(TypeCacheEntry *typentry); +bool array_element_has_hashing(TypeCacheEntry *typentry); +bool array_element_has_extended_hashing(TypeCacheEntry *typentry); static void cache_array_element_properties(TypeCacheEntry *typentry); static bool record_fields_have_equality(TypeCacheEntry *typentry); static bool record_fields_have_compare(TypeCacheEntry *typentry); @@ -335,7 +335,7 @@ static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc, * are InvalidOid or not. */ TypeCacheEntry * -lookup_type_cache(Oid type_id, int flags) +lookup_type_cache_original(Oid type_id, int flags) { TypeCacheEntry *typentry; bool found; @@ -1414,7 +1414,7 @@ DomainHasConstraints(Oid type_id) * component datatype(s). */ -static bool +bool array_element_has_equality(TypeCacheEntry *typentry) { if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES)) @@ -1422,7 +1422,7 @@ array_element_has_equality(TypeCacheEntry *typentry) return (typentry->flags & TCFLAGS_HAVE_ELEM_EQUALITY) != 0; } -static bool +bool array_element_has_compare(TypeCacheEntry *typentry) { if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES)) @@ -1430,7 +1430,7 @@ array_element_has_compare(TypeCacheEntry *typentry) return (typentry->flags & TCFLAGS_HAVE_ELEM_COMPARE) != 0; } -static bool +bool array_element_has_hashing(TypeCacheEntry *typentry) { if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES)) @@ -1438,7 +1438,7 @@ array_element_has_hashing(TypeCacheEntry *typentry) return (typentry->flags & TCFLAGS_HAVE_ELEM_HASHING) != 0; } -static bool +bool array_element_has_extended_hashing(TypeCacheEntry *typentry) { if (!(typentry->flags & TCFLAGS_CHECKED_ELEM_PROPERTIES)) diff --git a/ydb/library/yql/parser/pg_wrapper/type_cache.cpp b/ydb/library/yql/parser/pg_wrapper/type_cache.cpp new file mode 100644 index 0000000000..022df30572 --- /dev/null +++ b/ydb/library/yql/parser/pg_wrapper/type_cache.cpp @@ -0,0 +1,506 @@ +//================================================================================== +// lookup_type_cache reimplemented for YQL +//================================================================================== + +#include <util/system/compiler.h> +#include <ydb/library/yql/parser/pg_catalog/catalog.h> + +extern "C" { +#include "postgres.h" +#include "catalog/pg_operator_d.h" +#include "access/hash.h" +#include "utils/catcache.h" +#include "utils/fmgroids.h" +#include "utils/typcache.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/syscache.h" +} + +#include "type_cache.h" + +namespace NYql { + +typedef struct HTAB HTAB; + +static __thread HTAB *YQL_TypeCacheHash = nullptr; + +HTAB *init_type_cache() { + if (CacheMemoryContext == nullptr) + CreateCacheMemoryContext(); + + HASHCTL ctl = { + .keysize = sizeof(Oid), + .entrysize = sizeof(TypeCacheEntry) + }; + + return hash_create("Type information cache", 64, &ctl, + HASH_ELEM | HASH_BLOBS); +} + +extern "C" { +extern bool array_element_has_equality(TypeCacheEntry *typentry); +extern bool array_element_has_compare(TypeCacheEntry *typentry); +extern bool array_element_has_hashing(TypeCacheEntry *typentry); +extern bool array_element_has_extended_hashing(TypeCacheEntry *typentry); + +/* + * lookup_type_cache + * + * Fetch the type cache entry for the specified datatype, and make sure that + * all the fields requested by bits in 'flags' are valid. + * + * The the caller needs to check whether the fields are InvalidOid or not. + */ +TypeCacheEntry* +lookup_type_cache(Oid type_id, int flags) { + if (Y_UNLIKELY(YQL_TypeCacheHash == nullptr)) { + YQL_TypeCacheHash = init_type_cache(); + } + + // Try to look up an existing entry + auto typentry = static_cast<TypeCacheEntry*>(hash_search(YQL_TypeCacheHash, + &type_id, + HASH_FIND, nullptr)); + + if (typentry == nullptr) { + const auto &typeDesc = NYql::NPg::LookupType(type_id); + + bool found; + + typentry = static_cast<TypeCacheEntry*>(hash_search(YQL_TypeCacheHash, + (void *) &type_id, + HASH_ENTER, &found)); + + Y_ASSERT(!found); // it wasn't there a moment ago + + memset(typentry, 0, sizeof(TypeCacheEntry)); + + // These fields can never change, by definition + typentry->type_id = type_id; + // PG 14 seems to use type_id_hash in syscache invalidation callback only, we don't touch the field + // since YQL doesn't use the callback + // typentry->type_id_hash = 0; // GetSysCacheHashValue1(TYPEOID, ObjectIdGetDatum(type_id)); + + typentry->typlen = typeDesc.TypeLen; + typentry->typbyval = typeDesc.PassByValue; + typentry->typalign = typeDesc.TypeAlign; + // TODO: fill depending on the typstorage, if toasting gets implemented in PG + typentry->typstorage = TYPSTORAGE_PLAIN; //typtup->typstorage; + typentry->typtype = static_cast<char>(typeDesc.TypType); + + // TODO: fill for composite types only. Don't touch until YQL supports those + Y_ASSERT(typeDesc.TypType != NYql::NPg::ETypType::Composite); + // typentry->typrelid = 0; //typtup->typrelid; + + typentry->typsubscript = typeDesc.TypeSubscriptFuncId; + typentry->typelem = typeDesc.ElementTypeId; + typentry->typcollation = typeDesc.TypeCollation; + typentry->flags |= TCFLAGS_HAVE_PG_TYPE_DATA; + + // We don't fill base domain type since domains aren't supported in YQL + } + // typentries don't change from callbacks, cause we have none + + /* + * Look up opclasses if we haven't already and any dependent info is + * requested. + */ + if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR | + TYPECACHE_CMP_PROC | + TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO | + TYPECACHE_BTREE_OPFAMILY)) && + !(typentry->flags & TCFLAGS_CHECKED_BTREE_OPCLASS)) + { + const auto opClassDescPtr = NYql::NPg::LookupDefaultOpClass(NYql::NPg::EOpClassMethod::Btree, type_id); + + if (opClassDescPtr != nullptr) { + typentry->btree_opf = opClassDescPtr->FamilyId; + typentry->btree_opintype = opClassDescPtr->TypeId; + } else { + typentry->btree_opf = typentry->btree_opintype = InvalidOid; + } + + /* + * Reset information derived from btree opclass. Note in particular + * that we'll redetermine the eq_opr even if we previously found one; + * this matters in case a btree opclass has been added to a type that + * previously had only a hash opclass. + */ + typentry->flags &= ~(TCFLAGS_CHECKED_EQ_OPR | + TCFLAGS_CHECKED_LT_OPR | + TCFLAGS_CHECKED_GT_OPR | + TCFLAGS_CHECKED_CMP_PROC); + typentry->flags |= TCFLAGS_CHECKED_BTREE_OPCLASS; + } + + /* + * If we need to look up equality operator, and there's no btree opclass, + * force lookup of hash opclass. + */ + if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) && + !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR) && + typentry->btree_opf == InvalidOid) + flags |= TYPECACHE_HASH_OPFAMILY; + + if ((flags & (TYPECACHE_HASH_PROC | TYPECACHE_HASH_PROC_FINFO | + TYPECACHE_HASH_EXTENDED_PROC | + TYPECACHE_HASH_EXTENDED_PROC_FINFO | + TYPECACHE_HASH_OPFAMILY)) && + !(typentry->flags & TCFLAGS_CHECKED_HASH_OPCLASS)) + { + const auto opClassDescPtr = NYql::NPg::LookupDefaultOpClass(NYql::NPg::EOpClassMethod::Hash, type_id); + + if (opClassDescPtr != nullptr) { + typentry->hash_opf = opClassDescPtr->FamilyId; + typentry->hash_opintype = opClassDescPtr->TypeId; + } else { + typentry->hash_opf = typentry->hash_opintype = InvalidOid; + } + + /* + * Reset information derived from hash opclass. We do *not* reset the + * eq_opr; if we already found one from the btree opclass, that + * decision is still good. + */ + typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC | + TCFLAGS_CHECKED_HASH_EXTENDED_PROC); + typentry->flags |= TCFLAGS_CHECKED_HASH_OPCLASS; + } + + /* + * Look for requested operators and functions, if we haven't already. + */ + if ((flags & (TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO)) && + !(typentry->flags & TCFLAGS_CHECKED_EQ_OPR)) + { + ui32 eq_opr = InvalidOid; + + if (typentry->btree_opf != InvalidOid) { + eq_opr = get_opfamily_member(typentry->btree_opf, + typentry->btree_opintype, + typentry->btree_opintype, + BTEqualStrategyNumber); + } + + if (eq_opr == InvalidOid && + typentry->hash_opf != InvalidOid) { + eq_opr = get_opfamily_member(typentry->hash_opf, + typentry->hash_opintype, + typentry->hash_opintype, + HTEqualStrategyNumber); + } + + /* + * If the proposed equality operator is array_eq or record_eq, check + * to see if the element type or column types support equality. If + * not, array_eq or record_eq would fail at runtime, so we don't want + * to report that the type has equality. (We can omit similar + * checking for ranges and multiranges because ranges can't be created + * in the first place unless their subtypes support equality.) + */ + if (eq_opr == ARRAY_EQ_OP && + !array_element_has_equality(typentry)) + eq_opr = InvalidOid; + // TODO: uncomment when YQL supports PG records + else if (eq_opr == RECORD_EQ_OP /* && + !record_fields_have_equality(typentry) */) + eq_opr = InvalidOid; + + /* Force update of eq_opr_finfo only if we're changing state */ + if (typentry->eq_opr != eq_opr) + typentry->eq_opr_finfo.fn_oid = InvalidOid; + + typentry->eq_opr = eq_opr; + + /* + * Reset info about hash functions whenever we pick up new info about + * equality operator. This is so we can ensure that the hash + * functions match the operator. + */ + typentry->flags &= ~(TCFLAGS_CHECKED_HASH_PROC | + TCFLAGS_CHECKED_HASH_EXTENDED_PROC); + typentry->flags |= TCFLAGS_CHECKED_EQ_OPR; + } + + if ((flags & TYPECACHE_LT_OPR) && + !(typentry->flags & TCFLAGS_CHECKED_LT_OPR)) + { + ui32 lt_opr = InvalidOid; + + if (typentry->btree_opf != InvalidOid) { + lt_opr = get_opfamily_member(typentry->btree_opf, + typentry->btree_opintype, + typentry->btree_opintype, + BTLessStrategyNumber); + } + + /* + * As above, make sure array_cmp or record_cmp will succeed; but again + * we need no special check for ranges or multiranges. + */ + if (lt_opr == ARRAY_LT_OP && + !array_element_has_compare(typentry)) + lt_opr = InvalidOid; + // TODO: uncomment when YQL supports PG records + else if (lt_opr == RECORD_LT_OP /* && + !record_fields_have_compare(typentry) */) + lt_opr = InvalidOid; + + typentry->lt_opr = lt_opr; + typentry->flags |= TCFLAGS_CHECKED_LT_OPR; + } + + if ((flags & TYPECACHE_GT_OPR) && + !(typentry->flags & TCFLAGS_CHECKED_GT_OPR)) + { + ui32 gt_opr = InvalidOid; + + if (typentry->btree_opf != InvalidOid) { + gt_opr = get_opfamily_member(typentry->btree_opf, + typentry->btree_opintype, + typentry->btree_opintype, + BTGreaterStrategyNumber); + } + + /* + * As above, make sure array_cmp or record_cmp will succeed; but again + * we need no special check for ranges or multiranges. + */ + if (gt_opr == ARRAY_GT_OP && + !array_element_has_compare(typentry)) + gt_opr = InvalidOid; + // TODO: uncomment when YQL supports PG records + else if (gt_opr == RECORD_GT_OP /* && + !record_fields_have_compare(typentry) */) + gt_opr = InvalidOid; + + typentry->gt_opr = gt_opr; + typentry->flags |= TCFLAGS_CHECKED_GT_OPR; + } + + if ((flags & (TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO)) && + !(typentry->flags & TCFLAGS_CHECKED_CMP_PROC)) + { + Oid cmp_proc = InvalidOid; + + if (typentry->btree_opf != InvalidOid) + cmp_proc = get_opfamily_proc(typentry->btree_opf, + typentry->btree_opintype, + typentry->btree_opintype, + BTORDER_PROC); + + /* + * As above, make sure array_cmp or record_cmp will succeed; but again + * we need no special check for ranges or multiranges. + */ + if (cmp_proc == F_BTARRAYCMP && + !array_element_has_compare(typentry)) + cmp_proc = InvalidOid; + // TODO: uncomment when YQL supports PG records + else if (cmp_proc == F_BTRECORDCMP /* && + !record_fields_have_compare(typentry) */) + cmp_proc = InvalidOid; + + /* Force update of cmp_proc_finfo only if we're changing state */ + if (typentry->cmp_proc != cmp_proc) + typentry->cmp_proc_finfo.fn_oid = InvalidOid; + + typentry->cmp_proc = cmp_proc; + typentry->flags |= TCFLAGS_CHECKED_CMP_PROC; + } + + if ((flags & (TYPECACHE_HASH_PROC | TYPECACHE_HASH_PROC_FINFO)) && + !(typentry->flags & TCFLAGS_CHECKED_HASH_PROC)) + { + Oid hash_proc = InvalidOid; + + /* + * We insist that the eq_opr, if one has been determined, match the + * hash opclass; else report there is no hash function. + */ + if (typentry->hash_opf != InvalidOid && + (!OidIsValid(typentry->eq_opr) || + typentry->eq_opr == get_opfamily_member(typentry->hash_opf, + typentry->hash_opintype, + typentry->hash_opintype, + HTEqualStrategyNumber))) { + hash_proc = get_opfamily_proc(typentry->hash_opf, + typentry->hash_opintype, + typentry->hash_opintype, + HASHSTANDARD_PROC); + } + + /* + * As above, make sure hash_array, hash_record, or hash_range will + * succeed. + */ + if (hash_proc == F_HASH_ARRAY && + !array_element_has_hashing(typentry)) + hash_proc = InvalidOid; + // TODO: uncomment when YQL supports PG records + else if (hash_proc == F_HASH_RECORD /* && + !record_fields_have_hashing(typentry) */) + hash_proc = InvalidOid; + // TODO: uncomment when YQL supports PG ranges + else if (hash_proc == F_HASH_RANGE /* && + !range_element_has_hashing(typentry) */) + hash_proc = InvalidOid; + + /* + * Likewise for hash_multirange. + */ + // TODO: uncomment when YQL supports PG multiranges + if (hash_proc == F_HASH_MULTIRANGE /* && + !multirange_element_has_hashing(typentry) */) + hash_proc = InvalidOid; + + /* Force update of hash_proc_finfo only if we're changing state */ + if (typentry->hash_proc != hash_proc) + typentry->hash_proc_finfo.fn_oid = InvalidOid; + + typentry->hash_proc = hash_proc; + typentry->flags |= TCFLAGS_CHECKED_HASH_PROC; + } + + if ((flags & (TYPECACHE_HASH_EXTENDED_PROC | + TYPECACHE_HASH_EXTENDED_PROC_FINFO)) && + !(typentry->flags & TCFLAGS_CHECKED_HASH_EXTENDED_PROC)) + { + Oid hash_extended_proc = InvalidOid; + + /* + * We insist that the eq_opr, if one has been determined, match the + * hash opclass; else report there is no hash function. + */ + if (typentry->hash_opf != InvalidOid && + (!OidIsValid(typentry->eq_opr) || + typentry->eq_opr == get_opfamily_member(typentry->hash_opf, + typentry->hash_opintype, + typentry->hash_opintype, + HTEqualStrategyNumber))) + { + hash_extended_proc = get_opfamily_proc(typentry->hash_opf, + typentry->hash_opintype, + typentry->hash_opintype, + HASHEXTENDED_PROC); + } + + /* + * As above, make sure hash_array_extended, hash_record_extended, or + * hash_range_extended will succeed. + */ + if (hash_extended_proc == F_HASH_ARRAY_EXTENDED && + !array_element_has_extended_hashing(typentry)) + hash_extended_proc = InvalidOid; + // TODO: uncomment when YQL supports PG records + else if (hash_extended_proc == F_HASH_RECORD_EXTENDED /* && + !record_fields_have_extended_hashing(typentry) */) + hash_extended_proc = InvalidOid; + // TODO: uncomment when YQL supports PG ranges + else if (hash_extended_proc == F_HASH_RANGE_EXTENDED /* && + !range_element_has_extended_hashing(typentry) */) + hash_extended_proc = InvalidOid; + + /* + * Likewise for hash_multirange_extended. + */ + // TODO: uncomment when YQL supports PG multiranges + if (hash_extended_proc == F_HASH_MULTIRANGE_EXTENDED /* && + !multirange_element_has_extended_hashing(typentry) */) + hash_extended_proc = InvalidOid; + + /* Force update of proc finfo only if we're changing state */ + if (typentry->hash_extended_proc != hash_extended_proc) + typentry->hash_extended_proc_finfo.fn_oid = InvalidOid; + + typentry->hash_extended_proc = hash_extended_proc; + typentry->flags |= TCFLAGS_CHECKED_HASH_EXTENDED_PROC; + } + + /* + * Set up fmgr lookup info as requested + * + * Note: we tell fmgr the finfo structures live in CacheMemoryContext, + * which is not quite right (they're really in the hash table's private + * memory context) but this will do for our purposes. + */ + if ((flags & TYPECACHE_EQ_OPR_FINFO) && + typentry->eq_opr_finfo.fn_oid == InvalidOid && + typentry->eq_opr != InvalidOid) + { + ui32 eq_opr_func = get_opcode(typentry->eq_opr); + if (eq_opr_func != InvalidOid) + fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo, + CacheMemoryContext); + } + + if ((flags & TYPECACHE_CMP_PROC_FINFO) && + typentry->cmp_proc_finfo.fn_oid == InvalidOid && + typentry->cmp_proc != InvalidOid) + { + fmgr_info_cxt(typentry->cmp_proc, &typentry->cmp_proc_finfo, + CacheMemoryContext); + } + + if ((flags & TYPECACHE_HASH_PROC_FINFO) && + typentry->hash_proc_finfo.fn_oid == InvalidOid && + typentry->hash_proc != InvalidOid) + { + fmgr_info_cxt(typentry->hash_proc, &typentry->hash_proc_finfo, + CacheMemoryContext); + } + + if ((flags & TYPECACHE_HASH_EXTENDED_PROC_FINFO) && + typentry->hash_extended_proc_finfo.fn_oid == InvalidOid && + typentry->hash_extended_proc != InvalidOid) + { + fmgr_info_cxt(typentry->hash_extended_proc, + &typentry->hash_extended_proc_finfo, + CacheMemoryContext); + } + + return typentry; +} + +Oid +get_base_element_type(Oid type_id) { + const auto& typeDesc = NYql::NPg::LookupType(type_id); + + return (typeDesc.TypeSubscriptFuncId == F_ARRAY_SUBSCRIPT_HANDLER) + ? typeDesc.ElementTypeId + : InvalidOid; +} + +Oid +get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy) { + if (NYql::NPg::HasAmOp(opfamily, strategy, lefttype, righttype)) { + const auto &opDesc = NYql::NPg::LookupAmOp(opfamily, strategy, lefttype, righttype); + return opDesc.OperId; + } + return InvalidOid; +} + +Oid +get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum) { + if (NYql::NPg::HasAmProc(opfamily, procnum, lefttype, righttype)) { + const auto &procDesc = NYql::NPg::LookupAmProc(opfamily, procnum, lefttype, righttype); + return procDesc.ProcId; + } + return InvalidOid; +} + +RegProcedure +get_opcode(Oid opno) +{ + const auto& oprDesc = NYql::NPg::LookupOper(opno); + return oprDesc.ProcId; +} + +void destroy_typecache_hashtable() { + hash_destroy(YQL_TypeCacheHash); + YQL_TypeCacheHash = nullptr; +} + +} +}
\ No newline at end of file diff --git a/ydb/library/yql/parser/pg_wrapper/type_cache.h b/ydb/library/yql/parser/pg_wrapper/type_cache.h new file mode 100644 index 0000000000..d3b225cb6b --- /dev/null +++ b/ydb/library/yql/parser/pg_wrapper/type_cache.h @@ -0,0 +1,24 @@ +#pragma once + +namespace NYql { + +// Private flag bits in the TypeCacheEntry.flags field +constexpr ui32 TCFLAGS_HAVE_PG_TYPE_DATA = 0x000001; +constexpr ui32 TCFLAGS_CHECKED_BTREE_OPCLASS = 0x000002; +constexpr ui32 TCFLAGS_CHECKED_HASH_OPCLASS = 0x000004; +constexpr ui32 TCFLAGS_CHECKED_EQ_OPR = 0x000008; +constexpr ui32 TCFLAGS_CHECKED_LT_OPR = 0x000010; +constexpr ui32 TCFLAGS_CHECKED_GT_OPR = 0x000020; +constexpr ui32 TCFLAGS_CHECKED_CMP_PROC = 0x000040; +constexpr ui32 TCFLAGS_CHECKED_HASH_PROC = 0x000080; +constexpr ui32 TCFLAGS_CHECKED_HASH_EXTENDED_PROC = 0x000100; +constexpr ui32 TCFLAGS_CHECKED_ELEM_PROPERTIES = 0x000200; +constexpr ui32 TCFLAGS_HAVE_ELEM_EQUALITY = 0x000400; +constexpr ui32 TCFLAGS_HAVE_ELEM_COMPARE = 0x000800; +constexpr ui32 TCFLAGS_HAVE_ELEM_HASHING = 0x001000; +constexpr ui32 TCFLAGS_HAVE_ELEM_EXTENDED_HASHING = 0x002000; + +// Copied from nbtree.h +constexpr ui32 BTORDER_PROC = 1; + +} diff --git a/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.darwin.txt b/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.darwin.txt index cf6bc5596d..4c3ddfb126 100644 --- a/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.darwin.txt +++ b/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.darwin.txt @@ -13,6 +13,7 @@ target_compile_options(ydb-library-yql-parser-pg_wrapper-ut PRIVATE ) target_include_directories(ydb-library-yql-parser-pg_wrapper-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/include ) target_link_libraries(ydb-library-yql-parser-pg_wrapper-ut PUBLIC contrib-libs-cxxsupp @@ -35,6 +36,7 @@ target_link_options(ydb-library-yql-parser-pg_wrapper-ut PRIVATE target_sources(ydb-library-yql-parser-pg_wrapper-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/ut/parser_ut.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/ut/sort_ut.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/ut/type_cache_ut.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/minikql/comp_nodes/ut/mkql_test_factory.cpp ) add_test( diff --git a/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.linux-aarch64.txt b/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.linux-aarch64.txt index 94052d15f1..c0b3cba1cc 100644 --- a/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.linux-aarch64.txt +++ b/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.linux-aarch64.txt @@ -13,6 +13,7 @@ target_compile_options(ydb-library-yql-parser-pg_wrapper-ut PRIVATE ) target_include_directories(ydb-library-yql-parser-pg_wrapper-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/include ) target_link_libraries(ydb-library-yql-parser-pg_wrapper-ut PUBLIC contrib-libs-linux-headers @@ -40,6 +41,7 @@ target_link_options(ydb-library-yql-parser-pg_wrapper-ut PRIVATE target_sources(ydb-library-yql-parser-pg_wrapper-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/ut/parser_ut.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/ut/sort_ut.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/ut/type_cache_ut.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/minikql/comp_nodes/ut/mkql_test_factory.cpp ) add_test( diff --git a/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.linux.txt b/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.linux.txt index 08bcc2f954..9d8e7c0138 100644 --- a/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.linux.txt +++ b/ydb/library/yql/parser/pg_wrapper/ut/CMakeLists.linux.txt @@ -13,6 +13,7 @@ target_compile_options(ydb-library-yql-parser-pg_wrapper-ut PRIVATE ) target_include_directories(ydb-library-yql-parser-pg_wrapper-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/postgresql/src/include ) target_link_libraries(ydb-library-yql-parser-pg_wrapper-ut PUBLIC contrib-libs-linux-headers @@ -42,6 +43,7 @@ target_link_options(ydb-library-yql-parser-pg_wrapper-ut PRIVATE target_sources(ydb-library-yql-parser-pg_wrapper-ut PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/ut/parser_ut.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/ut/sort_ut.cpp + ${CMAKE_SOURCE_DIR}/ydb/library/yql/parser/pg_wrapper/ut/type_cache_ut.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/minikql/comp_nodes/ut/mkql_test_factory.cpp ) add_test( diff --git a/ydb/library/yql/parser/pg_wrapper/ut/type_cache_ut.cpp b/ydb/library/yql/parser/pg_wrapper/ut/type_cache_ut.cpp new file mode 100644 index 0000000000..b73f51901e --- /dev/null +++ b/ydb/library/yql/parser/pg_wrapper/ut/type_cache_ut.cpp @@ -0,0 +1,198 @@ +#include <library/cpp/testing/unittest/registar.h> +#include <library/cpp/testing/hook/hook.h> + +// see pg_attribute_printf macro in c.h +// should expand to nothing +#undef __GNUC__ +#undef __IBMC__ + +extern "C" { +#include "postgres.h" +#include "utils/typcache.h" + +#undef Min +#undef Max + +#include <ydb/library/yql/parser/pg_wrapper/thread_inits.h> +} + +#include "type_cache.h" + +using namespace ::NYql; + +Y_UNIT_TEST_SUITE(TLookupTypeCacheTests) { + // Defined in pg_type.dat + constexpr ui32 INT4_TYPEID = 23; + constexpr ui32 ANYARRAY_TYPEID = 2277; + + TypeCacheEntry* cacheEntry = nullptr; + + // We initialize a basic minimally initialized PG cache entry + // The tests then fill in various parts of it + Y_TEST_HOOK_BEFORE_RUN(InitTest) { + pg_thread_init(); + + cacheEntry = lookup_type_cache(INT4_TYPEID, 0); + } + + Y_UNIT_TEST(TestEqOpr) { + auto cacheEntry = lookup_type_cache(INT4_TYPEID, TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->btree_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->btree_opintype == INT4_TYPEID); + + UNIT_ASSERT(cacheEntry->eq_opr != InvalidOid); + UNIT_ASSERT(cacheEntry->eq_opr_finfo.fn_addr); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_BTREE_OPCLASS | TCFLAGS_CHECKED_EQ_OPR)); + } + + Y_UNIT_TEST(TestEqOprArray) { + auto cacheEntry = lookup_type_cache(ANYARRAY_TYPEID, TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->btree_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->btree_opintype == ANYARRAY_TYPEID); + + UNIT_ASSERT(cacheEntry->eq_opr == InvalidOid); + UNIT_ASSERT(cacheEntry->eq_opr_finfo.fn_addr == nullptr); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_BTREE_OPCLASS | TCFLAGS_CHECKED_EQ_OPR)); + } + + Y_UNIT_TEST(TestLtOpr) { + auto cacheEntry = lookup_type_cache(INT4_TYPEID, TYPECACHE_LT_OPR); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->btree_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->btree_opintype == INT4_TYPEID); + + UNIT_ASSERT(cacheEntry->lt_opr != InvalidOid); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_BTREE_OPCLASS | TCFLAGS_CHECKED_LT_OPR)); + } + + Y_UNIT_TEST(TestLtOprArray) { + auto cacheEntry = lookup_type_cache(ANYARRAY_TYPEID, TYPECACHE_LT_OPR); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->btree_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->btree_opintype == ANYARRAY_TYPEID); + + UNIT_ASSERT(cacheEntry->lt_opr == InvalidOid); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_BTREE_OPCLASS | TCFLAGS_CHECKED_LT_OPR)); + } + + Y_UNIT_TEST(TestGtOpr) { + auto cacheEntry = lookup_type_cache(INT4_TYPEID, TYPECACHE_GT_OPR); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->btree_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->btree_opintype == INT4_TYPEID); + + UNIT_ASSERT(cacheEntry->gt_opr != InvalidOid); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_BTREE_OPCLASS | TCFLAGS_CHECKED_GT_OPR)); + } + + Y_UNIT_TEST(TestGtOprArray) { + auto cacheEntry = lookup_type_cache(ANYARRAY_TYPEID, TYPECACHE_GT_OPR); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->btree_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->btree_opintype == ANYARRAY_TYPEID); + + UNIT_ASSERT(cacheEntry->gt_opr == InvalidOid); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_BTREE_OPCLASS | TCFLAGS_CHECKED_GT_OPR)); + } + + Y_UNIT_TEST(TestCmpProc) { + auto cacheEntry = lookup_type_cache(INT4_TYPEID, TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->btree_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->btree_opintype == INT4_TYPEID); + + UNIT_ASSERT(cacheEntry->cmp_proc != InvalidOid); + UNIT_ASSERT(cacheEntry->cmp_proc_finfo.fn_addr); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_BTREE_OPCLASS | TCFLAGS_CHECKED_CMP_PROC)); + } + + Y_UNIT_TEST(TestCmpProcArray) { + auto cacheEntry = lookup_type_cache(ANYARRAY_TYPEID, TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->btree_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->btree_opintype == ANYARRAY_TYPEID); + + UNIT_ASSERT(cacheEntry->cmp_proc == InvalidOid); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_BTREE_OPCLASS | TCFLAGS_CHECKED_CMP_PROC)); + } + + Y_UNIT_TEST(TestHashProc) { + auto cacheEntry = lookup_type_cache(INT4_TYPEID, TYPECACHE_HASH_PROC | TYPECACHE_HASH_PROC_FINFO); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->hash_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->hash_opintype == INT4_TYPEID); + + UNIT_ASSERT(cacheEntry->hash_proc != InvalidOid); + UNIT_ASSERT(cacheEntry->hash_proc_finfo.fn_addr); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_HASH_OPCLASS | TCFLAGS_CHECKED_HASH_PROC)); + } + + Y_UNIT_TEST(TestHashProcArray) { + auto cacheEntry = lookup_type_cache(ANYARRAY_TYPEID, TYPECACHE_HASH_PROC | TYPECACHE_HASH_PROC_FINFO); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->hash_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->hash_opintype == ANYARRAY_TYPEID); + + UNIT_ASSERT(cacheEntry->hash_proc == InvalidOid); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_HASH_OPCLASS | TCFLAGS_CHECKED_HASH_PROC)); + } + + Y_UNIT_TEST(TestHashExtendedProc) { + auto cacheEntry = lookup_type_cache(INT4_TYPEID, TYPECACHE_HASH_EXTENDED_PROC | TYPECACHE_HASH_EXTENDED_PROC_FINFO); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->hash_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->hash_opintype == INT4_TYPEID); + + UNIT_ASSERT(cacheEntry->hash_extended_proc != InvalidOid); + UNIT_ASSERT(cacheEntry->hash_extended_proc_finfo.fn_addr); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_HASH_OPCLASS | TCFLAGS_CHECKED_HASH_EXTENDED_PROC)); + } + + Y_UNIT_TEST(TestHashExtendedProcArray) { + auto cacheEntry = lookup_type_cache(ANYARRAY_TYPEID, TYPECACHE_HASH_EXTENDED_PROC | TYPECACHE_HASH_EXTENDED_PROC_FINFO); + + UNIT_ASSERT(cacheEntry); + + UNIT_ASSERT(cacheEntry->hash_opf != InvalidOid); + UNIT_ASSERT(cacheEntry->hash_opintype == ANYARRAY_TYPEID); + + UNIT_ASSERT(cacheEntry->hash_extended_proc == InvalidOid); + + UNIT_ASSERT(cacheEntry->flags & (TCFLAGS_CHECKED_HASH_OPCLASS | TCFLAGS_CHECKED_HASH_EXTENDED_PROC)); + } +} |