On Thu, Aug 11, 2005 at 02:26:16PM -0400, Bruce Momjian wrote:
> Alvaro Herrera wrote:

> > Interesting.  I wonder why the function is not defined instead with OUT
> > parameters.  That way you don't have to declare the record at execution
> > time.  See my patch to pgstattuple for an example.
> 
> Uh, where is that patch?  I can't find it.

Hmm, seems it never made it to the list, I can't find it in the
archives either.  Here it is.

-- 
Alvaro Herrera (<alvherre[a]alvh.no-ip.org>)
"¿Qué importan los años?  Lo que realmente importa es comprobar que
a fin de cuentas la mejor edad de la vida es estar vivo"  (Mafalda)
Index: pgstattuple.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/contrib/pgstattuple/pgstattuple.c,v
retrieving revision 1.19
diff -c -r1.19 pgstattuple.c
*** pgstattuple.c       30 May 2005 23:09:06 -0000      1.19
--- pgstattuple.c       28 Jul 2005 14:48:44 -0000
***************
*** 52,58 ****
   */
  
  #define NCOLUMNS 9
- #define NCHARS 32
  
  Datum
  pgstattuple(PG_FUNCTION_ARGS)
--- 52,57 ----
***************
*** 105,117 ****
        uint64          dead_tuple_len = 0;
        uint64          tuple_count = 0;
        uint64          dead_tuple_count = 0;
!       double          tuple_percent;
!       double          dead_tuple_percent;
        uint64          free_space = 0; /* free/reusable space in bytes */
!       double          free_percent;   /* free/reusable space in % */
        TupleDesc       tupdesc;
!       AttInMetadata *attinmeta;
!       char      **values;
        int                     i;
        Datum           result;
  
--- 104,116 ----
        uint64          dead_tuple_len = 0;
        uint64          tuple_count = 0;
        uint64          dead_tuple_count = 0;
!       float8          tuple_percent;
!       float8          dead_tuple_percent;
        uint64          free_space = 0; /* free/reusable space in bytes */
!       float8          free_percent;   /* free/reusable space in % */
        TupleDesc       tupdesc;
!       Datum      *values;
!       bool       *nulls;
        int                     i;
        Datum           result;
  
***************
*** 122,133 ****
        /* make sure we have a persistent copy of the tupdesc */
        tupdesc = CreateTupleDescCopy(tupdesc);
  
-       /*
-        * Generate attribute metadata needed later to produce tuples from raw
-        * C strings
-        */
-       attinmeta = TupleDescGetAttInMetadata(tupdesc);
- 
        scan = heap_beginscan(rel, SnapshotAny, 0, NULL);
  
        nblocks = scan->rs_nblocks; /* # blocks to be scanned */
--- 121,126 ----
***************
*** 191,230 ****
        }
        else
        {
!               tuple_percent = (double) tuple_len *100.0 / table_len;
!               dead_tuple_percent = (double) dead_tuple_len *100.0 / table_len;
!               free_percent = (double) free_space *100.0 / table_len;
        }
  
        /*
!        * Prepare a values array for constructing the tuple. This should be
!        * an array of C strings which will be processed later by the
!        * appropriate "in" functions.
         */
!       values = (char **) palloc(NCOLUMNS * sizeof(char *));
!       for (i = 0; i < NCOLUMNS; i++)
!               values[i] = (char *) palloc(NCHARS * sizeof(char));
        i = 0;
!       snprintf(values[i++], NCHARS, INT64_FORMAT, table_len);
!       snprintf(values[i++], NCHARS, INT64_FORMAT, tuple_count);
!       snprintf(values[i++], NCHARS, INT64_FORMAT, tuple_len);
!       snprintf(values[i++], NCHARS, "%.2f", tuple_percent);
!       snprintf(values[i++], NCHARS, INT64_FORMAT, dead_tuple_count);
!       snprintf(values[i++], NCHARS, INT64_FORMAT, dead_tuple_len);
!       snprintf(values[i++], NCHARS, "%.2f", dead_tuple_percent);
!       snprintf(values[i++], NCHARS, INT64_FORMAT, free_space);
!       snprintf(values[i++], NCHARS, "%.2f", free_percent);
  
        /* build a tuple */
!       tuple = BuildTupleFromCStrings(attinmeta, values);
  
        /* make the tuple into a datum */
        result = HeapTupleGetDatum(tuple);
  
        /* Clean up */
-       for (i = 0; i < NCOLUMNS; i++)
-               pfree(values[i]);
        pfree(values);
  
!       return (result);
  }
--- 184,220 ----
        }
        else
        {
!               tuple_percent = (float8) tuple_len *100.0 / table_len;
!               dead_tuple_percent = (float8) dead_tuple_len *100.0 / table_len;
!               free_percent = (float8) free_space *100.0 / table_len;
        }
  
        /*
!        * Prepare a values array for constructing the tuple.
         */
!       values = (Datum *) palloc(NCOLUMNS * sizeof(Datum));
!       nulls = (bool *) palloc0(NCOLUMNS * sizeof(bool));
        i = 0;
! 
!       values[i++] = Int64GetDatum(table_len);
!       values[i++] = Int64GetDatum(tuple_count);
!       values[i++] = Int64GetDatum(tuple_len);
!       values[i++] = Float8GetDatum(tuple_percent);
!       values[i++] = Int64GetDatum(dead_tuple_count);
!       values[i++] = Int64GetDatum(dead_tuple_len);
!       values[i++] = Float8GetDatum(dead_tuple_percent);
!       values[i++] = Int64GetDatum(free_space);
!       values[i++] = Float8GetDatum(free_percent);
  
        /* build a tuple */
!       tuple = heap_form_tuple(tupdesc, values, nulls);
  
        /* make the tuple into a datum */
        result = HeapTupleGetDatum(tuple);
  
        /* Clean up */
        pfree(values);
+       pfree(nulls);
  
!       return result;
  }
Index: pgstattuple.sql.in
===================================================================
RCS file: /home/alvherre/cvs/pgsql/contrib/pgstattuple/pgstattuple.sql.in,v
retrieving revision 1.9
diff -c -r1.9 pgstattuple.sql.in
*** pgstattuple.sql.in  1 Oct 2004 15:43:40 -0000       1.9
--- pgstattuple.sql.in  28 Jul 2005 14:45:50 -0000
***************
*** 1,24 ****
  -- Adjust this setting to control where the objects get created.
  SET search_path = public;
  
! CREATE TYPE pgstattuple_type AS (
!       table_len BIGINT,               -- physical table length in bytes
!       tuple_count BIGINT,             -- number of live tuples
!       tuple_len BIGINT,               -- total tuples length in bytes
!       tuple_percent FLOAT,            -- live tuples in %
!       dead_tuple_count BIGINT,        -- number of dead tuples
!       dead_tuple_len BIGINT,          -- total dead tuples length in bytes
!       dead_tuple_percent FLOAT,       -- dead tuples in %
!       free_space BIGINT,              -- free space in bytes
!       free_percent FLOAT              -- free space in %
! );
! 
! CREATE OR REPLACE FUNCTION pgstattuple(text)
! RETURNS pgstattuple_type
  AS 'MODULE_PATHNAME', 'pgstattuple'
  LANGUAGE 'C' STRICT;
  
! CREATE OR REPLACE FUNCTION pgstattuple(oid)
! RETURNS pgstattuple_type
  AS 'MODULE_PATHNAME', 'pgstattuplebyid'
  LANGUAGE 'C' STRICT;
--- 1,32 ----
  -- Adjust this setting to control where the objects get created.
  SET search_path = public;
  
! CREATE OR REPLACE FUNCTION pgstattuple (
!       IN table_name TEXT,
!       OUT table_len BIGINT,
!       OUT tuple_count BIGINT,
!       OUT tuple_len BIGINT,
!       OUT tuple_percent FLOAT8,
!       OUT dead_tuple_count BIGINT,
!       OUT dead_tuple_len BIGINT,
!       OUT dead_tuple_percent FLOAT8,
!       OUT free_space BIGINT,
!       OUT free_percent FLOAT8
!       ) RETURNS RECORD
  AS 'MODULE_PATHNAME', 'pgstattuple'
  LANGUAGE 'C' STRICT;
  
! CREATE OR REPLACE FUNCTION pgstattuple (
!       IN table_oid OID,
!       OUT table_len BIGINT,
!       OUT tuple_count BIGINT,
!       OUT tuple_len BIGINT,
!       OUT tuple_percent FLOAT8,
!       OUT dead_tuple_count BIGINT,
!       OUT dead_tuple_len BIGINT,
!       OUT dead_tuple_percent FLOAT8,
!       OUT free_space BIGINT,
!       OUT free_percent FLOAT8
!       ) RETURNS RECORD
  AS 'MODULE_PATHNAME', 'pgstattuplebyid'
  LANGUAGE 'C' STRICT;
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Reply via email to