#include "postgres.h"

#include "catalog/pg_type.h"
#include "fmgr.h"
#include "funcapi.h"
#include "executor/spi.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(srfmatpoc);

Datum srfmatpoc(PG_FUNCTION_ARGS) {
  ReturnSetInfo   *rsinfo;
  Tuplestorestate *tupstore;
  TupleDesc        tupdesc;
  MemoryContext    per_query_ctx;
  MemoryContext    oldcontext;
  text            *t,
                  *cpyt;
  int              ret,
                   c,
                   i;

  rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;

  if ((ret = SPI_connect()) < 0)
    elog(ERROR, "srfmatpoc: SPI_connect returned %d", ret);

  tupdesc = CreateTemplateTupleDesc(2, false);
  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "t", TEXTOID, -1, 0);
  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "count", INT4OID, -1, 0);

  oldcontext = MemoryContextSwitchTo(per_query_ctx);
  tupdesc = CreateTupleDescCopy(tupdesc);
  tupstore =
    tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
                          false, work_mem);
  MemoryContextSwitchTo(oldcontext);

  t = (text *)PG_GETARG_TEXT_PP(0);
  c = (uint32)PG_GETARG_INT32(1);

  for(i=0; i<c; ++i) {
    HeapTuple  tuple;
    Datum      values[2];
    bool       nulls[2];

    cpyt = (text *)palloc(VARHDRSZ + VARSIZE_ANY_EXHDR(t));
    SET_VARSIZE(cpyt, VARHDRSZ + VARSIZE_ANY_EXHDR(t));
    memcpy((void *)VARDATA(cpyt), (void *)VARDATA(t), VARSIZE_ANY_EXHDR(t));

    values[0] = PointerGetDatum(cpyt);
    values[1] = Int32GetDatum(i);
    nulls[0] = false;
    nulls[1] = false;

    tuple = heap_form_tuple(tupdesc, values, nulls);
    tuplestore_puttuple(tupstore, tuple);
    heap_freetuple(tuple);
  }

  rsinfo->returnMode = SFRM_Materialize;
  rsinfo->setResult = tupstore;
  rsinfo->setDesc = tupdesc;

  SPI_finish();

  return (Datum) 0;
}
