LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonb_op.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 110 137 80.3 %
Date: 2017-09-29 13:40:31 Functions: 11 14 78.6 %
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-2017, 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        2250 : jsonb_exists(PG_FUNCTION_ARGS)
      23             : {
      24        2250 :     Jsonb      *jb = PG_GETARG_JSONB(0);
      25        2250 :     text       *key = PG_GETARG_TEXT_PP(1);
      26             :     JsonbValue  kval;
      27        2250 :     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        2250 :     kval.type = jbvString;
      36        2250 :     kval.val.string.val = VARDATA_ANY(key);
      37        2250 :     kval.val.string.len = VARSIZE_ANY_EXHDR(key);
      38             : 
      39        2250 :     v = findJsonbValueFromContainer(&jb->root,
      40             :                                     JB_FOBJECT | JB_FARRAY,
      41             :                                     &kval);
      42             : 
      43        2250 :     PG_RETURN_BOOL(v != NULL);
      44             : }
      45             : 
      46             : Datum
      47        1359 : jsonb_exists_any(PG_FUNCTION_ARGS)
      48             : {
      49        1359 :     Jsonb      *jb = PG_GETARG_JSONB(0);
      50        1359 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
      51             :     int         i;
      52             :     Datum      *key_datums;
      53             :     bool       *key_nulls;
      54             :     int         elem_count;
      55             : 
      56        1359 :     deconstruct_array(keys, TEXTOID, -1, false, 'i', &key_datums, &key_nulls,
      57             :                       &elem_count);
      58             : 
      59        3001 :     for (i = 0; i < elem_count; i++)
      60             :     {
      61             :         JsonbValue  strVal;
      62             : 
      63        2322 :         if (key_nulls[i])
      64           0 :             continue;
      65             : 
      66        2322 :         strVal.type = jbvString;
      67        2322 :         strVal.val.string.val = VARDATA(key_datums[i]);
      68        2322 :         strVal.val.string.len = VARSIZE(key_datums[i]) - VARHDRSZ;
      69             : 
      70        2322 :         if (findJsonbValueFromContainer(&jb->root,
      71             :                                         JB_FOBJECT | JB_FARRAY,
      72             :                                         &strVal) != NULL)
      73         680 :             PG_RETURN_BOOL(true);
      74             :     }
      75             : 
      76         679 :     PG_RETURN_BOOL(false);
      77             : }
      78             : 
      79             : Datum
      80        1065 : jsonb_exists_all(PG_FUNCTION_ARGS)
      81             : {
      82        1065 :     Jsonb      *jb = PG_GETARG_JSONB(0);
      83        1065 :     ArrayType  *keys = PG_GETARG_ARRAYTYPE_P(1);
      84             :     int         i;
      85             :     Datum      *key_datums;
      86             :     bool       *key_nulls;
      87             :     int         elem_count;
      88             : 
      89        1065 :     deconstruct_array(keys, TEXTOID, -1, false, 'i', &key_datums, &key_nulls,
      90             :                       &elem_count);
      91             : 
      92        1398 :     for (i = 0; i < elem_count; i++)
      93             :     {
      94             :         JsonbValue  strVal;
      95             : 
      96        1307 :         if (key_nulls[i])
      97           0 :             continue;
      98             : 
      99        1307 :         strVal.type = jbvString;
     100        1307 :         strVal.val.string.val = VARDATA(key_datums[i]);
     101        1307 :         strVal.val.string.len = VARSIZE(key_datums[i]) - VARHDRSZ;
     102             : 
     103        1307 :         if (findJsonbValueFromContainer(&jb->root,
     104             :                                         JB_FOBJECT | JB_FARRAY,
     105             :                                         &strVal) == NULL)
     106         974 :             PG_RETURN_BOOL(false);
     107             :     }
     108             : 
     109          91 :     PG_RETURN_BOOL(true);
     110             : }
     111             : 
     112             : Datum
     113        7212 : jsonb_contains(PG_FUNCTION_ARGS)
     114             : {
     115        7212 :     Jsonb      *val = PG_GETARG_JSONB(0);
     116        7212 :     Jsonb      *tmpl = PG_GETARG_JSONB(1);
     117             : 
     118             :     JsonbIterator *it1,
     119             :                *it2;
     120             : 
     121        7212 :     if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
     122           5 :         PG_RETURN_BOOL(false);
     123             : 
     124        7207 :     it1 = JsonbIteratorInit(&val->root);
     125        7207 :     it2 = JsonbIteratorInit(&tmpl->root);
     126             : 
     127        7207 :     PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
     128             : }
     129             : 
     130             : Datum
     131          17 : jsonb_contained(PG_FUNCTION_ARGS)
     132             : {
     133             :     /* Commutator of "contains" */
     134          17 :     Jsonb      *tmpl = PG_GETARG_JSONB(0);
     135          17 :     Jsonb      *val = PG_GETARG_JSONB(1);
     136             : 
     137             :     JsonbIterator *it1,
     138             :                *it2;
     139             : 
     140          17 :     if (JB_ROOT_IS_OBJECT(val) != JB_ROOT_IS_OBJECT(tmpl))
     141           0 :         PG_RETURN_BOOL(false);
     142             : 
     143          17 :     it1 = JsonbIteratorInit(&val->root);
     144          17 :     it2 = JsonbIteratorInit(&tmpl->root);
     145             : 
     146          17 :     PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
     147             : }
     148             : 
     149             : Datum
     150           2 : jsonb_ne(PG_FUNCTION_ARGS)
     151             : {
     152           2 :     Jsonb      *jba = PG_GETARG_JSONB(0);
     153           2 :     Jsonb      *jbb = PG_GETARG_JSONB(1);
     154             :     bool        res;
     155             : 
     156           2 :     res = (compareJsonbContainers(&jba->root, &jbb->root) != 0);
     157             : 
     158           2 :     PG_FREE_IF_COPY(jba, 0);
     159           2 :     PG_FREE_IF_COPY(jbb, 1);
     160           2 :     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(0);
     170           0 :     Jsonb      *jbb = PG_GETARG_JSONB(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         893 : jsonb_gt(PG_FUNCTION_ARGS)
     182             : {
     183         893 :     Jsonb      *jba = PG_GETARG_JSONB(0);
     184         893 :     Jsonb      *jbb = PG_GETARG_JSONB(1);
     185             :     bool        res;
     186             : 
     187         893 :     res = (compareJsonbContainers(&jba->root, &jbb->root) > 0);
     188             : 
     189         893 :     PG_FREE_IF_COPY(jba, 0);
     190         893 :     PG_FREE_IF_COPY(jbb, 1);
     191         893 :     PG_RETURN_BOOL(res);
     192             : }
     193             : 
     194             : Datum
     195           0 : jsonb_le(PG_FUNCTION_ARGS)
     196             : {
     197           0 :     Jsonb      *jba = PG_GETARG_JSONB(0);
     198           0 :     Jsonb      *jbb = PG_GETARG_JSONB(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(0);
     212           0 :     Jsonb      *jbb = PG_GETARG_JSONB(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        4170 : jsonb_eq(PG_FUNCTION_ARGS)
     224             : {
     225        4170 :     Jsonb      *jba = PG_GETARG_JSONB(0);
     226        4170 :     Jsonb      *jbb = PG_GETARG_JSONB(1);
     227             :     bool        res;
     228             : 
     229        4170 :     res = (compareJsonbContainers(&jba->root, &jbb->root) == 0);
     230             : 
     231        4170 :     PG_FREE_IF_COPY(jba, 0);
     232        4170 :     PG_FREE_IF_COPY(jbb, 1);
     233        4170 :     PG_RETURN_BOOL(res);
     234             : }
     235             : 
     236             : Datum
     237       51015 : jsonb_cmp(PG_FUNCTION_ARGS)
     238             : {
     239       51015 :     Jsonb      *jba = PG_GETARG_JSONB(0);
     240       51015 :     Jsonb      *jbb = PG_GETARG_JSONB(1);
     241             :     int         res;
     242             : 
     243       51015 :     res = compareJsonbContainers(&jba->root, &jbb->root);
     244             : 
     245       51015 :     PG_FREE_IF_COPY(jba, 0);
     246       51015 :     PG_FREE_IF_COPY(jbb, 1);
     247       51015 :     PG_RETURN_INT32(res);
     248             : }
     249             : 
     250             : /*
     251             :  * Hash operator class jsonb hashing function
     252             :  */
     253             : Datum
     254        2030 : jsonb_hash(PG_FUNCTION_ARGS)
     255             : {
     256        2030 :     Jsonb      *jb = PG_GETARG_JSONB(0);
     257             :     JsonbIterator *it;
     258             :     JsonbValue  v;
     259             :     JsonbIteratorToken r;
     260        2030 :     uint32      hash = 0;
     261             : 
     262        2030 :     if (JB_ROOT_COUNT(jb) == 0)
     263         236 :         PG_RETURN_INT32(0);
     264             : 
     265        1794 :     it = JsonbIteratorInit(&jb->root);
     266             : 
     267       26446 :     while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
     268             :     {
     269       22858 :         switch (r)
     270             :         {
     271             :                 /* Rotation is left to JsonbHashScalarValue() */
     272             :             case WJB_BEGIN_ARRAY:
     273          14 :                 hash ^= JB_FARRAY;
     274          14 :                 break;
     275             :             case WJB_BEGIN_OBJECT:
     276        1806 :                 hash ^= JB_FOBJECT;
     277        1806 :                 break;
     278             :             case WJB_KEY:
     279             :             case WJB_VALUE:
     280             :             case WJB_ELEM:
     281       19218 :                 JsonbHashScalarValue(&v, &hash);
     282       19218 :                 break;
     283             :             case WJB_END_ARRAY:
     284             :             case WJB_END_OBJECT:
     285        1820 :                 break;
     286             :             default:
     287           0 :                 elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
     288             :         }
     289             :     }
     290             : 
     291        1794 :     PG_FREE_IF_COPY(jb, 0);
     292        1794 :     PG_RETURN_INT32(hash);
     293             : }
     294             : 
     295             : Datum
     296           6 : jsonb_hash_extended(PG_FUNCTION_ARGS)
     297             : {
     298           6 :     Jsonb      *jb = PG_GETARG_JSONB(0);
     299           6 :     uint64      seed = PG_GETARG_INT64(1);
     300             :     JsonbIterator *it;
     301             :     JsonbValue  v;
     302             :     JsonbIteratorToken r;
     303           6 :     uint64      hash = 0;
     304             : 
     305           6 :     if (JB_ROOT_COUNT(jb) == 0)
     306           0 :         PG_RETURN_UINT64(seed);
     307             : 
     308           6 :     it = JsonbIteratorInit(&jb->root);
     309             : 
     310          80 :     while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
     311             :     {
     312          68 :         switch (r)
     313             :         {
     314             :             /* Rotation is left to JsonbHashScalarValueExtended() */
     315             :             case WJB_BEGIN_ARRAY:
     316           4 :                 hash ^= ((uint64) JB_FARRAY) << 32 | JB_FARRAY;
     317           4 :                 break;
     318             :             case WJB_BEGIN_OBJECT:
     319          12 :                 hash ^= ((uint64) JB_FOBJECT) << 32 | JB_FOBJECT;
     320          12 :                 break;
     321             :             case WJB_KEY:
     322             :             case WJB_VALUE:
     323             :             case WJB_ELEM:
     324          36 :                 JsonbHashScalarValueExtended(&v, &hash, seed);
     325          36 :                 break;
     326             :             case WJB_END_ARRAY:
     327             :             case WJB_END_OBJECT:
     328          16 :                 break;
     329             :             default:
     330           0 :                 elog(ERROR, "invalid JsonbIteratorNext rc: %d", (int) r);
     331             :         }
     332             :     }
     333             : 
     334           6 :     PG_FREE_IF_COPY(jb, 0);
     335           6 :     PG_RETURN_UINT64(hash);
     336             : }

Generated by: LCOV version 1.11