В случае, если экранирование ?
невозможно, вы можете создать дублирующий оператор с другим именем.
Новый оператор
Синтаксис для создание операторов в Postgres:
CREATE OPERATOR name (
PROCEDURE = function_name
[, LEFTARG = left_type ] [, RIGHTARG = right_type ]
[, COMMUTATOR = com_op ] [, NEGATOR = neg_op ]
[, RESTRICT = res_proc ] [, JOIN = join_proc ]
[, HASHES ] [, MERGES ]
)
В случае использования ?|
в jsonb
это будет:
CREATE OPERATOR ^|(
PROCEDURE = jsonb_exists_any,
LEFTARG = jsonb,
RIGHTARG = _text,
RESTRICT = contsel,
JOIN = contjoinsel);
Я использовал ^|
в качестве примера, альтернативное имя.Это может быть любая последовательность из этого списка: + - * / < > = ~ ! @ # % ^ & |
? `.
Вы можете найти текущее определение интересующего вас оператора, запросив pg_catalog.pg_operator table.
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
Вы также можете использовать инструмент GUI, такой как pgAdmin и просмотреть pg_catalog
, чтобы подготовить определение SQL для повторного использования.
Включение индекса
Если вы хотите использовать индекс для этого "нового"оператор, вам потребуется создать новый операторский класс и опционально семейство.В нашем случае нам нужны оба варианта, поскольку мы не можем добавить их в существующее семейство, поскольку оператор по умолчанию уже занимает слот стратегии .
Так же, как и с операторами, рекомендуется использоватьGUI-инструмент, такой как pgAdmin, для просмотра классов операторов и просто его копирования и вставки.
Сначала мы берем OID оператора, из которого мы сделали дубликат:
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
То же самое для семейства операторов (мы получим егоиз таблицы классов операторов вместо этого), мы ищем класс джина, так как он поддерживает ?|
.opcdefault
используется, поскольку существует необязательный класс jsonb_path_ops
, который не поддерживает этот оператор:
SELECT opcfamily
FROM pg_opclass
WHERE opcintype = (SELECT oid FROM pg_type WHERE typname = 'jsonb')
AND opcmethod = (SELECT oid FROM pg_am WHERE amname = 'gin')
AND opcdefault
Затем мы получаем стратегию, используемую оператором , которую мы дублировали:
SELECT amopstrategy,
(SELECT typname FROM pg_type WHERE oid = amoplefttype) AS left_t,
(SELECT typname FROM pg_type WHERE oid = amoprighttype) AS right_t,*
FROM pg_amop
WHERE amopfamily = 4036 --family oid
AND amopopr = 3248 --operator oid
Затем функции, используемые классом :
SELECT amprocnum, amproc::text, pg_get_function_identity_arguments(amproc::oid) AS args,
(SELECT typname FROM pg_type WHERE oid = amproclefttype) AS left_t,
(SELECT typname FROM pg_type WHERE oid = amprocrighttype) AS right_t,*
FROM pg_amproc
WHERE amprocfamily = 4036 --op family
Это подводит нас к этому классу операторов .Это создаст семейство операторов, если оно еще не существует.
CREATE OPERATOR CLASS jsonb_ops_custom
FOR TYPE jsonb USING gin AS
OPERATOR 10 ^|(jsonb, _text),
FUNCTION 1 gin_compare_jsonb(text, text),
FUNCTION 2 gin_extract_jsonb(jsonb, internal, internal),
FUNCTION 3 gin_extract_jsonb_query(jsonb, internal, smallint, internal, internal, internal, internal),
FUNCTION 4 gin_consistent_jsonb(internal, smallint, jsonb, integer, internal, internal, internal, internal),
FUNCTION 6 gin_triconsistent_jsonb(internal, smallint, jsonb, integer, internal, internal, internal);
Теперь вам просто нужно создать индекс, используя имя оператора, которое было создано, что-то вроде:
CREATE INDEX ON jsonb_table USING gin(jsonb_column jsonb_ops_custom)
И вам следуетуметь использовать индекс:
SET enable_seqscan = off;
EXPLAIN ANALYZE
SELECT * FROM jsonb_table WHERE jsonb_column ^| array['b', 'c'];