PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment échapper au caractère point d'interrogation (?) avec Spring JpaRepository

En cas d'échappement de ? n'est pas possible, vous pouvez créer un opérateur en double avec un nom différent.

Nouvel opérateur

Syntaxe pour créer des opérateurs dans 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 cas de ?| utilisé dans jsonb ce sera :

CREATE OPERATOR ^|(
  PROCEDURE = jsonb_exists_any,
  LEFTARG = jsonb,
  RIGHTARG = _text,
  RESTRICT = contsel,
  JOIN = contjoinsel);

J'ai utilisé ^| par exemple, nom alternatif. Il peut s'agir de n'importe quelle séquence de cette liste :+ - * / < > = ~ ! @ # % ^ & | ?`.

Vous pouvez trouver la définition actuelle de l'opérateur qui vous intéresse en interrogeant la table pg_catalog.pg_operator.

SELECT oid, *
  FROM pg_catalog.pg_operator
 WHERE oprname = '?|'
   AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');

Vous pouvez également utiliser un outil graphique comme pgAdmin et parcourir pg_catalog pour que la définition SQL soit prête à être réutilisée.

Activation de l'index

Si vous souhaitez utiliser l'index pour ce "nouveau" opérateur, vous devrez créer une nouvelle classe d'opérateur et éventuellement une famille. Dans notre cas, nous avons besoin des deux, car nous ne pouvons pas l'ajouter à la famille existante, car l'opérateur par défaut prend déjà l'emplacement stratégique.

Tout comme avec les opérateurs, il est recommandé d'utiliser un outil graphique comme pgAdmin pour parcourir les classes d'opérateurs et simplement copier-coller.

Tout d'abord, nous prenons l'OID de l'opérateur dont nous avons fait un doublon :

SELECT oid, *
  FROM pg_catalog.pg_operator
 WHERE oprname = '?|'
   AND oprleft = (SELECT oid FROM pg_type WHERE typname = 'jsonb');

Même chose pour la famille d'opérateurs (nous l'obtiendrons plutôt à partir de la table des classes d'opérateurs), nous recherchons la classe gin car c'est celle qui prend en charge ?| . opcdefault est utilisé, car il existe une classe facultative jsonb_path_ops qui ne prend pas en charge cet opérateur :

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

Ensuite, nous obtenons la stratégie utilisée par l'opérateur que nous avons dupliqué :

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

Ensuite les fonctions utilisées par classe :

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

Cela nous amène à cette classe d'opérateurs. Il créera une famille d'opérateurs si elle n'existe pas déjà.

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);

Il ne vous reste plus qu'à créer un index en utilisant le nom de l'opérateur qui a été créé, quelque chose comme :

CREATE INDEX ON jsonb_table USING gin(jsonb_column jsonb_ops_custom)

Et vous devriez pouvoir utiliser index :

SET enable_seqscan = off;
EXPLAIN ANALYZE
SELECT * FROM jsonb_table WHERE jsonb_column ^| array['b', 'c'];