Datum gin_extract_agtype_query()

in src/backend/utils/adt/agtype_gin.c [181:276]


Datum gin_extract_agtype_query(PG_FUNCTION_ARGS)
{
    int32 *nentries;
    StrategyNumber strategy;
    int32 *searchMode;
    Datum *entries;

    if (PG_ARGISNULL(0) || PG_ARGISNULL(1) ||
        PG_ARGISNULL(2) || PG_ARGISNULL(6))
    {
        PG_RETURN_NULL();
    }

    nentries = (int32 *) PG_GETARG_POINTER(1);
    strategy = PG_GETARG_UINT16(2);
    searchMode = (int32 *) PG_GETARG_POINTER(6);

    if (strategy == AGTYPE_CONTAINS_STRATEGY_NUMBER ||
        strategy == AGTYPE_CONTAINS_TOP_LEVEL_STRATEGY_NUMBER)
    {
        /* Query is a agtype, so just apply gin_extract_agtype... */
        entries = (Datum *)
            DatumGetPointer(DirectFunctionCall2(gin_extract_agtype,
                                                PG_GETARG_DATUM(0),
                                                PointerGetDatum(nentries)));
        /* ...although "contains {}" requires a full index scan */
        if (*nentries == 0)
        {
            *searchMode = GIN_SEARCH_MODE_ALL;
        }
    }
    else if (strategy == AGTYPE_EXISTS_STRATEGY_NUMBER)
    {
        /* Query is a text string, which we treat as a key */
        text *query = PG_GETARG_TEXT_PP(0);

        *nentries = 1;
        entries = (Datum *)palloc(sizeof(Datum));
        entries[0] = make_text_key(AGT_GIN_FLAG_KEY, VARDATA_ANY(query),
                                   VARSIZE_ANY_EXHDR(query));
    }
    else if (strategy == AGTYPE_EXISTS_ANY_STRATEGY_NUMBER ||
             strategy == AGTYPE_EXISTS_ALL_STRATEGY_NUMBER)
    {
        /* Query is a text array; each element is treated as a key */
        agtype *agt = AG_GET_ARG_AGTYPE_P(0);
        agtype_iterator *it = NULL;
        agtype_value elem;
        agtype_iterator_token itok;
        int key_count = AGTYPE_CONTAINER_SIZE(&agt->root);
        int index = 0;

        if (AGTYPE_CONTAINER_IS_SCALAR(&agt->root) ||
            !AGTYPE_CONTAINER_IS_ARRAY(&agt->root))
        {
            elog(ERROR, "GIN query requires an agtype array");
        }

        entries = (Datum *) palloc(sizeof(Datum) * key_count);
        it = agtype_iterator_init(&agt->root);

        /* it should be WAGT_BEGIN_ARRAY */
        itok = agtype_iterator_next(&it, &elem, true);
        if (itok != WAGT_BEGIN_ARRAY)
        {
            elog(ERROR, "unexpected iterator token: %d", itok);
        }

        while (WAGT_END_ARRAY != agtype_iterator_next(&it, &elem, true))
        {
            if (elem.type != AGTV_STRING)
            {
                elog(ERROR, "unsupport agtype for GIN lookup: %d", elem.type);
            }

            entries[index++] = make_text_key(AGT_GIN_FLAG_KEY,
                                         elem.val.string.val,
                                         elem.val.string.len);
        }

        *nentries = index;

        /* ExistsAll with no keys should match everything */
        if (index == 0 && strategy == AGTYPE_EXISTS_ALL_STRATEGY_NUMBER)
        {
            *searchMode = GIN_SEARCH_MODE_ALL;
        }
    }
    else
    {
        elog(ERROR, "unrecognized strategy number: %d", strategy);
        entries = NULL;            /* keep compiler quiet */
    }

    PG_RETURN_POINTER(entries);
}