blob: f17c9e0f15d7532a107e17747b6c9c9e684d3a3f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "postgres.h"
#include "access/hd_work_mgr.h"
#include "catalog/external/externalmd.h"
#include "fmgr.h"
#include "funcapi.h"
#include "utils/builtins.h"
#include "utils/guc.h"
typedef struct ItemContext
{
ListCell *current_item;
ListCell *current_field;
} ItemContext;
static ListCell* pxf_item_fields_enum_start(text *profile, text *pattern);
static ItemContext* pxf_item_fields_enum_next(ItemContext *item_context);
static void pxf_item_fields_enum_end(void);
static ListCell*
pxf_item_fields_enum_start(text *profile, text *pattern)
{
List *items = NIL;
char *profile_cstr = text_to_cstring(profile);
char *pattern_cstr = text_to_cstring(pattern);
items = get_pxf_item_metadata(profile_cstr, pattern_cstr, InvalidOid);
if (items == NIL)
return NULL;
return list_head(items);
}
static ItemContext*
pxf_item_fields_enum_next(ItemContext *item_context)
{
/* first time call */
if (item_context->current_item && !item_context->current_field)
item_context->current_field = list_head(((PxfItem *) lfirst(item_context->current_item))->fields);
/* next field for the same item */
else if (lnext(item_context->current_field))
item_context->current_field = lnext(item_context->current_field);
/* next item */
else if (item_context->current_item && lnext(item_context->current_item))
{
item_context->current_item = lnext(item_context->current_item);
item_context->current_field = list_head(((PxfItem *) lfirst(item_context->current_item))->fields);
/* no items, no fields left */
} else
item_context = NULL;
return item_context;
}
static void pxf_item_fields_enum_end(void)
{
/* cleanup */
}
Datum pxf_get_item_fields(PG_FUNCTION_ARGS)
{
MemoryContext oldcontext;
FuncCallContext *funcctx;
HeapTuple tuple;
Datum result;
Datum values[5];
bool nulls[5];
ItemContext *item_context;
text *profile = PG_GETARG_TEXT_P(0);
text *pattern = PG_GETARG_TEXT_P(1);
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
{
TupleDesc tupdesc;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/*
* switch to memory context appropriate for multiple function calls
*/
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* initialize item fileds metadata scanning code */
ListCell *items_cell = pxf_item_fields_enum_start(profile, pattern);
if (items_cell == NULL)
{
pxf_item_fields_enum_end();
funcctx->user_fctx = NULL;
SRF_RETURN_DONE(funcctx);
}
item_context = (ItemContext *) palloc0(sizeof(ItemContext));
item_context->current_item = items_cell;
funcctx->user_fctx = (void *) item_context;
/*
* build tupdesc for result tuples. This must match this function's
* pg_proc entry!
*/
tupdesc = CreateTemplateTupleDesc(5, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "path",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "itemname",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "fieldname",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "fieldtype",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "sourcefieldtype",
TEXTOID, -1, 0);
funcctx->tuple_desc = BlessTupleDesc(tupdesc);
MemoryContextSwitchTo(oldcontext);
}
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
item_context = (ItemContext *) funcctx->user_fctx;
/* search for next entry to display */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
item_context = pxf_item_fields_enum_next(item_context);
;
funcctx->user_fctx = item_context;
MemoryContextSwitchTo(oldcontext);
if (!item_context)
{
pxf_item_fields_enum_end();
funcctx->user_fctx = NULL;
SRF_RETURN_DONE(funcctx);
}
PxfItem *item = (PxfItem *) lfirst(
item_context->current_item);
PxfField *field = (PxfField *) lfirst(
item_context->current_field);
MemSet(nulls, 0, sizeof(nulls));
values[0] = CStringGetTextDatum(item->path);
values[1] = CStringGetTextDatum(item->name);
values[2] = CStringGetTextDatum(field->name);
values[3] = CStringGetTextDatum(field->type);
values[4] = CStringGetTextDatum(field->sourceType);
tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
result = HeapTupleGetDatum(tuple);
SRF_RETURN_NEXT(funcctx, result);
}