Esempio n. 1
0
Datum
gin_extract_jsonb(PG_FUNCTION_ARGS)
{
	Jsonb	   *jb = (Jsonb *) PG_GETARG_JSONB_P(0);
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	int			total = 2 * JB_ROOT_COUNT(jb);
	JsonbIterator *it;
	JsonbValue	v;
	JsonbIteratorToken r;
	int			i = 0;
	Datum	   *entries;

	/* If the root level is empty, we certainly have no keys */
	if (total == 0)
	{
		*nentries = 0;
		PG_RETURN_POINTER(NULL);
	}

	/* Otherwise, use 2 * root count as initial estimate of result size */
	entries = (Datum *) palloc(sizeof(Datum) * total);

	it = JsonbIteratorInit(&jb->root);

	while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
	{
		/* Since we recurse into the object, we might need more space */
		if (i >= total)
		{
			total *= 2;
			entries = (Datum *) repalloc(entries, sizeof(Datum) * total);
		}

		switch (r)
		{
			case WJB_KEY:
				entries[i++] = make_scalar_key(&v, true);
				break;
			case WJB_ELEM:
				/* Pretend string array elements are keys, see jsonb.h */
				entries[i++] = make_scalar_key(&v, (v.type == jbvString));
				break;
			case WJB_VALUE:
				entries[i++] = make_scalar_key(&v, false);
				break;
			default:
				/* we can ignore structural items */
				break;
		}
	}

	*nentries = i;

	PG_RETURN_POINTER(entries);
}
Datum
gin_extract_jsonb(PG_FUNCTION_ARGS)
{
	Jsonb	   *jb = (Jsonb *) PG_GETARG_JSONB_P(0);
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	int			total = JB_ROOT_COUNT(jb);
	JsonbIterator *it;
	JsonbValue	v;
	JsonbIteratorToken r;
	GinEntries	entries;

	/* If the root level is empty, we certainly have no keys */
	if (total == 0)
	{
		*nentries = 0;
		PG_RETURN_POINTER(NULL);
	}

	/* Otherwise, use 2 * root count as initial estimate of result size */
	init_gin_entries(&entries, 2 * total);

	it = JsonbIteratorInit(&jb->root);

	while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
	{
		switch (r)
		{
			case WJB_KEY:
				add_gin_entry(&entries, make_scalar_key(&v, true));
				break;
			case WJB_ELEM:
				/* Pretend string array elements are keys, see jsonb.h */
				add_gin_entry(&entries, make_scalar_key(&v, v.type == jbvString));
				break;
			case WJB_VALUE:
				add_gin_entry(&entries, make_scalar_key(&v, false));
				break;
			default:
				/* we can ignore structural items */
				break;
		}
	}

	*nentries = entries.count;

	PG_RETURN_POINTER(entries.buf);
}
Datum
gin_extract_jsonb(PG_FUNCTION_ARGS)
{
	Jsonb	   *jb = (Jsonb *) PG_GETARG_JSONB(0);
	int32	   *nentries = (int32 *) PG_GETARG_POINTER(1);
	Datum	   *entries = NULL;
	int			total = 2 * JB_ROOT_COUNT(jb);
	int			i = 0,
				r;
	JsonbIterator *it;
	JsonbValue	v;

	if (total == 0)
	{
		*nentries = 0;
		PG_RETURN_POINTER(NULL);
	}

	entries = (Datum *) palloc(sizeof(Datum) * total);

	it = JsonbIteratorInit(VARDATA(jb));

	while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
	{
		if (i >= total)
		{
			total *= 2;
			entries = (Datum *) repalloc(entries, sizeof(Datum) * total);
		}

		/*
		 * Serialize keys and elements equivalently,  but only when elements
		 * are Jsonb strings.  Otherwise, serialize elements as values.  Array
		 * elements are indexed as keys, for the benefit of
		 * JsonbExistsStrategyNumber.  Our definition of existence does not
		 * allow for checking the existence of a non-jbvString element (just
		 * like the definition of the underlying operator), because the
		 * operator takes a text rhs argument (which is taken as a proxy for an
		 * equivalent Jsonb string).
		 *
		 * The way existence is represented does not preclude an alternative
		 * existence operator, that takes as its rhs value an arbitrarily
		 * internally-typed Jsonb.  The only reason that isn't the case here is
		 * that the existence operator is only really intended to determine if
		 * an object has a certain key (object pair keys are of course
		 * invariably strings), which is extended to jsonb arrays.  You could
		 * think of the default Jsonb definition of existence as being
		 * equivalent to a definition where all types of scalar array elements
		 * are keys that we can check the existence of, while just forbidding
		 * non-string notation.  This inflexibility prevents the user from
		 * having to qualify that the rhs string is a raw scalar string (that
		 * is, naturally no internal string quoting in required for the text
		 * argument), and allows us to not set the reset flag for
		 * JsonbExistsStrategyNumber, since we know that keys are strings for
		 * both objects and arrays, and don't have to further account for type
		 * mismatch.  Not having to set the reset flag makes it less than
		 * tempting to tighten up the definition of existence to preclude array
		 * elements entirely, which would arguably be a simpler alternative.
		 * In any case the infrastructure used to implement the existence
		 * operator could trivially support this hypothetical, slightly
		 * distinct definition of existence.
		 */
		switch (r)
		{
			case WJB_KEY:
				/* Serialize key separately, for existence strategies */
				entries[i++] = PointerGetDatum(make_scalar_key(&v, JKEYELEM));
				break;
			case WJB_ELEM:
				if (v.type == jbvString)
					entries[i++] = PointerGetDatum(make_scalar_key(&v, JKEYELEM));
				else
					entries[i++] = PointerGetDatum(make_scalar_key(&v, JVAL));
				break;
			case WJB_VALUE:
				entries[i++] = PointerGetDatum(make_scalar_key(&v, JVAL));
				break;
			default:
				continue;
		}
	}

	*nentries = i;

	PG_RETURN_POINTER(entries);
}
static JsonPathGinNode *
make_jsp_entry_node_scalar(JsonbValue *scalar, bool iskey)
{
	return make_jsp_entry_node(make_scalar_key(scalar, iskey));
}