appendBinaryStringInfo(out, "false", 5);
break;
case jbvNumeric:
- appendStringInfoString(out, DatumGetCString(DirectFunctionCall1(numeric_out, PointerGetDatum(v->numeric))));
+ appendStringInfoString(out,
+ DatumGetCString(DirectFunctionCall1(numeric_out,
+ PointerGetDatum(v->numeric))));
break;
default:
elog(ERROR, "unknown jsonb scalar type");
* keys.
*/
case WJB_ELEM:
- entries[i++] = PointerGetDatum(makeitemFromValue(&v, KEYFLAG));
+ entries[i++] = PointerGetDatum(makeitemFromValue(&v, KEYELEMFLAG));
break;
case WJB_VALUE:
entries[i++] = PointerGetDatum(makeitemFromValue(&v, VALFLAG));
*nentries = 1;
entries = (Datum *) palloc(sizeof(Datum));
- item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query), KEYFLAG);
+ item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query),
+ KEYELEMFLAG);
entries[0] = PointerGetDatum(item);
}
else if (strategy == JsonbExistsAnyStrategyNumber ||
if (key_nulls[i])
continue;
item = makeitem(VARDATA(key_datums[i]),
- VARSIZE(key_datums[i]) - VARHDRSZ, KEYFLAG);
+ VARSIZE(key_datums[i]) - VARHDRSZ,
+ KEYELEMFLAG);
entries[j++] = PointerGetDatum(item);
}
text *query = PG_GETARG_TEXT_PP(1);
int crc = crc32_Key(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query));
- qval = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(*qval));
+ qval = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(int));
*qval = HASHVAL(crc);
fcinfo->flinfo->fn_extra = qval;
* This is necessary because array elements are also keys.
*/
case WJB_ELEM:
- flag = KEYFLAG;
+ flag = KEYELEMFLAG;
break;
case WJB_VALUE:
flag = VALFLAG;
crc32_Key(char *buf, int sz)
{
int crc;
- char flag = KEYFLAG;
+ char flag = KEYELEMFLAG;
INIT_CRC32(crc);
plowbound = &lowbound;
/*
- * we exploit the fact that the pairs list is already sorted into strictly
+ * We exploit the fact that the pairs list is already sorted into strictly
* increasing order to narrow the findUncompressedJsonbValue search; each
* search can start one entry past the previous "found" entry, or at the
* lower bound of the last search.
*/
for (i = 0; i < v->array.nelems; i++)
{
- if (findUncompressedJsonbValueByValue(VARDATA(jb), JB_FLAG_OBJECT | JB_FLAG_ARRAY, plowbound,
+ if (findUncompressedJsonbValueByValue(VARDATA(jb),
+ JB_FLAG_OBJECT | JB_FLAG_ARRAY,
+ plowbound,
v->array.elems + i) != NULL)
{
res = true;
}
/*
- * this is a btree support function; this is one of the few places where
+ * This is a btree support function; this is one of the few places where
* memory needs to be explicitly freed.
*/
PG_FREE_IF_COPY(jb1, 0);
break;
case jbvNumeric:
crc ^= DatumGetInt32(DirectFunctionCall1(hash_numeric,
- NumericGetDatum(v.numeric)));
+ NumericGetDatum(v.numeric)));
break;
default:
elog(ERROR, "invalid jsonb iterator type");
{
uint32 j = 0;
- av = palloc(sizeof(*av) * nelems);
+ av = palloc(sizeof(JsonbValue) * nelems);
for (i = 0; i < nelems; i++)
{
return res;
}
+/*
+ * Convert a Postgres text array to a JsonbSortedArray, with de-duplicated key
+ * elements.
+ */
static JsonbValue *
arrayToJsonbSortedArray(ArrayType *a)
{
j;
bool hasNonUniq = false;
- deconstruct_array(a,
- TEXTOID, -1, false, 'i',
- &key_datums, &key_nulls, &key_count);
+ /* Extract data for sorting */
+ deconstruct_array(a, TEXTOID, -1, false, 'i', &key_datums, &key_nulls,
+ &key_count);
if (key_count == 0)
return NULL;
/*
* A text array uses at least eight bytes per element, so any overflow in
* "key_count * sizeof(JsonbPair)" is small enough for palloc() to catch.
- * However, credible improvements to the array format could invalidate
- * that assumption. Therefore, use an explicit check rather than relying
- * on palloc() to complain.
+ * However, credible improvements to the array format could invalidate that
+ * assumption. Therefore, use an explicit check rather than relying on
+ * palloc() to complain.
*/
if (key_count > MaxAllocSize / sizeof(JsonbPair))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
- key_count, (int) (MaxAllocSize / sizeof(JsonbPair)))));
+ errmsg("number of pairs (%d) exceeds the maximum allowed (%zu)",
+ key_count, MaxAllocSize / sizeof(JsonbPair))));
- v = palloc(sizeof(*v));
+ v = palloc(sizeof(JsonbValue));
v->type = jbvArray;
v->array.scalar = false;
v->array.elems = palloc(sizeof(*v->object.pairs) * key_count);
}
v->array.nelems = j;
+ /*
+ * Actually sort values, determining if any were equal on the basis of full
+ * binary equality (rather than just having the same string length).
+ */
if (v->array.nelems > 1)
qsort_arg(v->array.elems, v->array.nelems, sizeof(*v->array.elems),
- compareJsonbStringValue /* compareJsonbStringValue */ , &hasNonUniq);
+ compareJsonbStringValue, &hasNonUniq);
if (hasNonUniq)
{
while (ptr - v->array.elems < v->array.nelems)
{
+ /* Avoid copying over binary duplicate */
if (!(ptr->string.len == res->string.len &&
- memcmp(ptr->string.val, res->string.val, ptr->string.len) == 0))
+ memcmp(ptr->string.val, res->string.val, ptr->string.len) == 0))
{
res++;
*res = *ptr;
/*
* Compare two jbvString JsonbValue values.
*
- * Third argument 'arg', when set, should point to bool value which will be set
- * to true if strings are equal and untouched otherwise.
+ * This is a special qsort_arg() comparator used to
+ *
+ * Third argument 'binaryequal', when set, is deferenced to bool true if
+ * strings has full binary equality.
*/
int
-compareJsonbStringValue(const void *a, const void *b, void *arg)
+compareJsonbStringValue(const void *a, const void *b, void *binaryequal)
{
- const JsonbValue *va = a;
- const JsonbValue *vb = b;
+ const JsonbValue *va = (const JsonbValue *) a;
+ const JsonbValue *vb = (const JsonbValue *) b;
int res;
Assert(va->type == jbvString);
if (va->string.len == vb->string.len)
{
res = memcmp(va->string.val, vb->string.val, va->string.len);
- if (res == 0 && arg)
- *(bool *) arg = true;
+ if (res == 0 && binaryequal)
+ *((bool *) binaryequal) = true;
}
else
{
}
/*
- * Standard lexical comparison of jsonb strings
- *
- * not to be used for internal operations.
+ * Standard lexical qsort() comparator of jsonb strings.
*
+ * Sorts strings lexically, using the default text collation. Used by B-Tree
+ * operators.
*/
static int
-lexicalCompareJsonbStringValue(const void *a, const void *b, void *arg)
+lexicalCompareJsonbStringValue(const void *a, const void *b)
{
- const JsonbValue *va = a;
- const JsonbValue *vb = b;
- int res;
+ const JsonbValue *va = (const JsonbValue *) a;
+ const JsonbValue *vb = (const JsonbValue *) b;
Assert(va->type == jbvString);
Assert(vb->type == jbvString);
- res = varstr_cmp(va->string.val, va->string.len, vb->string.val,
- vb->string.len, DEFAULT_COLLATION_OID);
-
- if (arg && res == 0 && va->string.len == vb->string.len)
- *(bool *) arg = true;
-
- return res;
+ return varstr_cmp(va->string.val, va->string.len, vb->string.val,
+ vb->string.len, DEFAULT_COLLATION_OID);
}
/*
- * Give consistent ordering of JsonbValues
+ * Compare 2 JsonbValues
*/
int
compareJsonbValue(JsonbValue * a, JsonbValue * b)
case jbvNull:
return 0;
case jbvString:
- return lexicalCompareJsonbStringValue(a, b, NULL);
+ return lexicalCompareJsonbStringValue(a, b);
case jbvBool:
if (a->boolean == b->boolean)
return 0;
for (i = 0; i < a->object.npairs; i++)
{
if ((r = lexicalCompareJsonbStringValue(&a->object.pairs[i].key,
- &b->object.pairs[i].key,
- NULL)) != 0)
+ &b->object.pairs[i].key)) != 0)
return r;
if ((r = compareJsonbValue(&a->object.pairs[i].value,
&b->object.pairs[i].value)) != 0)
switch (v1.type)
{
case jbvString:
- res = lexicalCompareJsonbStringValue(&v1, &v2, NULL);
+ res = lexicalCompareJsonbStringValue(&v1, &v2);
break;
case jbvBool:
if (v1.boolean == v2.boolean)
}
/*
- * qsort comparator to compare JsonbPair values.
+ * qsort_arg() comparator to compare JsonbPair values.
*
* Function implemented in terms of compareJsonbStringValue(), and thus the
* same "arg setting" hack will be applied here in respect of the pair's key
* Walk the tree representation of jsonb *
****************************************************************************/
static void
-walkUncompressedJsonbDo(JsonbValue * v, walk_jsonb_cb cb, void *cb_arg, uint32 level)
+walkUncompressedJsonbDo(JsonbValue * v, walk_jsonb_cb cb, void *cb_arg,
+ uint32 level)
{
int i;
* the string to indicate key, value, or null values. (As of 9.1 it might be
* better to store null values as nulls, but we'll keep it this way for on-disk
* compatibility.)
+ *
+ * jsonb Keys and elements are treated equivalently when serialized to text
+ * index storage.
*/
-#define ELEMFLAG 'E'
-#define KEYFLAG 'K'
+#define KEYELEMFLAG 'K'
#define VALFLAG 'V'
#define NULLFLAG 'N'
typedef struct
{
int32 vl_len_; /* varlena header (do not touch directly!) */
- /* header of hash or array jsonb type
- * array of JEntry follows */
+ /* header of jsonb object or array */
+ /* array of JEntry follows */
} Jsonb;
struct JsonbValue
{
JsonbValue key;
JsonbValue value;
- uint32 order; /* To preserve order of pairs with equal keys */
+ uint32 order; /* preserves order of pairs with equal keys */
};
typedef struct ToJsonbState
bool isScalar;
char *data;
char *buffer; /* unparsed buffer */
-
int i;
/*
* Enum members should be freely OR'ed with JB_FLAG_ARRAY/JB_FLAG_JSONB
- * with possibility of decoding. See optimization in JsonbIteratorGet()
+ * with possibility of decoding. See optimization in JsonbIteratorGet()
*/
enum
{