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

Generated by: LCOV version 1.14