LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonb_op.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17beta1 Lines: 125 147 85.0 %
Date: 2024-06-18 00:11:41 Functions: 12 14 85.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * jsonb_op.c
       4             :  *   Special operators for jsonb only, used by various index access methods
       5             :  *
       6             :  * Copyright (c) 2014-2024, PostgreSQL Global Development Group
       7             :  *
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/backend/utils/adt/jsonb_op.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : #include "postgres.h"
      15             : 
      16             : #include "catalog/pg_type.h"
      17             : #include "utils/fmgrprotos.h"
      18             : #include "utils/jsonb.h"
      19             : 
      20             : Datum
      21       13718 : jsonb_exists(PG_FUNCTION_ARGS)
      22             : {
      23       13718 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
      24       13718 :     text       *key = PG_GETARG_TEXT_PP(1);
      25             :     JsonbValue  kval;
      26       13718 :     JsonbValue *v = NULL;
      27             : 
      28             :     /*
      29             :      * We only match Object keys (which are naturally always Strings), or
      30             :      * string elements in arrays.  In particular, we do not match non-string
      31             :      * scalar elements.  Existence of a key/element is only considered at the
      32             :      * top level.  No recursion occurs.
      33             :      */
      34       13718 :     kval.type = jbvString;
      35       13718 :     kval.val.string.val = VARDATA_ANY(key);
      36       13718 :     kval.val.string.len = VARSIZE_ANY_EXHDR(key);
      37             : 
      38       13718 :     v = findJsonbValueFromContainer(&jb->root,
      39             :                                     JB_FOBJECT | JB_FARRAY,
      40             :                                     &kval);
      41             : 
      42       13718 :     PG_RETURN_BOOL(v != NULL);
      43             : }
      44             : 
      45             : Datum
      46        8154 : jsonb_exists_any(PG_FUNCTION_ARGS)
      47             : {
      48        8154 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
      49        8154 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
      50             :     int         i;
      51             :     Datum      *key_datums;
      52             :     bool       *key_nulls;
      53             :     int         elem_count;
      54             : 
      55        8154 :     deconstruct_array_builtin(keys, TEXTOID, &key_datums, &key_nulls, &elem_count);
      56             : 
      57       18006 :     for (i = 0; i < elem_count; i++)
      58             :     {
      59             :         JsonbValue  strVal;
      60             : 
      61       13932 :         if (key_nulls[i])
      62           0 :             continue;
      63             : 
      64       13932 :         strVal.type = jbvString;
      65             :         /* We rely on the array elements not being toasted */
      66       13932 :         strVal.val.string.val = VARDATA_ANY(key_datums[i]);
      67       13932 :         strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
      68             : 
      69       13932 :         if (findJsonbValueFromContainer(&jb->root,
      70             :                                         JB_FOBJECT | JB_FARRAY,
      71             :                                         &strVal) != NULL)
      72        4080 :             PG_RETURN_BOOL(true);
      73             :     }
      74             : 
      75        4074 :     PG_RETURN_BOOL(false);
      76             : }
      77             : 
      78             : Datum
      79        6390 : jsonb_exists_all(PG_FUNCTION_ARGS)
      80             : {
      81        6390 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
      82        6390 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
      83             :     int         i;
      84             :     Datum      *key_datums;
      85             :     bool       *key_nulls;
      86             :     int         elem_count;
      87             : 
      88        6390 :     deconstruct_array_builtin(keys, TEXTOID, &key_datums, &key_nulls, &elem_count);
      89             : 
      90        8388 :     for (i = 0; i < elem_count; i++)
      91             :     {
      92             :         JsonbValue  strVal;
      93             : 
      94        7842 :         if (key_nulls[i])
      95           0 :             continue;
      96             : 
      97        7842 :         strVal.type = jbvString;
      98             :         /* We rely on the array elements not being toasted */
      99        7842 :         strVal.val.string.val = VARDATA_ANY(key_datums[i]);
     100        7842 :         strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
     101             : 
     102        7842 :         if (findJsonbValueFromContainer(&jb->root,
     103             :                                         JB_FOBJECT | JB_FARRAY,
     104             :                                         &strVal) == NULL)
     105        5844 :             PG_RETURN_BOOL(false);
     106             :     }
     107             : 
     108         546 :     PG_RETURN_BOOL(true);
     109             : }
     110             : 
     111             : Datum
     112       43272 : jsonb_contains(PG_FUNCTION_ARGS)
     113             : {
     114       43272 :     Jsonb      *val = PG_GETARG_JSONB_P(0);
     115       43272 :     Jsonb      *tmpl = PG_GETARG_JSONB_P(1);
     116             : 
     117             :     JsonbIterator *it1,
     118             :                *it2;
     119             : 
     120       43272 :     if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
     121          30 :         PG_RETURN_BOOL(false);
     122             : 
     123       43242 :     it1 = JsonbIteratorInit(&val->root);
     124       43242 :     it2 = JsonbIteratorInit(&tmpl->root);
     125             : 
     126       43242 :     PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
     127             : }
     128             : 
     129             : Datum
     130         102 : jsonb_contained(PG_FUNCTION_ARGS)
     131             : {
     132             :     /* Commutator of "contains" */
     133         102 :     Jsonb      *tmpl = PG_GETARG_JSONB_P(0);
     134         102 :     Jsonb      *val = PG_GETARG_JSONB_P(1);
     135             : 
     136             :     JsonbIterator *it1,
     137             :                *it2;
     138             : 
     139         102 :     if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
     140           0 :         PG_RETURN_BOOL(false);
     141             : 
     142         102 :     it1 = JsonbIteratorInit(&val->root);
     143         102 :     it2 = JsonbIteratorInit(&tmpl->root);
     144             : 
     145         102 :     PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
     146             : }
     147             : 
     148             : Datum
     149          12 : jsonb_ne(PG_FUNCTION_ARGS)
     150             : {
     151          12 :     Jsonb      *jba = PG_GETARG_JSONB_P(0);
     152          12 :     Jsonb      *jbb = PG_GETARG_JSONB_P(1);
     153             :     bool        res;
     154             : 
     155          12 :     res = (compareJsonbContainers(&jba->root, &jbb->root) != 0);
     156             : 
     157          12 :     PG_FREE_IF_COPY(jba, 0);
     158          12 :     PG_FREE_IF_COPY(jbb, 1);
     159          12 :     PG_RETURN_BOOL(res);
     160             : }
     161             : 
     162             : /*
     163             :  * B-Tree operator class operators, support function
     164             :  */
     165             : Datum
     166          12 : jsonb_lt(PG_FUNCTION_ARGS)
     167             : {
     168          12 :     Jsonb      *jba = PG_GETARG_JSONB_P(0);
     169          12 :     Jsonb      *jbb = PG_GETARG_JSONB_P(1);
     170             :     bool        res;
     171             : 
     172          12 :     res = (compareJsonbContainers(&jba->root, &jbb->root) < 0);
     173             : 
     174          12 :     PG_FREE_IF_COPY(jba, 0);
     175          12 :     PG_FREE_IF_COPY(jbb, 1);
     176          12 :     PG_RETURN_BOOL(res);
     177             : }
     178             : 
     179             : Datum
     180         174 : jsonb_gt(PG_FUNCTION_ARGS)
     181             : {
     182         174 :     Jsonb      *jba = PG_GETARG_JSONB_P(0);
     183         174 :     Jsonb      *jbb = PG_GETARG_JSONB_P(1);
     184             :     bool        res;
     185             : 
     186         174 :     res = (compareJsonbContainers(&jba->root, &jbb->root) > 0);
     187             : 
     188         174 :     PG_FREE_IF_COPY(jba, 0);
     189         174 :     PG_FREE_IF_COPY(jbb, 1);
     190         174 :     PG_RETURN_BOOL(res);
     191             : }
     192             : 
     193             : Datum
     194           0 : jsonb_le(PG_FUNCTION_ARGS)
     195             : {
     196           0 :     Jsonb      *jba = PG_GETARG_JSONB_P(0);
     197           0 :     Jsonb      *jbb = PG_GETARG_JSONB_P(1);
     198             :     bool        res;
     199             : 
     200           0 :     res = (compareJsonbContainers(&jba->root, &jbb->root) <= 0);
     201             : 
     202           0 :     PG_FREE_IF_COPY(jba, 0);
     203           0 :     PG_FREE_IF_COPY(jbb, 1);
     204           0 :     PG_RETURN_BOOL(res);
     205             : }
     206             : 
     207             : Datum
     208           0 : jsonb_ge(PG_FUNCTION_ARGS)
     209             : {
     210           0 :     Jsonb      *jba = PG_GETARG_JSONB_P(0);
     211           0 :     Jsonb      *jbb = PG_GETARG_JSONB_P(1);
     212             :     bool        res;
     213             : 
     214           0 :     res = (compareJsonbContainers(&jba->root, &jbb->root) >= 0);
     215             : 
     216           0 :     PG_FREE_IF_COPY(jba, 0);
     217           0 :     PG_FREE_IF_COPY(jbb, 1);
     218           0 :     PG_RETURN_BOOL(res);
     219             : }
     220             : 
     221             : Datum
     222       25024 : jsonb_eq(PG_FUNCTION_ARGS)
     223             : {
     224       25024 :     Jsonb      *jba = PG_GETARG_JSONB_P(0);
     225       25024 :     Jsonb      *jbb = PG_GETARG_JSONB_P(1);
     226             :     bool        res;
     227             : 
     228       25024 :     res = (compareJsonbContainers(&jba->root, &jbb->root) == 0);
     229             : 
     230       25024 :     PG_FREE_IF_COPY(jba, 0);
     231       25024 :     PG_FREE_IF_COPY(jbb, 1);
     232       25024 :     PG_RETURN_BOOL(res);
     233             : }
     234             : 
     235             : Datum
     236      242720 : jsonb_cmp(PG_FUNCTION_ARGS)
     237             : {
     238      242720 :     Jsonb      *jba = PG_GETARG_JSONB_P(0);
     239      242720 :     Jsonb      *jbb = PG_GETARG_JSONB_P(1);
     240             :     int         res;
     241             : 
     242      242720 :     res = compareJsonbContainers(&jba->root, &jbb->root);
     243             : 
     244      242720 :     PG_FREE_IF_COPY(jba, 0);
     245      242720 :     PG_FREE_IF_COPY(jbb, 1);
     246      242720 :     PG_RETURN_INT32(res);
     247             : }
     248             : 
     249             : /*
     250             :  * Hash operator class jsonb hashing function
     251             :  */
     252             : Datum
     253       12180 : jsonb_hash(PG_FUNCTION_ARGS)
     254             : {
     255       12180 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     256             :     JsonbIterator *it;
     257             :     JsonbValue  v;
     258             :     JsonbIteratorToken r;
     259       12180 :     uint32      hash = 0;
     260             : 
     261       12180 :     if (JB_ROOT_COUNT(jb) == 0)
     262        1416 :         PG_RETURN_INT32(0);
     263             : 
     264       10764 :     it = JsonbIteratorInit(&jb->root);
     265             : 
     266      147912 :     while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
     267             :     {
     268      137148 :         switch (r)
     269             :         {
     270             :                 /* Rotation is left to JsonbHashScalarValue() */
     271          84 :             case WJB_BEGIN_ARRAY:
     272          84 :                 hash ^= JB_FARRAY;
     273          84 :                 break;
     274       10836 :             case WJB_BEGIN_OBJECT:
     275       10836 :                 hash ^= JB_FOBJECT;
     276       10836 :                 break;
     277      115308 :             case WJB_KEY:
     278             :             case WJB_VALUE:
     279             :             case WJB_ELEM:
     280      115308 :                 JsonbHashScalarValue(&v, &hash);
     281      115308 :                 break;
     282       10920 :             case WJB_END_ARRAY:
     283             :             case WJB_END_OBJECT:
     284       10920 :                 break;
     285           0 :             default:
     286           0 :                 elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
     287             :         }
     288             :     }
     289             : 
     290       10764 :     PG_FREE_IF_COPY(jb, 0);
     291       10764 :     PG_RETURN_INT32(hash);
     292             : }
     293             : 
     294             : Datum
     295          36 : jsonb_hash_extended(PG_FUNCTION_ARGS)
     296             : {
     297          36 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     298          36 :     uint64      seed = PG_GETARG_INT64(1);
     299             :     JsonbIterator *it;
     300             :     JsonbValue  v;
     301             :     JsonbIteratorToken r;
     302          36 :     uint64      hash = 0;
     303             : 
     304          36 :     if (JB_ROOT_COUNT(jb) == 0)
     305           0 :         PG_RETURN_UINT64(seed);
     306             : 
     307          36 :     it = JsonbIteratorInit(&jb->root);
     308             : 
     309         444 :     while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
     310             :     {
     311         408 :         switch (r)
     312             :         {
     313             :                 /* Rotation is left to JsonbHashScalarValueExtended() */
     314          24 :             case WJB_BEGIN_ARRAY:
     315          24 :                 hash ^= ((uint64) JB_FARRAY) << 32 | JB_FARRAY;
     316          24 :                 break;
     317          72 :             case WJB_BEGIN_OBJECT:
     318          72 :                 hash ^= ((uint64) JB_FOBJECT) << 32 | JB_FOBJECT;
     319          72 :                 break;
     320         216 :             case WJB_KEY:
     321             :             case WJB_VALUE:
     322             :             case WJB_ELEM:
     323         216 :                 JsonbHashScalarValueExtended(&v, &hash, seed);
     324         216 :                 break;
     325          96 :             case WJB_END_ARRAY:
     326             :             case WJB_END_OBJECT:
     327          96 :                 break;
     328           0 :             default:
     329           0 :                 elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
     330             :         }
     331             :     }
     332             : 
     333          36 :     PG_FREE_IF_COPY(jb, 0);
     334          36 :     PG_RETURN_UINT64(hash);
     335             : }

Generated by: LCOV version 1.14