Datum age_vle()

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);
    }
}