SRF ok, now composite
authorCédric Villemain <cedric.villemain.debian@gmail.com>
Sun, 9 Aug 2009 20:34:44 +0000 (22:34 +0200)
committerCédric Villemain <cedric.villemain.debian@gmail.com>
Sun, 9 Aug 2009 20:34:44 +0000 (22:34 +0200)
pgfincore.c
pgfincore_84.sql.in

index f93e4b04f51d5a286b5735154b8dc8b2bdb8a715..b256cf8f689f5848f81b0fcc1ca8bc9aa64feb07 100644 (file)
@@ -37,6 +37,7 @@
 #include "catalog/namespace.h" /* makeRangeVarFromNameList */
 #include "utils/builtins.h" /* textToQualifiedNameList */
 #include "utils/rel.h" /* Relation */
+#include "funcapi.h" /* SRF */
 
 
 #ifdef PG_VERSION_NUM
@@ -51,117 +52,94 @@ PG_MODULE_MAGIC;
 /* } */
 
 
-#if PG_MAJOR_VERSION > 803
-static int64 pgfincore_all(RelFileNode *rfn, ForkNumber forknum);
 Datum pgfincore(PG_FUNCTION_ARGS); /* Prototype */
-PG_FUNCTION_INFO_V1(pgfincore);
-#else
-static int64 pgfincore_all(RelFileNode *rfn);
-Datum pgfincore_name(PG_FUNCTION_ARGS); /* Prototype */
-Datum pgfincore_oid(PG_FUNCTION_ARGS); /* Prototype */
-PG_FUNCTION_INFO_V1(pgfincore_name);
-PG_FUNCTION_INFO_V1(pgfincore_oid);
-#endif
 static int64 pgfincore_file(char *filename);
 
-
+typedef struct
+{
+  Relation rel;                                /* the relation */
+  int64 segcount;      /* the segment current number */
+  char *relationpath;          /* the relation path */
+} pgfincore_fctx;
 
 /* fincore -
  */
-#if PG_MAJOR_VERSION > 803
-Datum 
-pgfincore(PG_FUNCTION_ARGS)
+PG_FUNCTION_INFO_V1(pgfincore);
+Datum pgfincore(PG_FUNCTION_ARGS)
 {
+  FuncCallContext *funcctx;
+  MemoryContext oldcontext;
+  pgfincore_fctx *fctx;
+
   Oid          relOid = PG_GETARG_OID(0);
   text         *forkName = PG_GETARG_TEXT_P(1);
   Relation     rel;
-  int64                size;
-
-  rel = relation_open(relOid, AccessShareLock);
+  char         *relationpath;
+  char         pathname[MAXPGPATH];
+  int64 segcount;
+  int64 result    = 0;
+
+  /* stuff done only on the first call of the function */
+  if (SRF_IS_FIRSTCALL())
+  {
+       /* 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);
+
+       /* allocate memory for user context */
+       fctx = (pgfincore_fctx *) palloc(sizeof(pgfincore_fctx));
+
+       /*
+       * Use fctx to keep track of upper and lower bounds from call to call.
+       * It will also be used to carry over the spare value we get from the
+       * Box-Muller algorithm so that we only actually calculate a new value
+       * every other call.
+       */
+       fctx->rel = relation_open(relOid, AccessShareLock);
+       fctx->relationpath = relpath(fctx->rel->rd_node, forkname_to_number(text_to_cstring(forkName)));
+       fctx->segcount = 0;
+//     elog(DEBUG2, "1st call : %s",fctx->relationpath);
+       funcctx->user_fctx = fctx;
+
+       MemoryContextSwitchTo(oldcontext);
+  }
 
-  size = pgfincore_all(&(rel->rd_node), forkname_to_number(text_to_cstring(forkName)));
+  /* stuff done on every call of the function */
+  funcctx = SRF_PERCALL_SETUP();
+  segcount = fctx->segcount;
+  relationpath = fctx->relationpath;
+  rel = fctx->rel;
 
-  relation_close(rel, AccessShareLock);
+  // result
+  if (segcount == 0)
+       snprintf(pathname, MAXPGPATH, "%s", relationpath);
+  else
+       snprintf(pathname, MAXPGPATH, "%s.%u", relationpath, segcount);
 
-  PG_RETURN_INT64(size);
-}
-#else
-Datum 
-pgfincore_oid(PG_FUNCTION_ARGS)
-{
-       Oid                     relOid = PG_GETARG_OID(0);
-       Relation        rel;
-       int64           size = 0;
-
-       rel = relation_open(relOid, AccessShareLock);
-
-       size = pgfincore_all(&(rel->rd_node));
+  result = pgfincore_file(pathname);
+  elog(DEBUG2, "pgfincore : %lu",(unsigned long)result);
 
+  /* do when there is no more left */
+  if (result == -1) {
        relation_close(rel, AccessShareLock);
-
-       PG_RETURN_INT64(size);
+       SRF_RETURN_DONE(funcctx);
+  }
+  /* or send the result */
+  else {
+       fctx->segcount++;
+       SRF_RETURN_NEXT(funcctx, Int64GetDatum(result));
+  }
 }
 
-Datum pgfincore_name(PG_FUNCTION_ARGS) {
-       text       *relname = PG_GETARG_TEXT_P(0);
-       RangeVar   *relrv;
-       Relation        rel;
-       int64           size = 0;
-
-       relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
-       rel = relation_openrv(relrv, AccessShareLock);
-
-       size = pgfincore_all(&(rel->rd_node));
 
-       relation_close(rel, AccessShareLock);
-
-       PG_RETURN_INT64(size);
-}
-#endif
 
-// calculate number of block in memory
-static int64
-#if PG_MAJOR_VERSION > 803
-pgfincore_all(RelFileNode *rfn, ForkNumber forknum)
-#else
-pgfincore_all(RelFileNode *rfn)
-#endif
-{
-       int64           totalsize = 0;
-       int64           result    = 0;
-       char       *relationpath;
-       char            pathname[MAXPGPATH];
-       unsigned int segcount = 0;
-
-#if PG_MAJOR_VERSION > 803
-       relationpath = relpath(*rfn, forknum);
-#else
-       relationpath = relpath(*rfn);
-#endif
-       for (segcount = 0;; segcount++)
-       {
-               if (segcount == 0)
-                       snprintf(pathname, MAXPGPATH, "%s",
-                                        relationpath);
-               else
-                       snprintf(pathname, MAXPGPATH, "%s.%u",
-                                        relationpath, segcount);
-
-               result = pgfincore_file(pathname);
-               elog(DEBUG2, "pgfincore : %lu",(unsigned long)result);
-
-               if (result == -1)
-                 break;
-               totalsize += result;
-       }
-       elog(DEBUG2, "pgfincore2 : %lu",(unsigned long)totalsize);
-
-       return totalsize;
-}
 
 
-static int64
-pgfincore_file(char *filename) {
+static int64 pgfincore_file(char *filename) {
   // our counter for block in memory
   int64     n=0;
   int64     cut=0;
index b3b9e1906c02441ef5e4089e37d27699880d3704..3b6359a7f812470ef70ca8dcdc8477d01a6fdc0b 100644 (file)
@@ -1,11 +1,11 @@
 SET search_path = public;
 
 CREATE OR REPLACE FUNCTION pgfincore(regclass, text)
-RETURNS bigint
+RETURNS setof bigint
 AS 'MODULE_PATHNAME'
 LANGUAGE C;
 
 CREATE OR REPLACE FUNCTION pgfincore(regclass)
-RETURNS bigint
+RETURNS setof bigint
 AS 'SELECT pgfincore($1, ''main'')'
 LANGUAGE SQL;