PostgreSQL Source Code  git master
jsonb_gin.c File Reference
#include "postgres.h"
#include "access/gin.h"
#include "access/stratnum.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/hashfn.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/jsonb.h"
#include "utils/jsonpath.h"
#include "utils/varlena.h"
Include dependency graph for jsonb_gin.c:

Go to the source code of this file.

Data Structures

struct  PathHashStack
 
struct  GinEntries
 
struct  JsonPathGinNode
 
struct  JsonPathGinPathItem
 
union  JsonPathGinPath
 
struct  JsonPathGinContext
 

Typedefs

typedef struct PathHashStack PathHashStack
 
typedef struct GinEntries GinEntries
 
typedef enum JsonPathGinNodeType JsonPathGinNodeType
 
typedef struct JsonPathGinNode JsonPathGinNode
 
typedef struct JsonPathGinPathItem JsonPathGinPathItem
 
typedef union JsonPathGinPath JsonPathGinPath
 
typedef struct JsonPathGinContext JsonPathGinContext
 
typedef bool(* JsonPathGinAddPathItemFunc) (JsonPathGinPath *path, JsonPathItem *jsp)
 
typedef List *(* JsonPathGinExtractNodesFunc) (JsonPathGinContext *cxt, JsonPathGinPath path, JsonbValue *scalar, List *nodes)
 

Enumerations

enum  JsonPathGinNodeType { JSP_GIN_OR , JSP_GIN_AND , JSP_GIN_ENTRY }
 

Functions

static Datum make_text_key (char flag, const char *str, int len)
 
static Datum make_scalar_key (const JsonbValue *scalarVal, bool is_key)
 
static JsonPathGinNodeextract_jsp_bool_expr (JsonPathGinContext *cxt, JsonPathGinPath path, JsonPathItem *jsp, bool not)
 
static void init_gin_entries (GinEntries *entries, int preallocated)
 
static int add_gin_entry (GinEntries *entries, Datum entry)
 
Datum gin_compare_jsonb (PG_FUNCTION_ARGS)
 
Datum gin_extract_jsonb (PG_FUNCTION_ARGS)
 
static bool jsonb_ops__add_path_item (JsonPathGinPath *path, JsonPathItem *jsp)
 
static bool jsonb_path_ops__add_path_item (JsonPathGinPath *path, JsonPathItem *jsp)
 
static JsonPathGinNodemake_jsp_entry_node (Datum entry)
 
static JsonPathGinNodemake_jsp_entry_node_scalar (JsonbValue *scalar, bool iskey)
 
static JsonPathGinNodemake_jsp_expr_node (JsonPathGinNodeType type, int nargs)
 
static JsonPathGinNodemake_jsp_expr_node_args (JsonPathGinNodeType type, List *args)
 
static JsonPathGinNodemake_jsp_expr_node_binary (JsonPathGinNodeType type, JsonPathGinNode *arg1, JsonPathGinNode *arg2)
 
static Listjsonb_ops__extract_nodes (JsonPathGinContext *cxt, JsonPathGinPath path, JsonbValue *scalar, List *nodes)
 
static Listjsonb_path_ops__extract_nodes (JsonPathGinContext *cxt, JsonPathGinPath path, JsonbValue *scalar, List *nodes)
 
static Listextract_jsp_path_expr_nodes (JsonPathGinContext *cxt, JsonPathGinPath path, JsonPathItem *jsp, JsonbValue *scalar)
 
static JsonPathGinNodeextract_jsp_path_expr (JsonPathGinContext *cxt, JsonPathGinPath path, JsonPathItem *jsp, JsonbValue *scalar)
 
static void emit_jsp_gin_entries (JsonPathGinNode *node, GinEntries *entries)
 
static Datumextract_jsp_query (JsonPath *jp, StrategyNumber strat, bool pathOps, int32 *nentries, Pointer **extra_data)
 
static GinTernaryValue execute_jsp_gin_node (JsonPathGinNode *node, void *check, bool ternary)
 
Datum gin_extract_jsonb_query (PG_FUNCTION_ARGS)
 
Datum gin_consistent_jsonb (PG_FUNCTION_ARGS)
 
Datum gin_triconsistent_jsonb (PG_FUNCTION_ARGS)
 
Datum gin_extract_jsonb_path (PG_FUNCTION_ARGS)
 
Datum gin_extract_jsonb_query_path (PG_FUNCTION_ARGS)
 
Datum gin_consistent_jsonb_path (PG_FUNCTION_ARGS)
 
Datum gin_triconsistent_jsonb_path (PG_FUNCTION_ARGS)
 

Typedef Documentation

◆ GinEntries

typedef struct GinEntries GinEntries

◆ JsonPathGinAddPathItemFunc

typedef bool(* JsonPathGinAddPathItemFunc) (JsonPathGinPath *path, JsonPathItem *jsp)

Definition at line 134 of file jsonb_gin.c.

◆ JsonPathGinContext

Definition at line 1 of file jsonb_gin.c.

◆ JsonPathGinExtractNodesFunc

typedef List*(* JsonPathGinExtractNodesFunc) (JsonPathGinContext *cxt, JsonPathGinPath path, JsonbValue *scalar, List *nodes)

Definition at line 141 of file jsonb_gin.c.

◆ JsonPathGinNode

Definition at line 1 of file jsonb_gin.c.

◆ JsonPathGinNodeType

◆ JsonPathGinPath

◆ JsonPathGinPathItem

◆ PathHashStack

typedef struct PathHashStack PathHashStack

Enumeration Type Documentation

◆ JsonPathGinNodeType

Enumerator
JSP_GIN_OR 
JSP_GIN_AND 
JSP_GIN_ENTRY 

Definition at line 87 of file jsonb_gin.c.

88 {
89  JSP_GIN_OR,
JsonPathGinNodeType
Definition: jsonb_gin.c:88
@ JSP_GIN_AND
Definition: jsonb_gin.c:90
@ JSP_GIN_ENTRY
Definition: jsonb_gin.c:91
@ JSP_GIN_OR
Definition: jsonb_gin.c:89

Function Documentation

◆ add_gin_entry()

static int add_gin_entry ( GinEntries entries,
Datum  entry 
)
static

Definition at line 172 of file jsonb_gin.c.

173 {
174  int id = entries->count;
175 
176  if (entries->count >= entries->allocated)
177  {
178  if (entries->allocated)
179  {
180  entries->allocated *= 2;
181  entries->buf = repalloc(entries->buf,
182  sizeof(Datum) * entries->allocated);
183  }
184  else
185  {
186  entries->allocated = 8;
187  entries->buf = palloc(sizeof(Datum) * entries->allocated);
188  }
189  }
190 
191  entries->buf[entries->count++] = entry;
192 
193  return id;
194 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1188
void * palloc(Size size)
Definition: mcxt.c:1068
uintptr_t Datum
Definition: postgres.h:411
int allocated
Definition: jsonb_gin.c:84
Datum * buf
Definition: jsonb_gin.c:82
int count
Definition: jsonb_gin.c:83

References GinEntries::allocated, GinEntries::buf, GinEntries::count, palloc(), and repalloc().

Referenced by emit_jsp_gin_entries(), gin_extract_jsonb(), and gin_extract_jsonb_path().

◆ emit_jsp_gin_entries()

static void emit_jsp_gin_entries ( JsonPathGinNode node,
GinEntries entries 
)
static

Definition at line 719 of file jsonb_gin.c.

720 {
722 
723  switch (node->type)
724  {
725  case JSP_GIN_ENTRY:
726  /* replace datum with its index in the array */
727  node->val.entryIndex = add_gin_entry(entries, node->val.entryDatum);
728  break;
729 
730  case JSP_GIN_OR:
731  case JSP_GIN_AND:
732  {
733  int i;
734 
735  for (i = 0; i < node->val.nargs; i++)
736  emit_jsp_gin_entries(node->args[i], entries);
737 
738  break;
739  }
740  }
741 }
int i
Definition: isn.c:73
static int add_gin_entry(GinEntries *entries, Datum entry)
Definition: jsonb_gin.c:172
static void emit_jsp_gin_entries(JsonPathGinNode *node, GinEntries *entries)
Definition: jsonb_gin.c:719
void check_stack_depth(void)
Definition: postgres.c:3500
JsonPathGinNodeType type
Definition: jsonb_gin.c:99
JsonPathGinNode * args[FLEXIBLE_ARRAY_MEMBER]
Definition: jsonb_gin.c:108
Datum entryDatum
Definition: jsonb_gin.c:105
union JsonPathGinNode::@20 val

References add_gin_entry(), JsonPathGinNode::args, check_stack_depth(), JsonPathGinNode::entryDatum, JsonPathGinNode::entryIndex, i, JSP_GIN_AND, JSP_GIN_ENTRY, JSP_GIN_OR, JsonPathGinNode::nargs, JsonPathGinNode::type, and JsonPathGinNode::val.

Referenced by extract_jsp_query().

◆ execute_jsp_gin_node()

static GinTernaryValue execute_jsp_gin_node ( JsonPathGinNode node,
void *  check,
bool  ternary 
)
static

Definition at line 799 of file jsonb_gin.c.

800 {
802  GinTernaryValue v;
803  int i;
804 
805  switch (node->type)
806  {
807  case JSP_GIN_AND:
808  res = GIN_TRUE;
809  for (i = 0; i < node->val.nargs; i++)
810  {
811  v = execute_jsp_gin_node(node->args[i], check, ternary);
812  if (v == GIN_FALSE)
813  return GIN_FALSE;
814  else if (v == GIN_MAYBE)
815  res = GIN_MAYBE;
816  }
817  return res;
818 
819  case JSP_GIN_OR:
820  res = GIN_FALSE;
821  for (i = 0; i < node->val.nargs; i++)
822  {
823  v = execute_jsp_gin_node(node->args[i], check, ternary);
824  if (v == GIN_TRUE)
825  return GIN_TRUE;
826  else if (v == GIN_MAYBE)
827  res = GIN_MAYBE;
828  }
829  return res;
830 
831  case JSP_GIN_ENTRY:
832  {
833  int index = node->val.entryIndex;
834 
835  if (ternary)
836  return ((GinTernaryValue *) check)[index];
837  else
838  return ((bool *) check)[index] ? GIN_TRUE : GIN_FALSE;
839  }
840 
841  default:
842  elog(ERROR, "invalid jsonpath gin node type: %d", node->type);
843  return GIN_FALSE; /* keep compiler quiet */
844  }
845 }
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define GIN_FALSE
Definition: gin.h:60
char GinTernaryValue
Definition: gin.h:58
#define GIN_MAYBE
Definition: gin.h:62
#define GIN_TRUE
Definition: gin.h:61
static GinTernaryValue execute_jsp_gin_node(JsonPathGinNode *node, void *check, bool ternary)
Definition: jsonb_gin.c:799
Definition: type.h:90

References JsonPathGinNode::args, elog, JsonPathGinNode::entryIndex, ERROR, GIN_FALSE, GIN_MAYBE, GIN_TRUE, i, JSP_GIN_AND, JSP_GIN_ENTRY, JSP_GIN_OR, JsonPathGinNode::nargs, res, JsonPathGinNode::type, and JsonPathGinNode::val.

Referenced by gin_consistent_jsonb(), gin_consistent_jsonb_path(), gin_triconsistent_jsonb(), and gin_triconsistent_jsonb_path().

◆ extract_jsp_bool_expr()

static JsonPathGinNode * extract_jsp_bool_expr ( JsonPathGinContext cxt,
JsonPathGinPath  path,
JsonPathItem jsp,
bool  not 
)
static

Definition at line 583 of file jsonb_gin.c.

585 {
587 
588  switch (jsp->type)
589  {
590  case jpiAnd: /* expr && expr */
591  case jpiOr: /* expr || expr */
592  {
594  JsonPathGinNode *larg;
595  JsonPathGinNode *rarg;
597 
598  jspGetLeftArg(jsp, &arg);
599  larg = extract_jsp_bool_expr(cxt, path, &arg, not);
600 
601  jspGetRightArg(jsp, &arg);
602  rarg = extract_jsp_bool_expr(cxt, path, &arg, not);
603 
604  if (!larg || !rarg)
605  {
606  if (jsp->type == jpiOr)
607  return NULL;
608 
609  return larg ? larg : rarg;
610  }
611 
612  type = not ^ (jsp->type == jpiAnd) ? JSP_GIN_AND : JSP_GIN_OR;
613 
614  return make_jsp_expr_node_binary(type, larg, rarg);
615  }
616 
617  case jpiNot: /* !expr */
618  {
620 
621  jspGetArg(jsp, &arg);
622 
623  /* extract child expression inverting 'not' flag */
624  return extract_jsp_bool_expr(cxt, path, &arg, !not);
625  }
626 
627  case jpiExists: /* EXISTS(path) */
628  {
630 
631  if (not)
632  return NULL; /* NOT EXISTS is not supported */
633 
634  jspGetArg(jsp, &arg);
635 
636  return extract_jsp_path_expr(cxt, path, &arg, NULL);
637  }
638 
639  case jpiNotEqual:
640 
641  /*
642  * 'not' == true case is not supported here because '!(path !=
643  * scalar)' is not equivalent to 'path == scalar' in the general
644  * case because of sequence comparison semantics: 'path == scalar'
645  * === 'EXISTS (path, @ == scalar)', '!(path != scalar)' ===
646  * 'FOR_ALL(path, @ == scalar)'. So, we should translate '!(path
647  * != scalar)' into GIN query 'path == scalar || EMPTY(path)', but
648  * 'EMPTY(path)' queries are not supported by the both jsonb
649  * opclasses. However in strict mode we could omit 'EMPTY(path)'
650  * part if the path can return exactly one item (it does not
651  * contain wildcard accessors or item methods like .keyvalue()
652  * etc.).
653  */
654  return NULL;
655 
656  case jpiEqual: /* path == scalar */
657  {
658  JsonPathItem left_item;
659  JsonPathItem right_item;
660  JsonPathItem *path_item;
661  JsonPathItem *scalar_item;
662  JsonbValue scalar;
663 
664  if (not)
665  return NULL;
666 
667  jspGetLeftArg(jsp, &left_item);
668  jspGetRightArg(jsp, &right_item);
669 
670  if (jspIsScalar(left_item.type))
671  {
672  scalar_item = &left_item;
673  path_item = &right_item;
674  }
675  else if (jspIsScalar(right_item.type))
676  {
677  scalar_item = &right_item;
678  path_item = &left_item;
679  }
680  else
681  return NULL; /* at least one operand should be a scalar */
682 
683  switch (scalar_item->type)
684  {
685  case jpiNull:
686  scalar.type = jbvNull;
687  break;
688  case jpiBool:
689  scalar.type = jbvBool;
690  scalar.val.boolean = !!*scalar_item->content.value.data;
691  break;
692  case jpiNumeric:
693  scalar.type = jbvNumeric;
694  scalar.val.numeric =
695  (Numeric) scalar_item->content.value.data;
696  break;
697  case jpiString:
698  scalar.type = jbvString;
699  scalar.val.string.val = scalar_item->content.value.data;
700  scalar.val.string.len =
701  scalar_item->content.value.datalen;
702  break;
703  default:
704  elog(ERROR, "invalid scalar jsonpath item type: %d",
705  scalar_item->type);
706  return NULL;
707  }
708 
709  return extract_jsp_path_expr(cxt, path, path_item, &scalar);
710  }
711 
712  default:
713  return NULL; /* not a boolean expression */
714  }
715 }
@ jbvNumeric
Definition: jsonb.h:238
@ jbvBool
Definition: jsonb.h:239
@ jbvNull
Definition: jsonb.h:236
@ jbvString
Definition: jsonb.h:237
static JsonPathGinNode * extract_jsp_bool_expr(JsonPathGinContext *cxt, JsonPathGinPath path, JsonPathItem *jsp, bool not)
Definition: jsonb_gin.c:583
static JsonPathGinNode * extract_jsp_path_expr(JsonPathGinContext *cxt, JsonPathGinPath path, JsonPathItem *jsp, JsonbValue *scalar)
Definition: jsonb_gin.c:564
static JsonPathGinNode * make_jsp_expr_node_binary(JsonPathGinNodeType type, JsonPathGinNode *arg1, JsonPathGinNode *arg2)
Definition: jsonb_gin.c:395
void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:998
void jspGetArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:929
void jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1019
#define jspIsScalar(type)
Definition: jsonpath.h:41
@ jpiString
Definition: jsonpath.h:49
@ jpiBool
Definition: jsonpath.h:51
@ jpiExists
Definition: jsonpath.h:78
@ jpiNotEqual
Definition: jsonpath.h:57
@ jpiNot
Definition: jsonpath.h:54
@ jpiAnd
Definition: jsonpath.h:52
@ jpiOr
Definition: jsonpath.h:53
@ jpiNull
Definition: jsonpath.h:48
@ jpiEqual
Definition: jsonpath.h:56
@ jpiNumeric
Definition: jsonpath.h:50
struct NumericData * Numeric
Definition: numeric.h:53
void * arg
struct JsonPathItem::@136::@140 value
JsonPathItemType type
Definition: jsonpath.h:110
union JsonPathItem::@136 content
enum jbvType type
Definition: jsonb.h:263
char * val
Definition: jsonb.h:272

References arg, check_stack_depth(), JsonPathItem::content, elog, ERROR, extract_jsp_path_expr(), jbvBool, jbvNull, jbvNumeric, jbvString, jpiAnd, jpiBool, jpiEqual, jpiExists, jpiNot, jpiNotEqual, jpiNull, jpiNumeric, jpiOr, jpiString, JSP_GIN_AND, JSP_GIN_OR, jspGetArg(), jspGetLeftArg(), jspGetRightArg(), jspIsScalar, make_jsp_expr_node_binary(), generate_unaccent_rules::type, JsonbValue::type, JsonPathItem::type, JsonbValue::val, and JsonPathItem::value.

Referenced by extract_jsp_path_expr_nodes(), and extract_jsp_query().

◆ extract_jsp_path_expr()

static JsonPathGinNode* extract_jsp_path_expr ( JsonPathGinContext cxt,
JsonPathGinPath  path,
JsonPathItem jsp,
JsonbValue scalar 
)
static

Definition at line 564 of file jsonb_gin.c.

566 {
567  /* extract a list of nodes to be AND-ed */
568  List *nodes = extract_jsp_path_expr_nodes(cxt, path, jsp, scalar);
569 
570  if (list_length(nodes) <= 0)
571  /* no nodes were extracted => full scan is needed for this path */
572  return NULL;
573 
574  if (list_length(nodes) == 1)
575  return linitial(nodes); /* avoid extra AND-node */
576 
577  /* construct AND-node for path with filters */
578  return make_jsp_expr_node_args(JSP_GIN_AND, nodes);
579 }
static List * extract_jsp_path_expr_nodes(JsonPathGinContext *cxt, JsonPathGinPath path, JsonPathItem *jsp, JsonbValue *scalar)
Definition: jsonb_gin.c:504
static JsonPathGinNode * make_jsp_expr_node_args(JsonPathGinNodeType type, List *args)
Definition: jsonb_gin.c:382
static int list_length(const List *l)
Definition: pg_list.h:149
#define linitial(l)
Definition: pg_list.h:174
Definition: pg_list.h:51

References extract_jsp_path_expr_nodes(), JSP_GIN_AND, linitial, list_length(), and make_jsp_expr_node_args().

Referenced by extract_jsp_bool_expr(), and extract_jsp_query().

◆ extract_jsp_path_expr_nodes()

static List* extract_jsp_path_expr_nodes ( JsonPathGinContext cxt,
JsonPathGinPath  path,
JsonPathItem jsp,
JsonbValue scalar 
)
static

Definition at line 504 of file jsonb_gin.c.

506 {
508  List *nodes = NIL;
509 
510  for (;;)
511  {
512  switch (jsp->type)
513  {
514  case jpiCurrent:
515  break;
516 
517  case jpiFilter:
518  {
520  JsonPathGinNode *filter;
521 
522  jspGetArg(jsp, &arg);
523 
524  filter = extract_jsp_bool_expr(cxt, path, &arg, false);
525 
526  if (filter)
527  nodes = lappend(nodes, filter);
528 
529  break;
530  }
531 
532  default:
533  if (!cxt->add_path_item(&path, jsp))
534 
535  /*
536  * Path is not supported by the index opclass, return only
537  * the extracted filter nodes.
538  */
539  return nodes;
540  break;
541  }
542 
543  if (!jspGetNext(jsp, &next))
544  break;
545 
546  jsp = &next;
547  }
548 
549  /*
550  * Append nodes from the path expression itself to the already extracted
551  * list of filter nodes.
552  */
553  return cxt->extract_nodes(cxt, path, scalar, nodes);
554 }
static int32 next
Definition: blutils.c:219
bool jspGetNext(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:943
@ jpiFilter
Definition: jsonpath.h:77
@ jpiCurrent
Definition: jsonpath.h:74
List * lappend(List *list, void *datum)
Definition: list.c:336
#define NIL
Definition: pg_list.h:65
JsonPathGinExtractNodesFunc extract_nodes
Definition: jsonb_gin.c:150
JsonPathGinAddPathItemFunc add_path_item
Definition: jsonb_gin.c:149

References JsonPathGinContext::add_path_item, arg, extract_jsp_bool_expr(), JsonPathGinContext::extract_nodes, jpiCurrent, jpiFilter, jspGetArg(), jspGetNext(), lappend(), next, NIL, and JsonPathItem::type.

Referenced by extract_jsp_path_expr().

◆ extract_jsp_query()

static Datum* extract_jsp_query ( JsonPath jp,
StrategyNumber  strat,
bool  pathOps,
int32 nentries,
Pointer **  extra_data 
)
static

Definition at line 748 of file jsonb_gin.c.

750 {
751  JsonPathGinContext cxt;
752  JsonPathItem root;
753  JsonPathGinNode *node;
754  JsonPathGinPath path = {0};
755  GinEntries entries = {0};
756 
757  cxt.lax = (jp->header & JSONPATH_LAX) != 0;
758 
759  if (pathOps)
760  {
763  }
764  else
765  {
768  }
769 
770  jspInit(&root, jp);
771 
772  node = strat == JsonbJsonpathExistsStrategyNumber
773  ? extract_jsp_path_expr(&cxt, path, &root, NULL)
774  : extract_jsp_bool_expr(&cxt, path, &root, false);
775 
776  if (!node)
777  {
778  *nentries = 0;
779  return NULL;
780  }
781 
782  emit_jsp_gin_entries(node, &entries);
783 
784  *nentries = entries.count;
785  if (!*nentries)
786  return NULL;
787 
788  *extra_data = palloc0(sizeof(**extra_data) * entries.count);
789  **extra_data = (Pointer) node;
790 
791  return entries.buf;
792 }
char * Pointer
Definition: c.h:429
return false
Definition: isn.c:131
#define JsonbJsonpathExistsStrategyNumber
Definition: jsonb.h:37
static List * jsonb_ops__extract_nodes(JsonPathGinContext *cxt, JsonPathGinPath path, JsonbValue *scalar, List *nodes)
Definition: jsonb_gin.c:408
static List * jsonb_path_ops__extract_nodes(JsonPathGinContext *cxt, JsonPathGinPath path, JsonbValue *scalar, List *nodes)
Definition: jsonb_gin.c:478
static bool jsonb_ops__add_path_item(JsonPathGinPath *path, JsonPathItem *jsp)
Definition: jsonb_gin.c:278
static bool jsonb_path_ops__add_path_item(JsonPathGinPath *path, JsonPathItem *jsp)
Definition: jsonb_gin.c:323
void jspInit(JsonPathItem *v, JsonPath *js)
Definition: jsonpath.c:839
#define JSONPATH_LAX
Definition: jsonpath.h:32
void * palloc0(Size size)
Definition: mcxt.c:1099
uint32 header
Definition: jsonpath.h:27

References JsonPathGinContext::add_path_item, GinEntries::buf, GinEntries::count, emit_jsp_gin_entries(), extract_jsp_bool_expr(), extract_jsp_path_expr(), JsonPathGinContext::extract_nodes, JsonPath::header, jsonb_ops__add_path_item(), jsonb_ops__extract_nodes(), jsonb_path_ops__add_path_item(), jsonb_path_ops__extract_nodes(), JsonbJsonpathExistsStrategyNumber, JSONPATH_LAX, jspInit(), JsonPathGinContext::lax, and palloc0().

Referenced by gin_extract_jsonb_query(), and gin_extract_jsonb_query_path().

◆ gin_compare_jsonb()

Datum gin_compare_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 203 of file jsonb_gin.c.

204 {
205  text *arg1 = PG_GETARG_TEXT_PP(0);
206  text *arg2 = PG_GETARG_TEXT_PP(1);
207  int32 result;
208  char *a1p,
209  *a2p;
210  int len1,
211  len2;
212 
213  a1p = VARDATA_ANY(arg1);
214  a2p = VARDATA_ANY(arg2);
215 
216  len1 = VARSIZE_ANY_EXHDR(arg1);
217  len2 = VARSIZE_ANY_EXHDR(arg2);
218 
219  /* Compare text as bttextcmp does, but always using C collation */
220  result = varstr_cmp(a1p, len1, a2p, len2, C_COLLATION_OID);
221 
222  PG_FREE_IF_COPY(arg1, 0);
223  PG_FREE_IF_COPY(arg2, 1);
224 
225  PG_RETURN_INT32(result);
226 }
signed int int32
Definition: c.h:440
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define VARDATA_ANY(PTR)
Definition: postgres.h:361
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:354
Definition: c.h:633
int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid)
Definition: varlena.c:1517

References PG_FREE_IF_COPY, PG_GETARG_TEXT_PP, PG_RETURN_INT32, VARDATA_ANY, VARSIZE_ANY_EXHDR, and varstr_cmp().

◆ gin_consistent_jsonb()

Datum gin_consistent_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 928 of file jsonb_gin.c.

929 {
930  bool *check = (bool *) PG_GETARG_POINTER(0);
931  StrategyNumber strategy = PG_GETARG_UINT16(1);
932 
933  /* Jsonb *query = PG_GETARG_JSONB_P(2); */
934  int32 nkeys = PG_GETARG_INT32(3);
935 
936  Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
937  bool *recheck = (bool *) PG_GETARG_POINTER(5);
938  bool res = true;
939  int32 i;
940 
941  if (strategy == JsonbContainsStrategyNumber)
942  {
943  /*
944  * We must always recheck, since we can't tell from the index whether
945  * the positions of the matched items match the structure of the query
946  * object. (Even if we could, we'd also have to worry about hashed
947  * keys and the index's failure to distinguish keys from string array
948  * elements.) However, the tuple certainly doesn't match unless it
949  * contains all the query keys.
950  */
951  *recheck = true;
952  for (i = 0; i < nkeys; i++)
953  {
954  if (!check[i])
955  {
956  res = false;
957  break;
958  }
959  }
960  }
961  else if (strategy == JsonbExistsStrategyNumber)
962  {
963  /*
964  * Although the key is certainly present in the index, we must recheck
965  * because (1) the key might be hashed, and (2) the index match might
966  * be for a key that's not at top level of the JSON object. For (1),
967  * we could look at the query key to see if it's hashed and not
968  * recheck if not, but the index lacks enough info to tell about (2).
969  */
970  *recheck = true;
971  res = true;
972  }
973  else if (strategy == JsonbExistsAnyStrategyNumber)
974  {
975  /* As for plain exists, we must recheck */
976  *recheck = true;
977  res = true;
978  }
979  else if (strategy == JsonbExistsAllStrategyNumber)
980  {
981  /* As for plain exists, we must recheck */
982  *recheck = true;
983  /* ... but unless all the keys are present, we can say "false" */
984  for (i = 0; i < nkeys; i++)
985  {
986  if (!check[i])
987  {
988  res = false;
989  break;
990  }
991  }
992  }
993  else if (strategy == JsonbJsonpathPredicateStrategyNumber ||
995  {
996  *recheck = true;
997 
998  if (nkeys > 0)
999  {
1000  Assert(extra_data && extra_data[0]);
1001  res = execute_jsp_gin_node((JsonPathGinNode *) extra_data[0], check,
1002  false) != GIN_FALSE;
1003  }
1004  }
1005  else
1006  elog(ERROR, "unrecognized strategy number: %d", strategy);
1007 
1009 }
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:272
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define JsonbContainsStrategyNumber
Definition: jsonb.h:33
#define JsonbJsonpathPredicateStrategyNumber
Definition: jsonb.h:38
#define JsonbExistsAllStrategyNumber
Definition: jsonb.h:36
#define JsonbExistsStrategyNumber
Definition: jsonb.h:34
#define JsonbExistsAnyStrategyNumber
Definition: jsonb.h:35
Assert(fmt[strlen(fmt) - 1] !='\n')
uint16 StrategyNumber
Definition: stratnum.h:22

References Assert(), elog, ERROR, execute_jsp_gin_node(), GIN_FALSE, i, JsonbContainsStrategyNumber, JsonbExistsAllStrategyNumber, JsonbExistsAnyStrategyNumber, JsonbExistsStrategyNumber, JsonbJsonpathExistsStrategyNumber, JsonbJsonpathPredicateStrategyNumber, PG_GETARG_INT32, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_BOOL, and res.

◆ gin_consistent_jsonb_path()

Datum gin_consistent_jsonb_path ( PG_FUNCTION_ARGS  )

Definition at line 1219 of file jsonb_gin.c.

1220 {
1221  bool *check = (bool *) PG_GETARG_POINTER(0);
1222  StrategyNumber strategy = PG_GETARG_UINT16(1);
1223 
1224  /* Jsonb *query = PG_GETARG_JSONB_P(2); */
1225  int32 nkeys = PG_GETARG_INT32(3);
1226  Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
1227  bool *recheck = (bool *) PG_GETARG_POINTER(5);
1228  bool res = true;
1229  int32 i;
1230 
1231  if (strategy == JsonbContainsStrategyNumber)
1232  {
1233  /*
1234  * jsonb_path_ops is necessarily lossy, not only because of hash
1235  * collisions but also because it doesn't preserve complete
1236  * information about the structure of the JSON object. Besides, there
1237  * are some special rules around the containment of raw scalars in
1238  * arrays that are not handled here. So we must always recheck a
1239  * match. However, if not all of the keys are present, the tuple
1240  * certainly doesn't match.
1241  */
1242  *recheck = true;
1243  for (i = 0; i < nkeys; i++)
1244  {
1245  if (!check[i])
1246  {
1247  res = false;
1248  break;
1249  }
1250  }
1251  }
1252  else if (strategy == JsonbJsonpathPredicateStrategyNumber ||
1254  {
1255  *recheck = true;
1256 
1257  if (nkeys > 0)
1258  {
1259  Assert(extra_data && extra_data[0]);
1260  res = execute_jsp_gin_node((JsonPathGinNode *) extra_data[0], check,
1261  false) != GIN_FALSE;
1262  }
1263  }
1264  else
1265  elog(ERROR, "unrecognized strategy number: %d", strategy);
1266 
1268 }

References Assert(), elog, ERROR, execute_jsp_gin_node(), GIN_FALSE, i, JsonbContainsStrategyNumber, JsonbJsonpathExistsStrategyNumber, JsonbJsonpathPredicateStrategyNumber, PG_GETARG_INT32, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_BOOL, and res.

◆ gin_extract_jsonb()

Datum gin_extract_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 229 of file jsonb_gin.c.

230 {
231  Jsonb *jb = (Jsonb *) PG_GETARG_JSONB_P(0);
232  int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
233  int total = JB_ROOT_COUNT(jb);
234  JsonbIterator *it;
235  JsonbValue v;
237  GinEntries entries;
238 
239  /* If the root level is empty, we certainly have no keys */
240  if (total == 0)
241  {
242  *nentries = 0;
243  PG_RETURN_POINTER(NULL);
244  }
245 
246  /* Otherwise, use 2 * root count as initial estimate of result size */
247  init_gin_entries(&entries, 2 * total);
248 
249  it = JsonbIteratorInit(&jb->root);
250 
251  while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
252  {
253  switch (r)
254  {
255  case WJB_KEY:
256  add_gin_entry(&entries, make_scalar_key(&v, true));
257  break;
258  case WJB_ELEM:
259  /* Pretend string array elements are keys, see jsonb.h */
260  add_gin_entry(&entries, make_scalar_key(&v, v.type == jbvString));
261  break;
262  case WJB_VALUE:
263  add_gin_entry(&entries, make_scalar_key(&v, false));
264  break;
265  default:
266  /* we can ignore structural items */
267  break;
268  }
269  }
270 
271  *nentries = entries.count;
272 
273  PG_RETURN_POINTER(entries.buf);
274 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:74
JsonbIteratorToken
Definition: jsonb.h:21
@ WJB_KEY
Definition: jsonb.h:23
@ WJB_DONE
Definition: jsonb.h:22
@ WJB_VALUE
Definition: jsonb.h:24
@ WJB_ELEM
Definition: jsonb.h:25
#define JB_ROOT_COUNT(jbp_)
Definition: jsonb.h:227
static Datum make_scalar_key(const JsonbValue *scalarVal, bool is_key)
Definition: jsonb_gin.c:1363
static void init_gin_entries(GinEntries *entries, int preallocated)
Definition: jsonb_gin.c:163
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition: jsonb_util.c:819
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:855
Definition: jsonb.h:221
JsonbContainer root
Definition: jsonb.h:223

References add_gin_entry(), GinEntries::buf, GinEntries::count, init_gin_entries(), JB_ROOT_COUNT, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), make_scalar_key(), PG_GETARG_JSONB_P, PG_GETARG_POINTER, PG_RETURN_POINTER, Jsonb::root, JsonbValue::type, WJB_DONE, WJB_ELEM, WJB_KEY, and WJB_VALUE.

Referenced by gin_extract_jsonb_query().

◆ gin_extract_jsonb_path()

Datum gin_extract_jsonb_path ( PG_FUNCTION_ARGS  )

Definition at line 1089 of file jsonb_gin.c.

1090 {
1091  Jsonb *jb = PG_GETARG_JSONB_P(0);
1092  int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
1093  int total = JB_ROOT_COUNT(jb);
1094  JsonbIterator *it;
1095  JsonbValue v;
1097  PathHashStack tail;
1098  PathHashStack *stack;
1099  GinEntries entries;
1100 
1101  /* If the root level is empty, we certainly have no keys */
1102  if (total == 0)
1103  {
1104  *nentries = 0;
1105  PG_RETURN_POINTER(NULL);
1106  }
1107 
1108  /* Otherwise, use 2 * root count as initial estimate of result size */
1109  init_gin_entries(&entries, 2 * total);
1110 
1111  /* We keep a stack of partial hashes corresponding to parent key levels */
1112  tail.parent = NULL;
1113  tail.hash = 0;
1114  stack = &tail;
1115 
1116  it = JsonbIteratorInit(&jb->root);
1117 
1118  while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1119  {
1120  PathHashStack *parent;
1121 
1122  switch (r)
1123  {
1124  case WJB_BEGIN_ARRAY:
1125  case WJB_BEGIN_OBJECT:
1126  /* Push a stack level for this object */
1127  parent = stack;
1128  stack = (PathHashStack *) palloc(sizeof(PathHashStack));
1129 
1130  /*
1131  * We pass forward hashes from outer nesting levels so that
1132  * the hashes for nested values will include outer keys as
1133  * well as their own keys.
1134  *
1135  * Nesting an array within another array will not alter
1136  * innermost scalar element hash values, but that seems
1137  * inconsequential.
1138  */
1139  stack->hash = parent->hash;
1140  stack->parent = parent;
1141  break;
1142  case WJB_KEY:
1143  /* mix this key into the current outer hash */
1144  JsonbHashScalarValue(&v, &stack->hash);
1145  /* hash is now ready to incorporate the value */
1146  break;
1147  case WJB_ELEM:
1148  case WJB_VALUE:
1149  /* mix the element or value's hash into the prepared hash */
1150  JsonbHashScalarValue(&v, &stack->hash);
1151  /* and emit an index entry */
1152  add_gin_entry(&entries, UInt32GetDatum(stack->hash));
1153  /* reset hash for next key, value, or sub-object */
1154  stack->hash = stack->parent->hash;
1155  break;
1156  case WJB_END_ARRAY:
1157  case WJB_END_OBJECT:
1158  /* Pop the stack */
1159  parent = stack->parent;
1160  pfree(stack);
1161  stack = parent;
1162  /* reset hash for next key, value, or sub-object */
1163  if (stack->parent)
1164  stack->hash = stack->parent->hash;
1165  else
1166  stack->hash = 0;
1167  break;
1168  default:
1169  elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
1170  }
1171  }
1172 
1173  *nentries = entries.count;
1174 
1175  PG_RETURN_POINTER(entries.buf);
1176 }
@ WJB_END_ARRAY
Definition: jsonb.h:27
@ WJB_END_OBJECT
Definition: jsonb.h:29
@ WJB_BEGIN_OBJECT
Definition: jsonb.h:28
@ WJB_BEGIN_ARRAY
Definition: jsonb.h:26
void JsonbHashScalarValue(const JsonbValue *scalarVal, uint32 *hash)
Definition: jsonb_util.c:1318
void pfree(void *pointer)
Definition: mcxt.c:1175
#define UInt32GetDatum(X)
Definition: postgres.h:537
uint32 hash
Definition: jsonb_gin.c:75
struct PathHashStack * parent
Definition: jsonb_gin.c:76

References add_gin_entry(), GinEntries::buf, GinEntries::count, elog, ERROR, PathHashStack::hash, init_gin_entries(), JB_ROOT_COUNT, JsonbHashScalarValue(), JsonbIteratorInit(), JsonbIteratorNext(), palloc(), PathHashStack::parent, pfree(), PG_GETARG_JSONB_P, PG_GETARG_POINTER, PG_RETURN_POINTER, Jsonb::root, UInt32GetDatum, WJB_BEGIN_ARRAY, WJB_BEGIN_OBJECT, WJB_DONE, WJB_ELEM, WJB_END_ARRAY, WJB_END_OBJECT, WJB_KEY, and WJB_VALUE.

Referenced by gin_extract_jsonb_query_path().

◆ gin_extract_jsonb_query()

Datum gin_extract_jsonb_query ( PG_FUNCTION_ARGS  )

Definition at line 848 of file jsonb_gin.c.

849 {
850  int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
851  StrategyNumber strategy = PG_GETARG_UINT16(2);
852  int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
853  Datum *entries;
854 
855  if (strategy == JsonbContainsStrategyNumber)
856  {
857  /* Query is a jsonb, so just apply gin_extract_jsonb... */
858  entries = (Datum *)
860  PG_GETARG_DATUM(0),
861  PointerGetDatum(nentries)));
862  /* ...although "contains {}" requires a full index scan */
863  if (*nentries == 0)
864  *searchMode = GIN_SEARCH_MODE_ALL;
865  }
866  else if (strategy == JsonbExistsStrategyNumber)
867  {
868  /* Query is a text string, which we treat as a key */
869  text *query = PG_GETARG_TEXT_PP(0);
870 
871  *nentries = 1;
872  entries = (Datum *) palloc(sizeof(Datum));
873  entries[0] = make_text_key(JGINFLAG_KEY,
874  VARDATA_ANY(query),
875  VARSIZE_ANY_EXHDR(query));
876  }
877  else if (strategy == JsonbExistsAnyStrategyNumber ||
878  strategy == JsonbExistsAllStrategyNumber)
879  {
880  /* Query is a text array; each element is treated as a key */
881  ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
882  Datum *key_datums;
883  bool *key_nulls;
884  int key_count;
885  int i,
886  j;
887 
888  deconstruct_array_builtin(query, TEXTOID, &key_datums, &key_nulls, &key_count);
889 
890  entries = (Datum *) palloc(sizeof(Datum) * key_count);
891 
892  for (i = 0, j = 0; i < key_count; i++)
893  {
894  /* Nulls in the array are ignored */
895  if (key_nulls[i])
896  continue;
897  entries[j++] = make_text_key(JGINFLAG_KEY,
898  VARDATA(key_datums[i]),
899  VARSIZE(key_datums[i]) - VARHDRSZ);
900  }
901 
902  *nentries = j;
903  /* ExistsAll with no keys should match everything */
904  if (j == 0 && strategy == JsonbExistsAllStrategyNumber)
905  *searchMode = GIN_SEARCH_MODE_ALL;
906  }
907  else if (strategy == JsonbJsonpathPredicateStrategyNumber ||
909  {
911  Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4);
912 
913  entries = extract_jsp_query(jp, strategy, false, nentries, extra_data);
914 
915  if (!entries)
916  *searchMode = GIN_SEARCH_MODE_ALL;
917  }
918  else
919  {
920  elog(ERROR, "unrecognized strategy number: %d", strategy);
921  entries = NULL; /* keep compiler quiet */
922  }
923 
924  PG_RETURN_POINTER(entries);
925 }
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3643
#define VARHDRSZ
Definition: c.h:638
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:633
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define GIN_SEARCH_MODE_ALL
Definition: gin.h:36
int j
Definition: isn.c:74
#define JGINFLAG_KEY
Definition: jsonb.h:62
static Datum * extract_jsp_query(JsonPath *jp, StrategyNumber strat, bool pathOps, int32 *nentries, Pointer **extra_data)
Definition: jsonb_gin.c:748
static Datum make_text_key(char flag, const char *str, int len)
Definition: jsonb_gin.c:1325
Datum gin_extract_jsonb(PG_FUNCTION_ARGS)
Definition: jsonb_gin.c:229
#define PG_GETARG_JSONPATH_P(x)
Definition: jsonpath.h:37
#define DatumGetPointer(X)
Definition: postgres.h:593
#define VARDATA(PTR)
Definition: postgres.h:315
#define VARSIZE(PTR)
Definition: postgres.h:316
#define PointerGetDatum(X)
Definition: postgres.h:600

References DatumGetPointer, deconstruct_array_builtin(), DirectFunctionCall2, elog, ERROR, extract_jsp_query(), gin_extract_jsonb(), GIN_SEARCH_MODE_ALL, i, j, JGINFLAG_KEY, JsonbContainsStrategyNumber, JsonbExistsAllStrategyNumber, JsonbExistsAnyStrategyNumber, JsonbExistsStrategyNumber, JsonbJsonpathExistsStrategyNumber, JsonbJsonpathPredicateStrategyNumber, make_text_key(), palloc(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_GETARG_JSONPATH_P, PG_GETARG_POINTER, PG_GETARG_TEXT_PP, PG_GETARG_UINT16, PG_RETURN_POINTER, PointerGetDatum, VARDATA, VARDATA_ANY, VARHDRSZ, VARSIZE, and VARSIZE_ANY_EXHDR.

◆ gin_extract_jsonb_query_path()

Datum gin_extract_jsonb_query_path ( PG_FUNCTION_ARGS  )

Definition at line 1179 of file jsonb_gin.c.

1180 {
1181  int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
1182  StrategyNumber strategy = PG_GETARG_UINT16(2);
1183  int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
1184  Datum *entries;
1185 
1186  if (strategy == JsonbContainsStrategyNumber)
1187  {
1188  /* Query is a jsonb, so just apply gin_extract_jsonb_path ... */
1189  entries = (Datum *)
1191  PG_GETARG_DATUM(0),
1192  PointerGetDatum(nentries)));
1193 
1194  /* ... although "contains {}" requires a full index scan */
1195  if (*nentries == 0)
1196  *searchMode = GIN_SEARCH_MODE_ALL;
1197  }
1198  else if (strategy == JsonbJsonpathPredicateStrategyNumber ||
1200  {
1201  JsonPath *jp = PG_GETARG_JSONPATH_P(0);
1202  Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4);
1203 
1204  entries = extract_jsp_query(jp, strategy, true, nentries, extra_data);
1205 
1206  if (!entries)
1207  *searchMode = GIN_SEARCH_MODE_ALL;
1208  }
1209  else
1210  {
1211  elog(ERROR, "unrecognized strategy number: %d", strategy);
1212  entries = NULL;
1213  }
1214 
1215  PG_RETURN_POINTER(entries);
1216 }
Datum gin_extract_jsonb_path(PG_FUNCTION_ARGS)
Definition: jsonb_gin.c:1089

References DatumGetPointer, DirectFunctionCall2, elog, ERROR, extract_jsp_query(), gin_extract_jsonb_path(), GIN_SEARCH_MODE_ALL, JsonbContainsStrategyNumber, JsonbJsonpathExistsStrategyNumber, JsonbJsonpathPredicateStrategyNumber, PG_GETARG_DATUM, PG_GETARG_JSONPATH_P, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_POINTER, and PointerGetDatum.

◆ gin_triconsistent_jsonb()

Datum gin_triconsistent_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 1012 of file jsonb_gin.c.

1013 {
1015  StrategyNumber strategy = PG_GETARG_UINT16(1);
1016 
1017  /* Jsonb *query = PG_GETARG_JSONB_P(2); */
1018  int32 nkeys = PG_GETARG_INT32(3);
1019  Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
1021  int32 i;
1022 
1023  /*
1024  * Note that we never return GIN_TRUE, only GIN_MAYBE or GIN_FALSE; this
1025  * corresponds to always forcing recheck in the regular consistent
1026  * function, for the reasons listed there.
1027  */
1028  if (strategy == JsonbContainsStrategyNumber ||
1029  strategy == JsonbExistsAllStrategyNumber)
1030  {
1031  /* All extracted keys must be present */
1032  for (i = 0; i < nkeys; i++)
1033  {
1034  if (check[i] == GIN_FALSE)
1035  {
1036  res = GIN_FALSE;
1037  break;
1038  }
1039  }
1040  }
1041  else if (strategy == JsonbExistsStrategyNumber ||
1042  strategy == JsonbExistsAnyStrategyNumber)
1043  {
1044  /* At least one extracted key must be present */
1045  res = GIN_FALSE;
1046  for (i = 0; i < nkeys; i++)
1047  {
1048  if (check[i] == GIN_TRUE ||
1049  check[i] == GIN_MAYBE)
1050  {
1051  res = GIN_MAYBE;
1052  break;
1053  }
1054  }
1055  }
1056  else if (strategy == JsonbJsonpathPredicateStrategyNumber ||
1058  {
1059  if (nkeys > 0)
1060  {
1061  Assert(extra_data && extra_data[0]);
1062  res = execute_jsp_gin_node((JsonPathGinNode *) extra_data[0], check,
1063  true);
1064 
1065  /* Should always recheck the result */
1066  if (res == GIN_TRUE)
1067  res = GIN_MAYBE;
1068  }
1069  }
1070  else
1071  elog(ERROR, "unrecognized strategy number: %d", strategy);
1072 
1074 }
#define PG_RETURN_GIN_TERNARY_VALUE(x)
Definition: gin.h:66

References Assert(), elog, ERROR, execute_jsp_gin_node(), GIN_FALSE, GIN_MAYBE, GIN_TRUE, i, JsonbContainsStrategyNumber, JsonbExistsAllStrategyNumber, JsonbExistsAnyStrategyNumber, JsonbExistsStrategyNumber, JsonbJsonpathExistsStrategyNumber, JsonbJsonpathPredicateStrategyNumber, PG_GETARG_INT32, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_GIN_TERNARY_VALUE, and res.

◆ gin_triconsistent_jsonb_path()

Datum gin_triconsistent_jsonb_path ( PG_FUNCTION_ARGS  )

Definition at line 1271 of file jsonb_gin.c.

1272 {
1274  StrategyNumber strategy = PG_GETARG_UINT16(1);
1275 
1276  /* Jsonb *query = PG_GETARG_JSONB_P(2); */
1277  int32 nkeys = PG_GETARG_INT32(3);
1278  Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
1280  int32 i;
1281 
1282  if (strategy == JsonbContainsStrategyNumber)
1283  {
1284  /*
1285  * Note that we never return GIN_TRUE, only GIN_MAYBE or GIN_FALSE;
1286  * this corresponds to always forcing recheck in the regular
1287  * consistent function, for the reasons listed there.
1288  */
1289  for (i = 0; i < nkeys; i++)
1290  {
1291  if (check[i] == GIN_FALSE)
1292  {
1293  res = GIN_FALSE;
1294  break;
1295  }
1296  }
1297  }
1298  else if (strategy == JsonbJsonpathPredicateStrategyNumber ||
1300  {
1301  if (nkeys > 0)
1302  {
1303  Assert(extra_data && extra_data[0]);
1304  res = execute_jsp_gin_node((JsonPathGinNode *) extra_data[0], check,
1305  true);
1306 
1307  /* Should always recheck the result */
1308  if (res == GIN_TRUE)
1309  res = GIN_MAYBE;
1310  }
1311  }
1312  else
1313  elog(ERROR, "unrecognized strategy number: %d", strategy);
1314 
1316 }

References Assert(), elog, ERROR, execute_jsp_gin_node(), GIN_FALSE, GIN_MAYBE, GIN_TRUE, i, JsonbContainsStrategyNumber, JsonbJsonpathExistsStrategyNumber, JsonbJsonpathPredicateStrategyNumber, PG_GETARG_INT32, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_GIN_TERNARY_VALUE, and res.

◆ init_gin_entries()

static void init_gin_entries ( GinEntries entries,
int  preallocated 
)
static

Definition at line 163 of file jsonb_gin.c.

164 {
165  entries->allocated = preallocated;
166  entries->buf = preallocated ? palloc(sizeof(Datum) * preallocated) : NULL;
167  entries->count = 0;
168 }

References GinEntries::allocated, GinEntries::buf, GinEntries::count, and palloc().

Referenced by gin_extract_jsonb(), and gin_extract_jsonb_path().

◆ jsonb_ops__add_path_item()

static bool jsonb_ops__add_path_item ( JsonPathGinPath path,
JsonPathItem jsp 
)
static

Definition at line 278 of file jsonb_gin.c.

279 {
280  JsonPathGinPathItem *pentry;
281  Datum keyName;
282 
283  switch (jsp->type)
284  {
285  case jpiRoot:
286  path->items = NULL; /* reset path */
287  return true;
288 
289  case jpiKey:
290  {
291  int len;
292  char *key = jspGetString(jsp, &len);
293 
294  keyName = make_text_key(JGINFLAG_KEY, key, len);
295  break;
296  }
297 
298  case jpiAny:
299  case jpiAnyKey:
300  case jpiAnyArray:
301  case jpiIndexArray:
302  keyName = PointerGetDatum(NULL);
303  break;
304 
305  default:
306  /* other path items like item methods are not supported */
307  return false;
308  }
309 
310  pentry = palloc(sizeof(*pentry));
311 
312  pentry->type = jsp->type;
313  pentry->keyName = keyName;
314  pentry->parent = path->items;
315 
316  path->items = pentry;
317 
318  return true;
319 }
char * jspGetString(JsonPathItem *v, int32 *len)
Definition: jsonpath.c:1056
@ jpiIndexArray
Definition: jsonpath.h:71
@ jpiAny
Definition: jsonpath.h:72
@ jpiAnyArray
Definition: jsonpath.h:69
@ jpiRoot
Definition: jsonpath.h:75
@ jpiKey
Definition: jsonpath.h:73
@ jpiAnyKey
Definition: jsonpath.h:70
const void size_t len
JsonPathItemType type
Definition: jsonb_gin.c:121
struct JsonPathGinPathItem * parent
Definition: jsonb_gin.c:119
JsonPathGinPathItem * items
Definition: jsonb_gin.c:127

References JsonPathGinPath::items, JGINFLAG_KEY, jpiAny, jpiAnyArray, jpiAnyKey, jpiIndexArray, jpiKey, jpiRoot, jspGetString(), sort-test::key, JsonPathGinPathItem::keyName, len, make_text_key(), palloc(), JsonPathGinPathItem::parent, PointerGetDatum, JsonPathGinPathItem::type, and JsonPathItem::type.

Referenced by extract_jsp_query().

◆ jsonb_ops__extract_nodes()

static List* jsonb_ops__extract_nodes ( JsonPathGinContext cxt,
JsonPathGinPath  path,
JsonbValue scalar,
List nodes 
)
static

Definition at line 408 of file jsonb_gin.c.

410 {
411  JsonPathGinPathItem *pentry;
412 
413  if (scalar)
414  {
415  JsonPathGinNode *node;
416 
417  /*
418  * Append path entry nodes only if scalar is provided. See header
419  * comment for details.
420  */
421  for (pentry = path.items; pentry; pentry = pentry->parent)
422  {
423  if (pentry->type == jpiKey) /* only keys are indexed */
424  nodes = lappend(nodes, make_jsp_entry_node(pentry->keyName));
425  }
426 
427  /* Append scalar node for equality queries. */
428  if (scalar->type == jbvString)
429  {
430  JsonPathGinPathItem *last = path.items;
431  GinTernaryValue key_entry;
432 
433  /*
434  * Assuming that jsonb_ops interprets string array elements as
435  * keys, we may extract key or non-key entry or even both. In the
436  * latter case we create OR-node. It is possible in lax mode
437  * where arrays are automatically unwrapped, or in strict mode for
438  * jpiAny items.
439  */
440 
441  if (cxt->lax)
442  key_entry = GIN_MAYBE;
443  else if (!last) /* root ($) */
444  key_entry = GIN_FALSE;
445  else if (last->type == jpiAnyArray || last->type == jpiIndexArray)
446  key_entry = GIN_TRUE;
447  else if (last->type == jpiAny)
448  key_entry = GIN_MAYBE;
449  else
450  key_entry = GIN_FALSE;
451 
452  if (key_entry == GIN_MAYBE)
453  {
454  JsonPathGinNode *n1 = make_jsp_entry_node_scalar(scalar, true);
455  JsonPathGinNode *n2 = make_jsp_entry_node_scalar(scalar, false);
456 
457  node = make_jsp_expr_node_binary(JSP_GIN_OR, n1, n2);
458  }
459  else
460  {
461  node = make_jsp_entry_node_scalar(scalar,
462  key_entry == GIN_TRUE);
463  }
464  }
465  else
466  {
467  node = make_jsp_entry_node_scalar(scalar, false);
468  }
469 
470  nodes = lappend(nodes, node);
471  }
472 
473  return nodes;
474 }
static JsonPathGinNode * make_jsp_entry_node_scalar(JsonbValue *scalar, bool iskey)
Definition: jsonb_gin.c:364
static JsonPathGinNode * make_jsp_entry_node(Datum entry)
Definition: jsonb_gin.c:353

References GIN_FALSE, GIN_MAYBE, GIN_TRUE, JsonPathGinPath::items, jbvString, jpiAny, jpiAnyArray, jpiIndexArray, jpiKey, JSP_GIN_OR, JsonPathGinPathItem::keyName, lappend(), JsonPathGinContext::lax, make_jsp_entry_node(), make_jsp_entry_node_scalar(), make_jsp_expr_node_binary(), JsonPathGinPathItem::parent, JsonPathGinPathItem::type, and JsonbValue::type.

Referenced by extract_jsp_query().

◆ jsonb_path_ops__add_path_item()

static bool jsonb_path_ops__add_path_item ( JsonPathGinPath path,
JsonPathItem jsp 
)
static

Definition at line 323 of file jsonb_gin.c.

324 {
325  switch (jsp->type)
326  {
327  case jpiRoot:
328  path->hash = 0; /* reset path hash */
329  return true;
330 
331  case jpiKey:
332  {
333  JsonbValue jbv;
334 
335  jbv.type = jbvString;
336  jbv.val.string.val = jspGetString(jsp, &jbv.val.string.len);
337 
338  JsonbHashScalarValue(&jbv, &path->hash);
339  return true;
340  }
341 
342  case jpiIndexArray:
343  case jpiAnyArray:
344  return true; /* path hash is unchanged */
345 
346  default:
347  /* other items (wildcard paths, item methods) are not supported */
348  return false;
349  }
350 }

References JsonPathGinPath::hash, jbvString, jpiAnyArray, jpiIndexArray, jpiKey, jpiRoot, JsonbHashScalarValue(), jspGetString(), JsonbValue::type, JsonPathItem::type, and JsonbValue::val.

Referenced by extract_jsp_query().

◆ jsonb_path_ops__extract_nodes()

static List* jsonb_path_ops__extract_nodes ( JsonPathGinContext cxt,
JsonPathGinPath  path,
JsonbValue scalar,
List nodes 
)
static

Definition at line 478 of file jsonb_gin.c.

480 {
481  if (scalar)
482  {
483  /* append path hash node for equality queries */
484  uint32 hash = path.hash;
485 
486  JsonbHashScalarValue(scalar, &hash);
487 
488  return lappend(nodes,
490  }
491  else
492  {
493  /* jsonb_path_ops doesn't support EXISTS queries => nothing to append */
494  return nodes;
495  }
496 }
unsigned int uint32
Definition: c.h:452
static unsigned hash(unsigned *uv, int n)
Definition: rege_dfa.c:715

References hash(), JsonPathGinPath::hash, JsonbHashScalarValue(), lappend(), make_jsp_entry_node(), and UInt32GetDatum.

Referenced by extract_jsp_query().

◆ make_jsp_entry_node()

static JsonPathGinNode* make_jsp_entry_node ( Datum  entry)
static

Definition at line 353 of file jsonb_gin.c.

354 {
356 
357  node->type = JSP_GIN_ENTRY;
358  node->val.entryDatum = entry;
359 
360  return node;
361 }
#define offsetof(type, field)
Definition: c.h:738

References generate_unaccent_rules::args, JsonPathGinNode::entryDatum, JSP_GIN_ENTRY, offsetof, palloc(), JsonPathGinNode::type, and JsonPathGinNode::val.

Referenced by jsonb_ops__extract_nodes(), jsonb_path_ops__extract_nodes(), and make_jsp_entry_node_scalar().

◆ make_jsp_entry_node_scalar()

static JsonPathGinNode* make_jsp_entry_node_scalar ( JsonbValue scalar,
bool  iskey 
)
static

Definition at line 364 of file jsonb_gin.c.

365 {
366  return make_jsp_entry_node(make_scalar_key(scalar, iskey));
367 }

References make_jsp_entry_node(), and make_scalar_key().

Referenced by jsonb_ops__extract_nodes().

◆ make_jsp_expr_node()

static JsonPathGinNode* make_jsp_expr_node ( JsonPathGinNodeType  type,
int  nargs 
)
static

Definition at line 370 of file jsonb_gin.c.

371 {
373  sizeof(node->args[0]) * nargs);
374 
375  node->type = type;
376  node->val.nargs = nargs;
377 
378  return node;
379 }

References generate_unaccent_rules::args, JsonPathGinNode::args, JsonPathGinNode::nargs, offsetof, palloc(), generate_unaccent_rules::type, JsonPathGinNode::type, and JsonPathGinNode::val.

Referenced by make_jsp_expr_node_args(), and make_jsp_expr_node_binary().

◆ make_jsp_expr_node_args()

static JsonPathGinNode* make_jsp_expr_node_args ( JsonPathGinNodeType  type,
List args 
)
static

Definition at line 382 of file jsonb_gin.c.

383 {
385  ListCell *lc;
386  int i = 0;
387 
388  foreach(lc, args)
389  node->args[i++] = lfirst(lc);
390 
391  return node;
392 }
static JsonPathGinNode * make_jsp_expr_node(JsonPathGinNodeType type, int nargs)
Definition: jsonb_gin.c:370
#define lfirst(lc)
Definition: pg_list.h:169

References generate_unaccent_rules::args, JsonPathGinNode::args, i, lfirst, list_length(), make_jsp_expr_node(), and generate_unaccent_rules::type.

Referenced by extract_jsp_path_expr().

◆ make_jsp_expr_node_binary()

static JsonPathGinNode* make_jsp_expr_node_binary ( JsonPathGinNodeType  type,
JsonPathGinNode arg1,
JsonPathGinNode arg2 
)
static

Definition at line 395 of file jsonb_gin.c.

397 {
399 
400  node->args[0] = arg1;
401  node->args[1] = arg2;
402 
403  return node;
404 }

References JsonPathGinNode::args, make_jsp_expr_node(), and generate_unaccent_rules::type.

Referenced by extract_jsp_bool_expr(), and jsonb_ops__extract_nodes().

◆ make_scalar_key()

static Datum make_scalar_key ( const JsonbValue scalarVal,
bool  is_key 
)
static

Definition at line 1363 of file jsonb_gin.c.

1364 {
1365  Datum item;
1366  char *cstr;
1367 
1368  switch (scalarVal->type)
1369  {
1370  case jbvNull:
1371  Assert(!is_key);
1372  item = make_text_key(JGINFLAG_NULL, "", 0);
1373  break;
1374  case jbvBool:
1375  Assert(!is_key);
1377  scalarVal->val.boolean ? "t" : "f", 1);
1378  break;
1379  case jbvNumeric:
1380  Assert(!is_key);
1381 
1382  /*
1383  * A normalized textual representation, free of trailing zeroes,
1384  * is required so that numerically equal values will produce equal
1385  * strings.
1386  *
1387  * It isn't ideal that numerics are stored in a relatively bulky
1388  * textual format. However, it's a notationally convenient way of
1389  * storing a "union" type in the GIN B-Tree, and indexing Jsonb
1390  * strings takes precedence.
1391  */
1392  cstr = numeric_normalize(scalarVal->val.numeric);
1393  item = make_text_key(JGINFLAG_NUM, cstr, strlen(cstr));
1394  pfree(cstr);
1395  break;
1396  case jbvString:
1397  item = make_text_key(is_key ? JGINFLAG_KEY : JGINFLAG_STR,
1398  scalarVal->val.string.val,
1399  scalarVal->val.string.len);
1400  break;
1401  default:
1402  elog(ERROR, "unrecognized jsonb scalar type: %d", scalarVal->type);
1403  item = 0; /* keep compiler quiet */
1404  break;
1405  }
1406 
1407  return item;
1408 }
char * numeric_normalize(Numeric num)
Definition: numeric.c:945
#define JGINFLAG_STR
Definition: jsonb.h:66
#define JGINFLAG_NULL
Definition: jsonb.h:63
#define JGINFLAG_BOOL
Definition: jsonb.h:64
#define JGINFLAG_NUM
Definition: jsonb.h:65

References Assert(), elog, ERROR, jbvBool, jbvNull, jbvNumeric, jbvString, JGINFLAG_BOOL, JGINFLAG_KEY, JGINFLAG_NULL, JGINFLAG_NUM, JGINFLAG_STR, make_text_key(), numeric_normalize(), pfree(), JsonbValue::type, and JsonbValue::val.

Referenced by gin_extract_jsonb(), and make_jsp_entry_node_scalar().

◆ make_text_key()

static Datum make_text_key ( char  flag,
const char *  str,
int  len 
)
static

Definition at line 1325 of file jsonb_gin.c.

1326 {
1327  text *item;
1328  char hashbuf[10];
1329 
1330  if (len > JGIN_MAXLENGTH)
1331  {
1332  uint32 hashval;
1333 
1334  hashval = DatumGetUInt32(hash_any((const unsigned char *) str, len));
1335  snprintf(hashbuf, sizeof(hashbuf), "%08x", hashval);
1336  str = hashbuf;
1337  len = 8;
1338  flag |= JGINFLAG_HASHED;
1339  }
1340 
1341  /*
1342  * Now build the text Datum. For simplicity we build a 4-byte-header
1343  * varlena text Datum here, but we expect it will get converted to short
1344  * header format when stored in the index.
1345  */
1346  item = (text *) palloc(VARHDRSZ + len + 1);
1347  SET_VARSIZE(item, VARHDRSZ + len + 1);
1348 
1349  *VARDATA(item) = flag;
1350 
1351  memcpy(VARDATA(item) + 1, str, len);
1352 
1353  return PointerGetDatum(item);
1354 }
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31
#define JGINFLAG_HASHED
Definition: jsonb.h:67
#define JGIN_MAXLENGTH
Definition: jsonb.h:68
#define snprintf
Definition: port.h:225
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:342
#define DatumGetUInt32(X)
Definition: postgres.h:530
char * flag(int b)
Definition: test-ctype.c:33

References DatumGetUInt32, flag(), hash_any(), JGIN_MAXLENGTH, JGINFLAG_HASHED, len, palloc(), PointerGetDatum, SET_VARSIZE, snprintf, generate_unaccent_rules::str, VARDATA, and VARHDRSZ.

Referenced by gin_extract_jsonb_query(), jsonb_ops__add_path_item(), and make_scalar_key().