in src/backend/utils/adt/age_vle.c [1708:1873]
Datum age_vle(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
VLE_local_context *vlelctx = NULL;
bool found_a_path = false;
bool done = false;
bool is_zero_bound = false;
MemoryContext oldctx;
/* Initialization for the first call to the SRF */
if (SRF_IS_FIRSTCALL())
{
/* all of these arguments need to be non NULL */
if (PG_ARGISNULL(0) || /* graph name */
PG_ARGISNULL(3) || /* edge prototype */
PG_ARGISNULL(6)) /* direction */
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("age_vle: invalid NULL argument passed")));
}
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/* build the local vle context */
vlelctx = build_local_vle_context(fcinfo, funcctx);
/*
* Point the function call context's user pointer to the local VLE
* context just created
*/
funcctx->user_fctx = vlelctx;
/* if we are starting from zero [*0..x] flag it */
if (vlelctx->lidx == 0)
{
is_zero_bound = true;
done = true;
}
}
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
/* restore our VLE local context */
vlelctx = (VLE_local_context *)funcctx->user_fctx;
/*
* All work done in dfs_find_a_path needs to be done in a context that
* survives multiple SRF calls. So switch to the appropriate context.
*/
oldctx = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
while (done == false)
{
/* find one path based on specific input */
switch (vlelctx->path_function)
{
case VLE_FUNCTION_PATHS_TO:
case VLE_FUNCTION_PATHS_BETWEEN:
found_a_path = dfs_find_a_path_between(vlelctx);
break;
case VLE_FUNCTION_PATHS_ALL:
case VLE_FUNCTION_PATHS_FROM:
found_a_path = dfs_find_a_path_from(vlelctx);
break;
default:
found_a_path = false;
break;
}
/* if we found a path, or are done, flag it so we can output the data */
if (found_a_path == true ||
(found_a_path == false && vlelctx->next_vertex == NULL) ||
(found_a_path == false &&
(vlelctx->path_function == VLE_FUNCTION_PATHS_BETWEEN ||
vlelctx->path_function == VLE_FUNCTION_PATHS_FROM)))
{
done = true;
}
/* if we need to fetch a new vertex and rerun the find */
else if ((vlelctx->path_function == VLE_FUNCTION_PATHS_ALL) ||
(vlelctx->path_function == VLE_FUNCTION_PATHS_TO))
{
/* get the next start vertex id */
vlelctx->vsid = get_graphid(vlelctx->next_vertex);
/* increment to the next vertex */
vlelctx->next_vertex = next_GraphIdNode(vlelctx->next_vertex);
/* load in the starting edge(s) */
load_initial_dfs_stacks(vlelctx);
/* if we are starting from zero [*0..x] flag it */
if (vlelctx->lidx == 0)
{
is_zero_bound = true;
done = true;
}
/* otherwise we need to loop back around */
else
{
done = false;
}
}
/* we shouldn't get here */
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("age_vle() invalid path function")));
}
}
/* switch back to a more volatile context */
MemoryContextSwitchTo(oldctx);
/*
* If we find a path, we need to convert the path_stack into a list that
* the outside world can use.
*/
if (found_a_path || is_zero_bound)
{
VLE_path_container *vpc = NULL;
/* if this isn't the zero boundary case generate a normal vpc */
if (!is_zero_bound)
{
/* the path_stack should have something in it if we have a path */
Assert(vlelctx->dfs_path_stack > 0);
/*
* Build the graphid array into a VLE_path_container from the
* path_stack. This will also correct for the path_stack being last
* in, first out.
*/
vpc = build_VLE_path_container(vlelctx);
}
/* otherwise, this is the zero boundary case [*0..x] */
else
{
vpc = build_VLE_zero_container(vlelctx);
}
/* return the result and signal that the function is not yet done */
SRF_RETURN_NEXT(funcctx, PointerGetDatum(vpc));
}
/* otherwise, we are done and we need to cleanup and signal done */
else
{
/* mark local context as clean */
vlelctx->is_dirty = false;
/* free the local context, if we aren't caching it */
if (vlelctx->use_cache == false)
{
free_VLE_local_context(vlelctx);
}
/* signal that we are done */
SRF_RETURN_DONE(funcctx);
}
}