in src/backend/utils/adt/agtype_util.c [1022:1167]
agtype_iterator_token agtype_iterator_next(agtype_iterator **it,
agtype_value *val, bool skip_nested)
{
if (*it == NULL)
return WAGT_DONE;
/*
* When stepping into a nested container, we jump back here to start
* processing the child. We will not recurse further in one call, because
* processing the child will always begin in AGTI_ARRAY_START or
* AGTI_OBJECT_START state.
*/
recurse:
switch ((*it)->state)
{
case AGTI_ARRAY_START:
/* Set v to array on first array call */
val->type = AGTV_ARRAY;
val->val.array.num_elems = (*it)->num_elems;
/*
* v->val.array.elems is not actually set, because we aren't doing
* a full conversion
*/
val->val.array.raw_scalar = (*it)->is_scalar;
(*it)->curr_index = 0;
(*it)->curr_data_offset = 0;
(*it)->curr_value_offset = 0; /* not actually used */
/* Set state for next call */
(*it)->state = AGTI_ARRAY_ELEM;
return WAGT_BEGIN_ARRAY;
case AGTI_ARRAY_ELEM:
if ((*it)->curr_index >= (*it)->num_elems)
{
/*
* All elements within array already processed. Report this
* to caller, and give it back original parent iterator (which
* independently tracks iteration progress at its level of
* nesting).
*/
*it = free_and_get_parent(*it);
return WAGT_END_ARRAY;
}
fill_agtype_value((*it)->container, (*it)->curr_index,
(*it)->data_proper, (*it)->curr_data_offset, val);
AGTE_ADVANCE_OFFSET((*it)->curr_data_offset,
(*it)->children[(*it)->curr_index]);
(*it)->curr_index++;
if (!IS_A_AGTYPE_SCALAR(val) && !skip_nested)
{
/* Recurse into container. */
*it = iterator_from_container(val->val.binary.data, *it);
goto recurse;
}
else
{
/*
* Scalar item in array, or a container and caller didn't want
* us to recurse into it.
*/
return WAGT_ELEM;
}
case AGTI_OBJECT_START:
/* Set v to object on first object call */
val->type = AGTV_OBJECT;
val->val.object.num_pairs = (*it)->num_elems;
/*
* v->val.object.pairs is not actually set, because we aren't
* doing a full conversion
*/
(*it)->curr_index = 0;
(*it)->curr_data_offset = 0;
(*it)->curr_value_offset = get_agtype_offset((*it)->container,
(*it)->num_elems);
/* Set state for next call */
(*it)->state = AGTI_OBJECT_KEY;
return WAGT_BEGIN_OBJECT;
case AGTI_OBJECT_KEY:
if ((*it)->curr_index >= (*it)->num_elems)
{
/*
* All pairs within object already processed. Report this to
* caller, and give it back original containing iterator
* (which independently tracks iteration progress at its level
* of nesting).
*/
*it = free_and_get_parent(*it);
return WAGT_END_OBJECT;
}
else
{
/* Return key of a key/value pair. */
fill_agtype_value((*it)->container, (*it)->curr_index,
(*it)->data_proper, (*it)->curr_data_offset,
val);
if (val->type != AGTV_STRING)
ereport(ERROR,
(errmsg("unexpected agtype type as object key %d",
val->type)));
/* Set state for next call */
(*it)->state = AGTI_OBJECT_VALUE;
return WAGT_KEY;
}
case AGTI_OBJECT_VALUE:
/* Set state for next call */
(*it)->state = AGTI_OBJECT_KEY;
fill_agtype_value((*it)->container,
(*it)->curr_index + (*it)->num_elems,
(*it)->data_proper, (*it)->curr_value_offset, val);
AGTE_ADVANCE_OFFSET((*it)->curr_data_offset,
(*it)->children[(*it)->curr_index]);
AGTE_ADVANCE_OFFSET(
(*it)->curr_value_offset,
(*it)->children[(*it)->curr_index + (*it)->num_elems]);
(*it)->curr_index++;
/*
* Value may be a container, in which case we recurse with new,
* child iterator (unless the caller asked not to, by passing
* skip_nested).
*/
if (!IS_A_AGTYPE_SCALAR(val) && !skip_nested)
{
*it = iterator_from_container(val->val.binary.data, *it);
goto recurse;
}
else
{
return WAGT_VALUE;
}
}
ereport(ERROR, (errmsg("invalid iterator state %d", (*it)->state)));
return -1;
}