This is a multi-part message in MIME format.
------=_NextPart_000_0265_01C8A92E.5D5461A0
Content-Type: text/plain;
format=flowed;
charset="iso-8859-1";
reply-type=original
Content-Transfer-Encoding: 7bit
Hi all,
I am working on implementation of custom "C" SRF for our team. The SRF
uses
SFRM_ValuePerCall mode. I know that sometimes even in SFRM_ValuePerCall
mode
all the rows returned from SRF are "materialized" (for performing JOINs,
for
example). But it looks like even in cases when SELECT is very simple and
it's obvious that no more rows will be read from the SRF, SRF is being
iterated till it returns SRF_RETURN_DONE(...). So, in case when the SRF
returns 1000 rows but the SELECT is querying only the first one (with
LIMIT
1), all 1000 iterations will be performed and 999 rows will be created,
allocated, returned and thrown away.
Is there a way to avoid unnecessary calls of SRF in this case? Is it a
"feature"?
In the attachment you can find the simplest example of SRF function
working
in SFRM_ValuePerCall mode.
I have created it while researching the issue. After building it, use the
following SQLs:
-- this creates the test function
CREATE OR REPLACE FUNCTION vpc() RETURNS setof record
AS 'plbsh.dll', 'vpc' LANGUAGE 'C';
-- this returns 10 rows
SELECT * FROM vpc() AS T(a INT, b TEXT);
-- this returns 1 row, but performs 10 calls
SELECT * FROM vpc() AS T(a INT, b TEXT) LIMIT 1;
Regards,
Denis
------=_NextPart_000_0265_01C8A92E.5D5461A0
Content-Type: text/plain;
format=flowed;
name="vpc.c.txt";
reply-type=original
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="vpc.c.txt"
#include "executor/spi.h"
#include "fmgr.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "storage/ipc.h"
#include "utils/date.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
/*
CREATE OR REPLACE FUNCTION vpc() RETURNS setof record
AS 'plbsh.dll', 'vpc' LANGUAGE 'C';
SELECT * FROM vpc() AS T(a INT, b TEXT);
SELECT * FROM vpc() AS T(a INT, b TEXT) LIMIT 1;
*/
extern Datum vpc(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(vpc);
Datum vpc(PG_FUNCTION_ARGS)
{
ReturnSetInfo* rsinfo;
FuncCallContext *funcctx;
int current =3D 0;
rsinfo =3D (ReturnSetInfo*) fcinfo->resultinfo;
if (!rsinfo)
ere****t(ERROR, (errmsg("Invalid ReturnSetInfo in SRF")));
if (!(rsinfo->allowedModes & SFRM_ValuePerCall))
ere****t(ERROR, (errmsg("Function must sup****t returning a SETOF
composite=
type in SFRM_ValuePerCall mode")));
if (SRF_IS_FIRSTCALL())
{
MemoryContext oldcontext;
funcctx =3D SRF_FIRSTCALL_INIT();
oldcontext =3D MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
funcctx->attinmeta =3D TupleDescGetAttInMetadata(rsinfo->expectedDesc);
funcctx->user_fctx =3D (void*)(int*)palloc(sizeof(int));
*((int*)funcctx->user_fctx) =3D 0;
MemoryContextSwitchTo(oldcontext);
}
rsinfo->returnMode =3D SFRM_ValuePerCall;
rsinfo->setDesc =3D rsinfo->expectedDesc;
funcctx =3D SRF_PERCALL_SETUP();
current =3D *((int*)funcctx->user_fctx);
ere****t(WARNING, (errmsg("## Call#%d", current)));
if(current >=3D 10)
{
ere****t(WARNING, (errmsg("## Last Call")));
SRF_RETURN_DONE(funcctx);
}
else
{
char buffer[100];
char* values[2];
HeapTuple tuple;
Datum result;
sprintf(buffer, "%d", current++);
*((int*)funcctx->user_fctx) =3D current;
values[0] =3D buffer;
values[1] =3D buffer;
tuple =3D BuildTupleFromCStrings(funcctx->attinmeta, values);
result =3D TupleGetDatum(slot, tuple);
ere****t(WARNING, (errmsg("## (return)", current)));
SRF_RETURN_NEXT(funcctx, result);
}
}=
------=_NextPart_000_0265_01C8A92E.5D5461A0
Content-Type: text/plain
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0
--
Sent via pgsql-hackers mailing list (pgsql-hackers@[EMAIL PROTECTED]
)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
------=_NextPart_000_0265_01C8A92E.5D5461A0--


|