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:1456
void * palloc(Size size)
Definition: mcxt.c:1210
uintptr_t Datum
Definition: postgres.h:64
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:3454
union JsonPathGinNode::@21 val
JsonPathGinNodeType type
Definition: jsonb_gin.c:99
JsonPathGinNode * args[FLEXIBLE_ARRAY_MEMBER]
Definition: jsonb_gin.c:108
Datum entryDatum
Definition: jsonb_gin.c:105

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:39
#define GIN_FALSE
Definition: gin.h:63
char GinTernaryValue
Definition: gin.h:58
#define GIN_MAYBE
Definition: gin.h:65
#define GIN_TRUE
Definition: gin.h:64
static GinTernaryValue execute_jsp_gin_node(JsonPathGinNode *node, void *check, bool ternary)
Definition: jsonb_gin.c:799
Definition: type.h:95

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:230
@ jbvBool
Definition: jsonb.h:231
@ jbvNull
Definition: jsonb.h:228
@ jbvString
Definition: jsonb.h:229
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:1028
void jspGetArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:959
void jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1049
#define jspIsScalar(type)
Definition: jsonpath.h:48
@ jpiString
Definition: jsonpath.h:56
@ jpiBool
Definition: jsonpath.h:58
@ jpiExists
Definition: jsonpath.h:85
@ jpiNotEqual
Definition: jsonpath.h:64
@ jpiNot
Definition: jsonpath.h:61
@ jpiAnd
Definition: jsonpath.h:59
@ jpiOr
Definition: jsonpath.h:60
@ jpiNull
Definition: jsonpath.h:55
@ jpiEqual
Definition: jsonpath.h:63
@ jpiNumeric
Definition: jsonpath.h:57
struct NumericData * Numeric
Definition: numeric.h:53
void * arg
struct JsonPathItem::@126::@130 value
union JsonPathItem::@126 content
JsonPathItemType type
Definition: jsonpath.h:117
enum jbvType type
Definition: jsonb.h:255
char * val
Definition: jsonb.h:264

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 (nodes == NIL)
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:152
#define NIL
Definition: pg_list.h:68
#define linitial(l)
Definition: pg_list.h:178
Definition: pg_list.h:54

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

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:973
@ jpiFilter
Definition: jsonpath.h:84
@ jpiCurrent
Definition: jsonpath.h:81
List * lappend(List *list, void *datum)
Definition: list.c:338
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:467
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:869
#define JSONPATH_LAX
Definition: jsonpath.h:29
void * palloc0(Size size)
Definition: mcxt.c:1241
uint32 header
Definition: jsonpath.h:24

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:478
#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
Definition: c.h:671
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid)
Definition: varlena.c:1536

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 929 of file jsonb_gin.c.

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

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

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:389
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:219
static Datum make_scalar_key(const JsonbValue *scalarVal, bool is_key)
Definition: jsonb_gin.c:1364
static void init_gin_entries(GinEntries *entries, int preallocated)
Definition: jsonb_gin.c:163
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition: jsonb_util.c:813
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:849
Definition: jsonb.h:213
JsonbContainer root
Definition: jsonb.h:215

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 1090 of file jsonb_gin.c.

1091 {
1092  Jsonb *jb = PG_GETARG_JSONB_P(0);
1093  int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
1094  int total = JB_ROOT_COUNT(jb);
1095  JsonbIterator *it;
1096  JsonbValue v;
1098  PathHashStack tail;
1099  PathHashStack *stack;
1100  GinEntries entries;
1101 
1102  /* If the root level is empty, we certainly have no keys */
1103  if (total == 0)
1104  {
1105  *nentries = 0;
1106  PG_RETURN_POINTER(NULL);
1107  }
1108 
1109  /* Otherwise, use 2 * root count as initial estimate of result size */
1110  init_gin_entries(&entries, 2 * total);
1111 
1112  /* We keep a stack of partial hashes corresponding to parent key levels */
1113  tail.parent = NULL;
1114  tail.hash = 0;
1115  stack = &tail;
1116 
1117  it = JsonbIteratorInit(&jb->root);
1118 
1119  while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1120  {
1121  PathHashStack *parent;
1122 
1123  switch (r)
1124  {
1125  case WJB_BEGIN_ARRAY:
1126  case WJB_BEGIN_OBJECT:
1127  /* Push a stack level for this object */
1128  parent = stack;
1129  stack = (PathHashStack *) palloc(sizeof(PathHashStack));
1130 
1131  /*
1132  * We pass forward hashes from outer nesting levels so that
1133  * the hashes for nested values will include outer keys as
1134  * well as their own keys.
1135  *
1136  * Nesting an array within another array will not alter
1137  * innermost scalar element hash values, but that seems
1138  * inconsequential.
1139  */
1140  stack->hash = parent->hash;
1141  stack->parent = parent;
1142  break;
1143  case WJB_KEY:
1144  /* mix this key into the current outer hash */
1145  JsonbHashScalarValue(&v, &stack->hash);
1146  /* hash is now ready to incorporate the value */
1147  break;
1148  case WJB_ELEM:
1149  case WJB_VALUE:
1150  /* mix the element or value's hash into the prepared hash */
1151  JsonbHashScalarValue(&v, &stack->hash);
1152  /* and emit an index entry */
1153  add_gin_entry(&entries, UInt32GetDatum(stack->hash));
1154  /* reset hash for next key, value, or sub-object */
1155  stack->hash = stack->parent->hash;
1156  break;
1157  case WJB_END_ARRAY:
1158  case WJB_END_OBJECT:
1159  /* Pop the stack */
1160  parent = stack->parent;
1161  pfree(stack);
1162  stack = parent;
1163  /* reset hash for next key, value, or sub-object */
1164  if (stack->parent)
1165  stack->hash = stack->parent->hash;
1166  else
1167  stack->hash = 0;
1168  break;
1169  default:
1170  elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
1171  }
1172  }
1173 
1174  *nentries = entries.count;
1175 
1176  PG_RETURN_POINTER(entries.buf);
1177 }
@ 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:1312
void pfree(void *pointer)
Definition: mcxt.c:1436
static Datum UInt32GetDatum(uint32 X)
Definition: postgres.h:232
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  /* We rely on the array elements not being toasted */
898  entries[j++] = make_text_key(JGINFLAG_KEY,
899  VARDATA_ANY(key_datums[i]),
900  VARSIZE_ANY_EXHDR(key_datums[i]));
901  }
902 
903  *nentries = j;
904  /* ExistsAll with no keys should match everything */
905  if (j == 0 && strategy == JsonbExistsAllStrategyNumber)
906  *searchMode = GIN_SEARCH_MODE_ALL;
907  }
908  else if (strategy == JsonbJsonpathPredicateStrategyNumber ||
910  {
912  Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4);
913 
914  entries = extract_jsp_query(jp, strategy, false, nentries, extra_data);
915 
916  if (!entries)
917  *searchMode = GIN_SEARCH_MODE_ALL;
918  }
919  else
920  {
921  elog(ERROR, "unrecognized strategy number: %d", strategy);
922  entries = NULL; /* keep compiler quiet */
923  }
924 
925  PG_RETURN_POINTER(entries);
926 }
#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:3668
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#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:1326
Datum gin_extract_jsonb(PG_FUNCTION_ARGS)
Definition: jsonb_gin.c:229
#define PG_GETARG_JSONPATH_P(x)
Definition: jsonpath.h:44
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312

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_ANY, and VARSIZE_ANY_EXHDR.

◆ gin_extract_jsonb_query_path()

Datum gin_extract_jsonb_query_path ( PG_FUNCTION_ARGS  )

Definition at line 1180 of file jsonb_gin.c.

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

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 1013 of file jsonb_gin.c.

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

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 1272 of file jsonb_gin.c.

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

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:1086
@ jpiIndexArray
Definition: jsonpath.h:78
@ jpiAny
Definition: jsonpath.h:79
@ jpiAnyArray
Definition: jsonpath.h:76
@ jpiRoot
Definition: jsonpath.h:82
@ jpiKey
Definition: jsonpath.h:80
@ jpiAnyKey
Definition: jsonpath.h:77
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:490
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

◆ 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 {
372  JsonPathGinNode *node = palloc(offsetof(JsonPathGinNode, args) +
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, 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:172

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 1364 of file jsonb_gin.c.

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

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

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().