En caso de escapar ?
no es posible, puede crear un operador duplicado con un nombre diferente.
Nuevo operador
Sintaxis para crear operadores en 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 ]
)
En caso de ?|
usado en jsonb
será:
CREATE OPERATOR ^|(
PROCEDURE = jsonb_exists_any,
LEFTARG = jsonb,
RIGHTARG = _text,
RESTRICT = contsel,
JOIN = contjoinsel);
He usado ^|
como ejemplo, nombre alternativo. Puede ser cualquier secuencia de esta lista:+ - * / < > = ~ ! @ # % ^ & |
?`.
Puede encontrar la definición actual del operador que le interesa consultando la tabla pg_catalog.pg_operator.
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
También puede usar una herramienta GUI como pgAdmin y navegar por pg_catalog
para obtener la definición de SQL lista para su reutilización.
Habilitación de índice
Si desea utilizar el índice para este "nuevo" operador, deberá crear una nueva clase de operador y, opcionalmente, una familia. En nuestro caso, necesitamos ambos, ya que no podemos agregarlo a la familia existente, porque el operador predeterminado ya está tomando el espacio de estrategia.
Al igual que con los operadores, se recomienda usar una herramienta GUI como pgAdmin para buscar clases de operadores y simplemente copiar y pegar.
Primero, tomamos el OID del operador del que hicimos un duplicado:
SELECT oid, *
FROM pg_catalog.pg_operator
WHERE oprname = '?|'
AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');
Lo mismo para la familia de operadores (lo obtendremos de la tabla de clases de operadores), estamos buscando la clase gin ya que esta es la que admite ?|
. opcdefault
se usa, porque hay una clase opcional jsonb_path_ops
que no admite este operador:
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
Luego obtenemos la estrategia utilizada por el operador que duplicamos:
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
Luego funciones usadas por clase:
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
Esto nos lleva a esta clase de operador. Creará una familia de operadores si aún no existe.
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);
Ahora solo necesita crear un índice usando el nombre del operador que se creó, algo como:
CREATE INDEX ON jsonb_table USING gin(jsonb_column jsonb_ops_custom)
Y deberías poder usar index:
SET enable_seqscan = off;
EXPLAIN ANALYZE
SELECT * FROM jsonb_table WHERE jsonb_column ^| array['b', 'c'];