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:1541
void * palloc(Size size)
Definition: mcxt.c:1317
uintptr_t Datum
Definition: postgres.h:69
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:72
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
JsonPathGinNodeType type
Definition: jsonb_gin.c:99
JsonPathGinNode * args[FLEXIBLE_ARRAY_MEMBER]
Definition: jsonb_gin.c:108
union JsonPathGinNode::@23 val
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{
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:225
#define GIN_FALSE
Definition: gin.h:63
char GinTernaryValue
Definition: gin.h:58
#define GIN_MAYBE
Definition: gin.h:65
#define GIN_TRUE
Definition: gin.h:64
static GinTernaryValue execute_jsp_gin_node(JsonPathGinNode *node, void *check, bool ternary)
Definition: jsonb_gin.c:799
Definition: type.h: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, res, 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:54
void * arg
int32 datalen
Definition: jsonpath.h:181
union JsonPathItem::@144 content
JsonPathItemType type
Definition: jsonpath.h:137
char * data
Definition: jsonpath.h:180
struct JsonPathItem::@144::@148 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:221
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}
char * Pointer
Definition: c.h:479
return false
Definition: isn.c:130
#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:1347
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:484
#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:644
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid)
Definition: varlena.c:1538

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

◆ gin_consistent_jsonb()

Datum gin_consistent_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 929 of file jsonb_gin.c.

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

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

◆ gin_consistent_jsonb_path()

Datum gin_consistent_jsonb_path ( PG_FUNCTION_ARGS  )

Definition at line 1220 of file jsonb_gin.c.

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

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

◆ gin_extract_jsonb()

Datum gin_extract_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 229 of file jsonb_gin.c.

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

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

Referenced by gin_extract_jsonb_query().

◆ gin_extract_jsonb_path()

Datum gin_extract_jsonb_path ( PG_FUNCTION_ARGS  )

Definition at line 1090 of file jsonb_gin.c.

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

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

◆ gin_extract_jsonb_query_path()

Datum gin_extract_jsonb_query_path ( PG_FUNCTION_ARGS  )

Definition at line 1180 of file jsonb_gin.c.

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

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

◆ gin_triconsistent_jsonb()

Datum gin_triconsistent_jsonb ( PG_FUNCTION_ARGS  )

Definition at line 1013 of file jsonb_gin.c.

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

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

◆ gin_triconsistent_jsonb_path()

Datum gin_triconsistent_jsonb_path ( PG_FUNCTION_ARGS  )

Definition at line 1272 of file jsonb_gin.c.

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

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

◆ init_gin_entries()

static void init_gin_entries ( GinEntries entries,
int  preallocated 
)
static

Definition at line 163 of file jsonb_gin.c.

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

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

Referenced by gin_extract_jsonb(), and gin_extract_jsonb_path().

◆ jsonb_ops__add_path_item()

static bool jsonb_ops__add_path_item ( JsonPathGinPath path,
JsonPathItem jsp 
)
static

Definition at line 278 of file jsonb_gin.c.

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

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

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

Referenced by gin_extract_jsonb(), and make_jsp_entry_node_scalar().

◆ make_text_key()

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

Definition at line 1326 of file jsonb_gin.c.

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

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

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