Esempio n. 1
0
/*
 * jsonb_delete:
 * Return copy of jsonb with the specified item removed.
 * Item is a one key or element from jsonb, specified by name.
 * If there are many keys or elements with than name,
 * the first one will be removed.
 */
Datum
jsonb_delete(PG_FUNCTION_ARGS)
{
	Jsonb 				*in = PG_GETARG_JSONB(0);
	text 				*key = PG_GETARG_TEXT_PP(1);
	char 				*keyptr = VARDATA_ANY(key);
	int					keylen = VARSIZE_ANY_EXHDR(key);
	JsonbParseState 	*state = NULL;
	JsonbIterator 		*it;
	uint32 				r;
	JsonbValue 			v, *res = NULL;
	bool 				skipped = false;

	if (JB_ROOT_IS_SCALAR(in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot delete from scalar")));

	if (JB_ROOT_COUNT(in) == 0)
	{
		PG_RETURN_JSONB(in);
	}

	it = JsonbIteratorInit(&in->root);

	while((r = JsonbIteratorNext(&it, &v, false)) != 0)
	{
		if (!skipped && (r == WJB_ELEM || r == WJB_KEY) &&
			(v.type == jbvString && keylen == v.val.string.len &&
			 memcmp(keyptr, v.val.string.val, keylen) == 0))
		{
			/* we should delete only one key/element */
			skipped = true;

			if (r == WJB_KEY)
			{
				/* skip corresponding value */
				JsonbIteratorNext(&it, &v, true);
			}

			continue;
		}

		res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
	}

	Assert(res != NULL);
	PG_RETURN_JSONB(JsonbValueToJsonb(res));
}
Esempio n. 2
0
/*
 * jsonb_set:
 * Replace/create value of jsonb key or jsonb element, which can be found by the specified path.
 * Path must be replesented as an array of key names or indexes. If indexes will be used,
 * the same rules implied as for jsonb_delete_idx (negative indexing and edge cases)
 */
Datum
jsonb_set(PG_FUNCTION_ARGS)
{
	Jsonb 				*in = PG_GETARG_JSONB(0);
	ArrayType 			*path = PG_GETARG_ARRAYTYPE_P(1);
	Jsonb 				*newval = PG_GETARG_JSONB(2);
	bool       			create = PG_GETARG_BOOL(3);
	JsonbValue 			*res = NULL;
	Datum 				*path_elems;
	bool 				*path_nulls;
	int					path_len;
	JsonbIterator 		*it;
	JsonbParseState 	*st = NULL;


	if (ARR_NDIM(path) > 1)
		ereport(ERROR,
				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
				 errmsg("wrong number of array subscripts")));

	if (JB_ROOT_IS_SCALAR(in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot set path in scalar")));


	if (JB_ROOT_COUNT(in) == 0 && !create)
	{
		PG_RETURN_JSONB(in);
	}

	deconstruct_array(path, TEXTOID, -1, false, 'i',
					  &path_elems, &path_nulls, &path_len);

	if (path_len == 0)
	{
		PG_RETURN_JSONB(in);
	}

	it = JsonbIteratorInit(&in->root);

	res = setPath(&it, path_elems, path_nulls, path_len, &st, 0, newval, create);

	Assert (res != NULL);
	PG_RETURN_JSONB(JsonbValueToJsonb(res));
}
Esempio n. 3
0
Datum
bool_jsonb(PG_FUNCTION_ARGS)
{
	bool		b = PG_GETARG_BOOL(0);
	JsonbValue	jv;

	jv.type = jbvBool;
	jv.val.boolean = b;

	PG_RETURN_JSONB(JsonbValueToJsonb(&jv));
}
Esempio n. 4
0
/*
 * jsonb_concat:
 * Concatenation of two jsonb. There are few allowed combinations:
 * - concatenation of two objects
 * - concatenation of two arrays
 * - concatenation of object and array
 *
 * The result for first two is new object and array accordingly.
 * The last one return new array, which contains all elements from
 * original array, and one extra element (which is actually
 * other argument of this function with type jbvObject) at the first or last position.
 */
Datum
jsonb_concat(PG_FUNCTION_ARGS)
{
	Jsonb 				*jb1 = PG_GETARG_JSONB(0);
	Jsonb 				*jb2 = PG_GETARG_JSONB(1);
	Jsonb 				*out = palloc(VARSIZE(jb1) + VARSIZE(jb2));
	JsonbParseState 	*state = NULL;
	JsonbValue 			*res;
	JsonbIterator 		*it1, *it2;

	/*
	 * If one of the jsonb is empty,
	 * just return other.
	 */
	if (JB_ROOT_COUNT(jb1) == 0)
	{
		memcpy(out, jb2, VARSIZE(jb2));
		PG_RETURN_POINTER(out);
	}
	else if (JB_ROOT_COUNT(jb2) == 0) 
	{
		memcpy(out, jb1, VARSIZE(jb1));
		PG_RETURN_POINTER(out);
	}

	it1 = JsonbIteratorInit(&jb1->root);
	it2 = JsonbIteratorInit(&jb2->root);

	res = IteratorConcat(&it1, &it2, &state);

	if (res == NULL || (res->type == jbvArray && res->val.array.nElems == 0) ||
					   (res->type == jbvObject && res->val.object.nPairs == 0) )
	{
		SET_VARSIZE(out, VARHDRSZ);
	}
	else
	{
		if (res->type == jbvArray && res->val.array.nElems > 1)
			res->val.array.rawScalar = false;

		out = JsonbValueToJsonb(res);
	}

	PG_RETURN_JSONB(out);
}
Esempio n. 5
0
Datum
jsonb_add(PG_FUNCTION_ARGS)
{
	Jsonb	   *l = PG_GETARG_JSONB(0);
	Jsonb	   *r = PG_GETARG_JSONB(1);
	JsonbValue *ljv;
	JsonbValue *rjv;
	JsonbValue	jv;
	Size		len;
	char	   *buf;
	Datum		n;
	char	   *nstr;

	if (!(JB_ROOT_IS_SCALAR(l) && JB_ROOT_IS_SCALAR(r)))
	{
		Datum		j;

		if ((JB_ROOT_IS_SCALAR(l) && JB_ROOT_IS_OBJECT(r)) ||
			(JB_ROOT_IS_OBJECT(l) && JB_ROOT_IS_SCALAR(r)) ||
			(JB_ROOT_IS_OBJECT(l) && JB_ROOT_IS_OBJECT(r)))
			ereport_op_str("+", l, r);

		j = DirectFunctionCall2(jsonb_concat,
								JsonbGetDatum(l), JsonbGetDatum(r));

		PG_RETURN_DATUM(j);
	}

	ljv = getIthJsonbValueFromContainer(&l->root, 0);
	rjv = getIthJsonbValueFromContainer(&r->root, 0);

	if (ljv->type == jbvString && rjv->type == jbvString)
	{
		len = ljv->val.string.len + rjv->val.string.len;
		buf = palloc(len + 1);

		strncpy(buf, ljv->val.string.val, ljv->val.string.len);
		strncpy(buf + ljv->val.string.len,
				rjv->val.string.val, rjv->val.string.len);
		buf[len] = '\0';

		jv.type = jbvString;
		jv.val.string.len = len;
		jv.val.string.val = buf;

		PG_RETURN_JSONB(JsonbValueToJsonb(&jv));
	}
	else if (ljv->type == jbvString && rjv->type == jbvNumeric)
	{
		n = DirectFunctionCall1(numeric_out,
								NumericGetDatum(rjv->val.numeric));
		nstr = DatumGetCString(n);

		len = ljv->val.string.len + strlen(nstr);
		buf = palloc(len + 1);

		strncpy(buf, ljv->val.string.val, ljv->val.string.len);
		strcpy(buf + ljv->val.string.len, nstr);

		jv.type = jbvString;
		jv.val.string.len = len;
		jv.val.string.val = buf;

		PG_RETURN_JSONB(JsonbValueToJsonb(&jv));
	}
	else if (ljv->type == jbvNumeric && rjv->type == jbvString)
	{
		Size		nlen;

		n = DirectFunctionCall1(numeric_out,
								NumericGetDatum(ljv->val.numeric));
		nstr = DatumGetCString(n);
		nlen = strlen(nstr);

		len = nlen + rjv->val.string.len;
		buf = palloc(len + 1);

		strcpy(buf, nstr);
		strncpy(buf + nlen, rjv->val.string.val, rjv->val.string.len);
		buf[len] = '\0';

		jv.type = jbvString;
		jv.val.string.len = len;
		jv.val.string.val = buf;

		PG_RETURN_JSONB(JsonbValueToJsonb(&jv));
	}
	else if (ljv->type == jbvNumeric && rjv->type == jbvNumeric)
	{
		n = DirectFunctionCall2(numeric_add,
								NumericGetDatum(ljv->val.numeric),
								NumericGetDatum(rjv->val.numeric));

		PG_RETURN_JSONB(numeric_to_jnumber(DatumGetNumeric(n)));
	}
	else
	{
		ereport_op_str("+", l, r);
	}

	PG_RETURN_NULL();
}
Esempio n. 6
0
Datum
jsonb_uminus(PG_FUNCTION_ARGS)
{
	PG_RETURN_JSONB(jnumber_op(numeric_uminus, NULL, PG_GETARG_JSONB(0)));
}
Esempio n. 7
0
Datum
jsonb_pow(PG_FUNCTION_ARGS)
{
	PG_RETURN_JSONB(jnumber_op(numeric_power,
							   PG_GETARG_JSONB(0), PG_GETARG_JSONB(1)));
}
Esempio n. 8
0
/*
 * jsonb_delete_idx:
 * Return a copy of jsonb withour specified items.
 * Delete key (only from the top level of object) or element from jsonb by index (idx).
 * Negative idx value is supported, and it implies the countdown from the last key/element.
 * If idx is more, than numbers of keys/elements, or equal - nothing will be deleted.
 * If idx is negative and -idx is more, than number of keys/elements - the last one will be deleted.
 *
 * TODO: take care about nesting values.
 */
Datum
jsonb_delete_idx(PG_FUNCTION_ARGS)
{
	Jsonb 				*in = PG_GETARG_JSONB(0);
	int					idx = PG_GETARG_INT32(1);
	JsonbParseState 	*state = NULL;
	JsonbIterator 		*it;
	uint32 				r, i = 0, n;
	JsonbValue 			v, *res = NULL;

	if (JB_ROOT_IS_SCALAR(in))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
				 errmsg("cannot delete from scalar")));

	if (JB_ROOT_COUNT(in) == 0)
	{
		PG_RETURN_JSONB(in);
	}

	it = JsonbIteratorInit(&in->root);

	r = JsonbIteratorNext(&it, &v, false);
	if (r == WJB_BEGIN_ARRAY)
		n = v.val.array.nElems;
	else
		n = v.val.object.nPairs;

	if (idx < 0)
	{
		if (-idx > n)
			idx = n;
		else
			idx = n + idx;
	}

	if (idx >= n)
	{
		PG_RETURN_JSONB(in);
	}

	pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);

	while((r = JsonbIteratorNext(&it, &v, true)) != 0)
	{
		if (r == WJB_ELEM || r == WJB_KEY)
		{
			if (i++ == idx)
			{
				if (r == WJB_KEY)
					JsonbIteratorNext(&it, &v, true); /* skip value */
				continue;
			}
		}

		res = pushJsonbValue(&state, r, r < WJB_BEGIN_ARRAY ? &v : NULL);
	}

	Assert (res != NULL);
	PG_RETURN_JSONB(JsonbValueToJsonb(res));
}