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/fmgrprotos.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 131 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 94 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{
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_array(entries->buf,
182 Datum,
183 entries->allocated);
184 }
185 else
186 {
187 entries->allocated = 8;
188 entries->buf = palloc_array(Datum, entries->allocated);
189 }
190 }
191
192 entries->buf[entries->count++] = entry;
193
194 return id;
195}
#define repalloc_array(pointer, type, count)
Definition: fe_memutils.h:78
#define palloc_array(type, count)
Definition: fe_memutils.h:76
uint64_t Datum
Definition: postgres.h:70
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_array, and repalloc_array.

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

721{
723
724 switch (node->type)
725 {
726 case JSP_GIN_ENTRY:
727 /* replace datum with its index in the array */
728 node->val.entryIndex = add_gin_entry(entries, node->val.entryDatum);
729 break;
730
731 case JSP_GIN_OR:
732 case JSP_GIN_AND:
733 {
734 int i;
735
736 for (i = 0; i < node->val.nargs; i++)
737 emit_jsp_gin_entries(node->args[i], entries);
738
739 break;
740 }
741 }
742}
int i
Definition: isn.c:77
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:720
void check_stack_depth(void)
Definition: stack_depth.c:95
union JsonPathGinNode::@25 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(), emit_jsp_gin_entries(), JsonPathGinNode::entryDatum, JsonPathGinNode::entryIndex, i, JSP_GIN_AND, JSP_GIN_ENTRY, JSP_GIN_OR, JsonPathGinNode::nargs, JsonPathGinNode::type, and JsonPathGinNode::val.

Referenced by emit_jsp_gin_entries(), and extract_jsp_query().

◆ execute_jsp_gin_node()

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

Definition at line 800 of file jsonb_gin.c.

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

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

Referenced by execute_jsp_gin_node(), 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 584 of file jsonb_gin.c.

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

References arg, check_stack_depth(), JsonPathItem::content, JsonPathItem::data, JsonPathItem::datalen, elog, ERROR, extract_jsp_bool_expr(), 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(), type, JsonbValue::type, JsonPathItem::type, JsonbValue::val, and JsonPathItem::value.

Referenced by extract_jsp_bool_expr(), 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 565 of file jsonb_gin.c.

567{
568 /* extract a list of nodes to be AND-ed */
569 List *nodes = extract_jsp_path_expr_nodes(cxt, path, jsp, scalar);
570
571 if (nodes == NIL)
572 /* no nodes were extracted => full scan is needed for this path */
573 return NULL;
574
575 if (list_length(nodes) == 1)
576 return linitial(nodes); /* avoid extra AND-node */
577
578 /* construct AND-node for path with filters */
580}
static JsonPathGinNode * make_jsp_expr_node_args(JsonPathGinNodeType type, List *args)
Definition: jsonb_gin.c:383
static List * extract_jsp_path_expr_nodes(JsonPathGinContext *cxt, JsonPathGinPath path, JsonPathItem *jsp, JsonbValue *scalar)
Definition: jsonb_gin.c:505
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 505 of file jsonb_gin.c.

507{
509 List *nodes = NIL;
510
511 for (;;)
512 {
513 switch (jsp->type)
514 {
515 case jpiCurrent:
516 break;
517
518 case jpiFilter:
519 {
521 JsonPathGinNode *filter;
522
523 jspGetArg(jsp, &arg);
524
525 filter = extract_jsp_bool_expr(cxt, path, &arg, false);
526
527 if (filter)
528 nodes = lappend(nodes, filter);
529
530 break;
531 }
532
533 default:
534 if (!cxt->add_path_item(&path, jsp))
535
536 /*
537 * Path is not supported by the index opclass, return only
538 * the extracted filter nodes.
539 */
540 return nodes;
541 break;
542 }
543
544 if (!jspGetNext(jsp, &next))
545 break;
546
547 jsp = &next;
548 }
549
550 /*
551 * Append nodes from the path expression itself to the already extracted
552 * list of filter nodes.
553 */
554 return cxt->extract_nodes(cxt, path, scalar, nodes);
555}
static int32 next
Definition: blutils.c:224
bool jspGetNext(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1099
@ jpiFilter
Definition: jsonpath.h:93
@ jpiCurrent
Definition: jsonpath.h:90
List * lappend(List *list, void *datum)
Definition: list.c:339
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 749 of file jsonb_gin.c.

751{
754 JsonPathGinNode *node;
755 JsonPathGinPath path = {0};
756 GinEntries entries = {0};
757
758 cxt.lax = (jp->header & JSONPATH_LAX) != 0;
759
760 if (pathOps)
761 {
764 }
765 else
766 {
769 }
770
771 jspInit(&root, jp);
772
774 ? extract_jsp_path_expr(&cxt, path, &root, NULL)
775 : extract_jsp_bool_expr(&cxt, path, &root, false);
776
777 if (!node)
778 {
779 *nentries = 0;
780 return NULL;
781 }
782
783 emit_jsp_gin_entries(node, &entries);
784
785 *nentries = entries.count;
786 if (!*nentries)
787 return NULL;
788
789 *extra_data = palloc0_array(Pointer, entries.count);
790 **extra_data = (Pointer) node;
791
792 return entries.buf;
793}
void * Pointer
Definition: c.h:543
#define palloc0_array(type, count)
Definition: fe_memutils.h:77
return false
Definition: isn.c:135
#define JsonbJsonpathExistsStrategyNumber
Definition: jsonb.h:37
static List * jsonb_path_ops__extract_nodes(JsonPathGinContext *cxt, JsonPathGinPath path, JsonbValue *scalar, List *nodes)
Definition: jsonb_gin.c:479
static bool jsonb_ops__add_path_item(JsonPathGinPath *path, JsonPathItem *jsp)
Definition: jsonb_gin.c:279
static List * jsonb_ops__extract_nodes(JsonPathGinContext *cxt, JsonPathGinPath path, JsonbValue *scalar, List *nodes)
Definition: jsonb_gin.c:409
static bool jsonb_path_ops__add_path_item(JsonPathGinPath *path, JsonPathItem *jsp)
Definition: jsonb_gin.c:324
void jspInit(JsonPathItem *v, JsonPath *js)
Definition: jsonpath.c:980
#define JSONPATH_LAX
Definition: jsonpath.h:31
tree ctl root
Definition: radixtree.h:1857
uint32 header
Definition: jsonpath.h:26

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, palloc0_array, and root.

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

205{
206 text *arg1 = PG_GETARG_TEXT_PP(0);
207 text *arg2 = PG_GETARG_TEXT_PP(1);
208 int32 result;
209 char *a1p,
210 *a2p;
211 int len1,
212 len2;
213
214 a1p = VARDATA_ANY(arg1);
215 a2p = VARDATA_ANY(arg2);
216
217 len1 = VARSIZE_ANY_EXHDR(arg1);
218 len2 = VARSIZE_ANY_EXHDR(arg2);
219
220 /* Compare text as bttextcmp does, but always using C collation */
221 result = varstr_cmp(a1p, len1, a2p, len2, C_COLLATION_OID);
222
223 PG_FREE_IF_COPY(arg1, 0);
224 PG_FREE_IF_COPY(arg2, 1);
225
226 PG_RETURN_INT32(result);
227}
int32_t int32
Definition: c.h:548
#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:706
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition: varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition: varatt.h:486
int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid)
Definition: varlena.c:1308

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

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

◆ 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(extra_data[0], check, false) != GIN_FALSE;
1261 }
1262 }
1263 else
1264 elog(ERROR, "unrecognized strategy number: %d", strategy);
1265
1266 PG_RETURN_BOOL(res);
1267}

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

◆ gin_extract_jsonb()

Datum gin_extract_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 230 of file jsonb_gin.c.

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

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;
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}
#define palloc_object(type)
Definition: fe_memutils.h:74
@ 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:1443
void pfree(void *pointer)
Definition: mcxt.c:1594
static Datum UInt32GetDatum(uint32 X)
Definition: postgres.h:242
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_object, 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 849 of file jsonb_gin.c.

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

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_array, palloc_object, 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 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 {
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 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(extra_data[0], check, 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:92

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, and PG_RETURN_GIN_TERNARY_VALUE.

◆ gin_triconsistent_jsonb_path()

Datum gin_triconsistent_jsonb_path ( PG_FUNCTION_ARGS  )

Definition at line 1270 of file jsonb_gin.c.

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

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, and PG_RETURN_GIN_TERNARY_VALUE.

◆ 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_array(Datum, preallocated) : NULL;
167 entries->count = 0;
168}

References GinEntries::allocated, GinEntries::buf, GinEntries::count, and palloc_array.

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

280{
281 JsonPathGinPathItem *pentry;
282 Datum keyName;
283
284 switch (jsp->type)
285 {
286 case jpiRoot:
287 path->items = NULL; /* reset path */
288 return true;
289
290 case jpiKey:
291 {
292 int len;
293 char *key = jspGetString(jsp, &len);
294
295 keyName = make_text_key(JGINFLAG_KEY, key, len);
296 break;
297 }
298
299 case jpiAny:
300 case jpiAnyKey:
301 case jpiAnyArray:
302 case jpiIndexArray:
303 keyName = PointerGetDatum(NULL);
304 break;
305
306 default:
307 /* other path items like item methods are not supported */
308 return false;
309 }
310
312
313 pentry->type = jsp->type;
314 pentry->keyName = keyName;
315 pentry->parent = path->items;
316
317 path->items = pentry;
318
319 return true;
320}
char * jspGetString(JsonPathItem *v, int32 *len)
Definition: jsonpath.c:1226
@ jpiIndexArray
Definition: jsonpath.h:87
@ jpiAny
Definition: jsonpath.h:88
@ jpiAnyArray
Definition: jsonpath.h:85
@ jpiRoot
Definition: jsonpath.h:91
@ jpiKey
Definition: jsonpath.h:89
@ jpiAnyKey
Definition: jsonpath.h:86
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_object, 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 409 of file jsonb_gin.c.

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

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

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

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

481{
482 if (scalar)
483 {
484 /* append path hash node for equality queries */
485 uint32 hash = path.hash;
486
487 JsonbHashScalarValue(scalar, &hash);
488
489 return lappend(nodes,
491 }
492 else
493 {
494 /* jsonb_path_ops doesn't support EXISTS queries => nothing to append */
495 return nodes;
496 }
497}
uint32_t uint32
Definition: c.h:552
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 365 of file jsonb_gin.c.

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

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

372{
373 JsonPathGinNode *node = palloc(offsetof(JsonPathGinNode, args) +
374 sizeof(node->args[0]) * nargs);
375
376 node->type = type;
377 node->val.nargs = nargs;
378
379 return node;
380}

References generate_unaccent_rules::args, JsonPathGinNode::args, JsonPathGinNode::nargs, palloc(), 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 383 of file jsonb_gin.c.

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

References generate_unaccent_rules::args, JsonPathGinNode::args, i, lfirst, list_length(), make_jsp_expr_node(), and 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 396 of file jsonb_gin.c.

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

References JsonPathGinNode::args, make_jsp_expr_node(), and 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 1361 of file jsonb_gin.c.

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

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

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

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