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(entries->buf,
182 sizeof(Datum) * entries->allocated);
183 }
184 else
185 {
186 entries->allocated = 8;
187 entries->buf = palloc(sizeof(Datum) * entries->allocated);
188 }
189 }
190
191 entries->buf[entries->count++] = entry;
192
193 return id;
194}
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1610
void * palloc(Size size)
Definition: mcxt.c:1365
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(), and repalloc().

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

◆ emit_jsp_gin_entries()

static void emit_jsp_gin_entries ( JsonPathGinNode node,
GinEntries entries 
)
static

Definition at line 719 of file jsonb_gin.c.

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

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

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

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

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

Referenced by extract_jsp_bool_expr(), and extract_jsp_query().

◆ extract_jsp_path_expr_nodes()

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

Definition at line 504 of file jsonb_gin.c.

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

750{
753 JsonPathGinNode *node;
754 JsonPathGinPath path = {0};
755 GinEntries entries = {0};
756
757 cxt.lax = (jp->header & JSONPATH_LAX) != 0;
758
759 if (pathOps)
760 {
763 }
764 else
765 {
768 }
769
770 jspInit(&root, jp);
771
773 ? extract_jsp_path_expr(&cxt, path, &root, NULL)
774 : extract_jsp_bool_expr(&cxt, path, &root, false);
775
776 if (!node)
777 {
778 *nentries = 0;
779 return NULL;
780 }
781
782 emit_jsp_gin_entries(node, &entries);
783
784 *nentries = entries.count;
785 if (!*nentries)
786 return NULL;
787
788 *extra_data = palloc0(sizeof(**extra_data) * entries.count);
789 **extra_data = (Pointer) node;
790
791 return entries.buf;
792}
void * Pointer
Definition: c.h:532
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:478
static bool jsonb_ops__add_path_item(JsonPathGinPath *path, JsonPathItem *jsp)
Definition: jsonb_gin.c:278
static List * jsonb_ops__extract_nodes(JsonPathGinContext *cxt, JsonPathGinPath path, JsonbValue *scalar, List *nodes)
Definition: jsonb_gin.c:408
static bool jsonb_path_ops__add_path_item(JsonPathGinPath *path, JsonPathItem *jsp)
Definition: jsonb_gin.c:323
void jspInit(JsonPathItem *v, JsonPath *js)
Definition: jsonpath.c:980
#define JSONPATH_LAX
Definition: jsonpath.h:31
void * palloc0(Size size)
Definition: mcxt.c:1395
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(), 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 203 of file jsonb_gin.c.

204{
205 text *arg1 = PG_GETARG_TEXT_PP(0);
206 text *arg2 = PG_GETARG_TEXT_PP(1);
207 int32 result;
208 char *a1p,
209 *a2p;
210 int len1,
211 len2;
212
213 a1p = VARDATA_ANY(arg1);
214 a2p = VARDATA_ANY(arg2);
215
216 len1 = VARSIZE_ANY_EXHDR(arg1);
217 len2 = VARSIZE_ANY_EXHDR(arg2);
218
219 /* Compare text as bttextcmp does, but always using C collation */
220 result = varstr_cmp(a1p, len1, a2p, len2, C_COLLATION_OID);
221
222 PG_FREE_IF_COPY(arg1, 0);
223 PG_FREE_IF_COPY(arg2, 1);
224
225 PG_RETURN_INT32(result);
226}
int32_t int32
Definition: c.h:537
#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:695
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:1297

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

◆ gin_consistent_jsonb()

Datum gin_consistent_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 929 of file jsonb_gin.c.

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

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

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

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

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

Referenced by gin_extract_jsonb_query().

◆ gin_extract_jsonb_path()

Datum gin_extract_jsonb_path ( PG_FUNCTION_ARGS  )

Definition at line 1088 of file jsonb_gin.c.

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

Referenced by gin_extract_jsonb_query_path().

◆ gin_extract_jsonb_query()

Datum gin_extract_jsonb_query ( PG_FUNCTION_ARGS  )

Definition at line 848 of file jsonb_gin.c.

849{
850 int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
851 StrategyNumber strategy = PG_GETARG_UINT16(2);
852 int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
853 Datum *entries;
854
855 if (strategy == JsonbContainsStrategyNumber)
856 {
857 /* Query is a jsonb, so just apply gin_extract_jsonb... */
858 entries = (Datum *)
861 PointerGetDatum(nentries)));
862 /* ...although "contains {}" requires a full index scan */
863 if (*nentries == 0)
864 *searchMode = GIN_SEARCH_MODE_ALL;
865 }
866 else if (strategy == JsonbExistsStrategyNumber)
867 {
868 /* Query is a text string, which we treat as a key */
869 text *query = PG_GETARG_TEXT_PP(0);
870
871 *nentries = 1;
872 entries = (Datum *) palloc(sizeof(Datum));
873 entries[0] = make_text_key(JGINFLAG_KEY,
874 VARDATA_ANY(query),
875 VARSIZE_ANY_EXHDR(query));
876 }
877 else if (strategy == JsonbExistsAnyStrategyNumber ||
879 {
880 /* Query is a text array; each element is treated as a key */
882 Datum *key_datums;
883 bool *key_nulls;
884 int key_count;
885 int i,
886 j;
887
888 deconstruct_array_builtin(query, TEXTOID, &key_datums, &key_nulls, &key_count);
889
890 entries = (Datum *) palloc(sizeof(Datum) * key_count);
891
892 for (i = 0, j = 0; i < key_count; i++)
893 {
894 /* Nulls in the array are ignored */
895 if (key_nulls[i])
896 continue;
897 /* We rely on the array elements not being toasted */
898 entries[j++] = make_text_key(JGINFLAG_KEY,
899 VARDATA_ANY(DatumGetPointer(key_datums[i])),
900 VARSIZE_ANY_EXHDR(DatumGetPointer(key_datums[i])));
901 }
902
903 *nentries = j;
904 /* ExistsAll with no keys should match everything */
905 if (j == 0 && strategy == JsonbExistsAllStrategyNumber)
906 *searchMode = GIN_SEARCH_MODE_ALL;
907 }
908 else if (strategy == JsonbJsonpathPredicateStrategyNumber ||
910 {
912 Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4);
913
914 entries = extract_jsp_query(jp, strategy, false, nentries, extra_data);
915
916 if (!entries)
917 *searchMode = GIN_SEARCH_MODE_ALL;
918 }
919 else
920 {
921 elog(ERROR, "unrecognized strategy number: %d", strategy);
922 entries = NULL; /* keep compiler quiet */
923 }
924
925 PG_RETURN_POINTER(entries);
926}
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h: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:1322
static Datum * extract_jsp_query(JsonPath *jp, StrategyNumber strat, bool pathOps, int32 *nentries, Pointer **extra_data)
Definition: jsonb_gin.c:748
Datum gin_extract_jsonb(PG_FUNCTION_ARGS)
Definition: jsonb_gin.c:229
#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(), 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 1178 of file jsonb_gin.c.

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

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

◆ gin_triconsistent_jsonb()

Datum gin_triconsistent_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 1012 of file jsonb_gin.c.

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

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

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

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

Referenced by gin_extract_jsonb(), and gin_extract_jsonb_path().

◆ jsonb_ops__add_path_item()

static bool jsonb_ops__add_path_item ( JsonPathGinPath path,
JsonPathItem jsp 
)
static

Definition at line 278 of file jsonb_gin.c.

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

Referenced by extract_jsp_query().

◆ jsonb_ops__extract_nodes()

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

Definition at line 408 of file jsonb_gin.c.

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

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

Referenced by extract_jsp_query().

◆ jsonb_path_ops__add_path_item()

static bool jsonb_path_ops__add_path_item ( JsonPathGinPath path,
JsonPathItem jsp 
)
static

Definition at line 323 of file jsonb_gin.c.

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

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

Referenced by extract_jsp_query().

◆ jsonb_path_ops__extract_nodes()

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

Definition at line 478 of file jsonb_gin.c.

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

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

Referenced by extract_jsp_query().

◆ make_jsp_entry_node()

static JsonPathGinNode * make_jsp_entry_node ( Datum  entry)
static

◆ make_jsp_entry_node_scalar()

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

Definition at line 364 of file jsonb_gin.c.

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

References make_jsp_entry_node(), and make_scalar_key().

Referenced by jsonb_ops__extract_nodes().

◆ make_jsp_expr_node()

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

Definition at line 370 of file jsonb_gin.c.

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

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

Referenced by make_jsp_expr_node_args(), and make_jsp_expr_node_binary().

◆ make_jsp_expr_node_args()

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

Definition at line 382 of file jsonb_gin.c.

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

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

Referenced by extract_jsp_path_expr().

◆ make_jsp_expr_node_binary()

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

Definition at line 395 of file jsonb_gin.c.

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

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

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

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