PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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

◆ JsonPathGinAddPathItemFunc

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

Definition at line 134 of file jsonb_gin.c.

◆ JsonPathGinContext

◆ JsonPathGinExtractNodesFunc

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

Definition at line 141 of file jsonb_gin.c.

◆ JsonPathGinNode

◆ JsonPathGinNodeType

◆ JsonPathGinPath

◆ JsonPathGinPathItem

◆ 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

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

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
static int fb(int x)
Definition type.h:96

References JsonPathGinNode::args, elog, JsonPathGinNode::entryIndex, ERROR, execute_jsp_gin_node(), fb(), 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
600 larg = extract_jsp_bool_expr(cxt, path, &arg, not);
601
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 {
663 JsonbValue scalar;
664
665 if (not)
666 return NULL;
667
670
671 if (jspIsScalar(left_item.type))
672 {
675 }
676 else if (jspIsScalar(right_item.type))
677 {
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
enum jbvType type
Definition jsonb.h:257
char * val
Definition jsonb.h:266
const char * type

References arg, check_stack_depth(), elog, ERROR, extract_jsp_bool_expr(), extract_jsp_path_expr(), fb(), 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, and JsonbValue::val.

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(), fb(), 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:225
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, fb(), jpiCurrent, jpiFilter, jspGetArg(), jspGetNext(), lappend(), next, and NIL.

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:537
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#define false
#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

References JsonPathGinContext::add_path_item, GinEntries::buf, GinEntries::count, emit_jsp_gin_entries(), extract_jsp_bool_expr(), extract_jsp_path_expr(), JsonPathGinContext::extract_nodes, fb(), 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{
208 int32 result;
209 char *a1p,
210 *a2p;
211 int len1,
212 len2;
213
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
225
226 PG_RETURN_INT32(result);
227}
int32_t int32
Definition c.h:542
#define PG_FREE_IF_COPY(ptr, n)
Definition fmgr.h:260
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define PG_RETURN_INT32(x)
Definition fmgr.h:355
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 fb(), 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#ifdef NOT_USED
935 Jsonb *query = PG_GETARG_JSONB_P(2);
936#endif
937 int32 nkeys = PG_GETARG_INT32(3);
938
939 Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
940 bool *recheck = (bool *) PG_GETARG_POINTER(5);
941 bool res = true;
942 int32 i;
943
944 if (strategy == JsonbContainsStrategyNumber)
945 {
946 /*
947 * We must always recheck, since we can't tell from the index whether
948 * the positions of the matched items match the structure of the query
949 * object. (Even if we could, we'd also have to worry about hashed
950 * keys and the index's failure to distinguish keys from string array
951 * elements.) However, the tuple certainly doesn't match unless it
952 * contains all the query keys.
953 */
954 *recheck = true;
955 for (i = 0; i < nkeys; i++)
956 {
957 if (!check[i])
958 {
959 res = false;
960 break;
961 }
962 }
963 }
964 else if (strategy == JsonbExistsStrategyNumber)
965 {
966 /*
967 * Although the key is certainly present in the index, we must recheck
968 * because (1) the key might be hashed, and (2) the index match might
969 * be for a key that's not at top level of the JSON object. For (1),
970 * we could look at the query key to see if it's hashed and not
971 * recheck if not, but the index lacks enough info to tell about (2).
972 */
973 *recheck = true;
974 res = true;
975 }
976 else if (strategy == JsonbExistsAnyStrategyNumber)
977 {
978 /* As for plain exists, we must recheck */
979 *recheck = true;
980 res = true;
981 }
982 else if (strategy == JsonbExistsAllStrategyNumber)
983 {
984 /* As for plain exists, we must recheck */
985 *recheck = true;
986 /* ... but unless all the keys are present, we can say "false" */
987 for (i = 0; i < nkeys; i++)
988 {
989 if (!check[i])
990 {
991 res = false;
992 break;
993 }
994 }
995 }
996 else if (strategy == JsonbJsonpathPredicateStrategyNumber ||
998 {
999 *recheck = true;
1000
1001 if (nkeys > 0)
1002 {
1003 Assert(extra_data && extra_data[0]);
1004 res = execute_jsp_gin_node(extra_data[0], check, false) != GIN_FALSE;
1005 }
1006 }
1007 else
1008 elog(ERROR, "unrecognized strategy number: %d", strategy);
1009
1010 PG_RETURN_BOOL(res);
1011}
#define Assert(condition)
Definition c.h:873
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#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:360
#define PG_GETARG_JSONB_P(x)
Definition jsonb.h:418
#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
Definition jsonb.h:215

References Assert, elog, ERROR, execute_jsp_gin_node(), GIN_FALSE, i, JsonbContainsStrategyNumber, JsonbExistsAllStrategyNumber, JsonbExistsAnyStrategyNumber, JsonbExistsStrategyNumber, JsonbJsonpathExistsStrategyNumber, JsonbJsonpathPredicateStrategyNumber, PG_GETARG_INT32, PG_GETARG_JSONB_P, 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 1221 of file jsonb_gin.c.

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

References Assert, elog, ERROR, execute_jsp_gin_node(), GIN_FALSE, i, JsonbContainsStrategyNumber, JsonbJsonpathExistsStrategyNumber, JsonbJsonpathPredicateStrategyNumber, PG_GETARG_INT32, PG_GETARG_JSONB_P, 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{
233 int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
234 int total = JB_ROOT_COUNT(jb);
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;
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:363
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:1365
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

References add_gin_entry(), GinEntries::buf, GinEntries::count, fb(), init_gin_entries(), JB_ROOT_COUNT, jbvString, JsonbIteratorInit(), JsonbIteratorNext(), make_scalar_key(), PG_GETARG_JSONB_P, PG_GETARG_POINTER, PG_RETURN_POINTER, 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 1091 of file jsonb_gin.c.

1092{
1094 int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
1095 int total = JB_ROOT_COUNT(jb);
1097 JsonbValue v;
1099 PathHashStack tail;
1100 PathHashStack *stack;
1101 GinEntries entries;
1102
1103 /* If the root level is empty, we certainly have no keys */
1104 if (total == 0)
1105 {
1106 *nentries = 0;
1108 }
1109
1110 /* Otherwise, use 2 * root count as initial estimate of result size */
1111 init_gin_entries(&entries, 2 * total);
1112
1113 /* We keep a stack of partial hashes corresponding to parent key levels */
1114 tail.parent = NULL;
1115 tail.hash = 0;
1116 stack = &tail;
1117
1118 it = JsonbIteratorInit(&jb->root);
1119
1120 while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1121 {
1122 PathHashStack *parent;
1123
1124 switch (r)
1125 {
1126 case WJB_BEGIN_ARRAY:
1127 case WJB_BEGIN_OBJECT:
1128 /* Push a stack level for this object */
1129 parent = stack;
1131
1132 /*
1133 * We pass forward hashes from outer nesting levels so that
1134 * the hashes for nested values will include outer keys as
1135 * well as their own keys.
1136 *
1137 * Nesting an array within another array will not alter
1138 * innermost scalar element hash values, but that seems
1139 * inconsequential.
1140 */
1141 stack->hash = parent->hash;
1142 stack->parent = parent;
1143 break;
1144 case WJB_KEY:
1145 /* mix this key into the current outer hash */
1146 JsonbHashScalarValue(&v, &stack->hash);
1147 /* hash is now ready to incorporate the value */
1148 break;
1149 case WJB_ELEM:
1150 case WJB_VALUE:
1151 /* mix the element or value's hash into the prepared hash */
1152 JsonbHashScalarValue(&v, &stack->hash);
1153 /* and emit an index entry */
1154 add_gin_entry(&entries, UInt32GetDatum(stack->hash));
1155 /* reset hash for next key, value, or sub-object */
1156 stack->hash = stack->parent->hash;
1157 break;
1158 case WJB_END_ARRAY:
1159 case WJB_END_OBJECT:
1160 /* Pop the stack */
1161 parent = stack->parent;
1162 pfree(stack);
1163 stack = parent;
1164 /* reset hash for next key, value, or sub-object */
1165 if (stack->parent)
1166 stack->hash = stack->parent->hash;
1167 else
1168 stack->hash = 0;
1169 break;
1170 default:
1171 elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
1172 }
1173 }
1174
1175 *nentries = entries.count;
1176
1177 PG_RETURN_POINTER(entries.buf);
1178}
#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)
void pfree(void *pointer)
Definition mcxt.c:1616
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, fb(), 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, 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 */
884 bool *key_nulls;
885 int key_count;
886 int i,
887 j;
888
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,
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)
#define DirectFunctionCall2(func, arg1, arg2)
Definition fmgr.h:686
#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:1327
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:352
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342

References DatumGetPointer(), deconstruct_array_builtin(), DirectFunctionCall2, elog, ERROR, extract_jsp_query(), fb(), 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 1181 of file jsonb_gin.c.

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

References DatumGetPointer(), DirectFunctionCall2, elog, ERROR, extract_jsp_query(), fb(), 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 1014 of file jsonb_gin.c.

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

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

References Assert, elog, ERROR, execute_jsp_gin_node(), GIN_FALSE, GIN_MAYBE, GIN_TRUE, i, JsonbContainsStrategyNumber, JsonbJsonpathExistsStrategyNumber, JsonbJsonpathPredicateStrategyNumber, PG_GETARG_INT32, PG_GETARG_JSONB_P, 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, fb(), 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{
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
JsonPathGinPathItem * items
Definition jsonb_gin.c:127

References fb(), JsonPathGinPath::items, JGINFLAG_KEY, jpiAny, jpiAnyArray, jpiAnyKey, jpiIndexArray, jpiKey, jpiRoot, jspGetString(), len, make_text_key(), palloc_object, and PointerGetDatum().

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{
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 */
426 }
427
428 /* Append scalar node for equality queries. */
429 if (scalar->type == jbvString)
430 {
431 JsonPathGinPathItem *last = path.items;
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)
444 else if (!last) /* root ($) */
446 else if (last->type == jpiAnyArray || last->type == jpiIndexArray)
448 else if (last->type == jpiAny)
450 else
452
453 if (key_entry == GIN_MAYBE)
454 {
457
459 }
460 else
461 {
462 node = make_jsp_entry_node_scalar(scalar,
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
JsonPathItemType type
Definition jsonb_gin.c:121

References fb(), GIN_FALSE, GIN_MAYBE, GIN_TRUE, JsonPathGinPath::items, jbvString, jpiAny, jpiAnyArray, jpiIndexArray, jpiKey, JSP_GIN_OR, lappend(), JsonPathGinContext::lax, make_jsp_entry_node(), make_jsp_entry_node_scalar(), make_jsp_expr_node_binary(), 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 {
335
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 fb(), JsonPathGinPath::hash, jbvString, jpiAnyArray, jpiIndexArray, jpiKey, jpiRoot, JsonbHashScalarValue(), jspGetString(), and JsonbValue::type.

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:546
static unsigned hash(unsigned *uv, int n)
Definition rege_dfa.c:715

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

Referenced by extract_jsp_query().

◆ make_jsp_entry_node()

static JsonPathGinNode * make_jsp_entry_node ( Datum  entry)
static

Definition at line 354 of file jsonb_gin.c.

355{
357
358 node->type = JSP_GIN_ENTRY;
359 node->val.entryDatum = entry;
360
361 return node;
362}
void * palloc(Size size)
Definition mcxt.c:1387

References JsonPathGinNode::entryDatum, fb(), JSP_GIN_ENTRY, palloc(), JsonPathGinNode::type, and JsonPathGinNode::val.

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

◆ make_jsp_entry_node_scalar()

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

Definition at line 365 of file jsonb_gin.c.

366{
368}

References fb(), 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{
374 sizeof(node->args[0]) * nargs);
375
376 node->type = type;
377 node->val.nargs = nargs;
378
379 return node;
380}

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

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

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

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

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