]> granicus.if.org Git - postgresql/commitdiff
Code review for standalone composite types, query-specified composite
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 29 Aug 2002 00:17:06 +0000 (00:17 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 29 Aug 2002 00:17:06 +0000 (00:17 +0000)
types, SRFs.  Not happy with memory management yet, but I'll commit these
other changes.

41 files changed:
contrib/dbsize/dbsize.c
doc/src/sgml/ref/create_type.sgml
doc/src/sgml/ref/select.sgml
doc/src/sgml/ref/select_into.sgml
doc/src/sgml/release.sgml
doc/src/sgml/xfunc.sgml
src/backend/access/common/tupdesc.c
src/backend/access/heap/heapam.c
src/backend/catalog/heap.c
src/backend/catalog/namespace.c
src/backend/catalog/pg_proc.c
src/backend/catalog/pg_type.c
src/backend/commands/comment.c
src/backend/commands/copy.c
src/backend/commands/explain.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/executor/execMain.c
src/backend/executor/execTuples.c
src/backend/executor/functions.c
src/backend/executor/nodeFunctionscan.c
src/backend/nodes/outfuncs.c
src/backend/parser/gram.y
src/backend/parser/parse_relation.c
src/backend/tcop/utility.c
src/backend/utils/adt/lockfuncs.c
src/backend/utils/adt/tid.c
src/backend/utils/cache/lsyscache.c
src/backend/utils/fmgr/funcapi.c
src/backend/utils/misc/guc.c
src/bin/pg_dump/common.c
src/bin/pg_dump/pg_dump.c
src/bin/psql/describe.c
src/include/catalog/pg_type.h
src/include/executor/executor.h
src/include/funcapi.h
src/include/nodes/execnodes.h
src/include/utils/builtins.h
src/include/utils/lsyscache.h
src/test/regress/expected/rangefuncs.out
src/test/regress/sql/rangefuncs.sql

index 0e5e63d1eee49f2687b58d693627cbb13599e0a2..8bc216bf7993c5588801b5697d599777e13e7ff4 100644 (file)
@@ -112,7 +112,7 @@ relation_size(PG_FUNCTION_ARGS)
 
        relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
                                                                                                                         "relation_size"));
-       relation = relation_openrv(relrv, AccessShareLock);
+       relation = heap_openrv(relrv, AccessShareLock);
 
        relnode = relation->rd_rel->relfilenode;
 
@@ -140,7 +140,7 @@ relation_size(PG_FUNCTION_ARGS)
                segcount++;
        }
 
-       relation_close(relation, AccessShareLock);
+       heap_close(relation, AccessShareLock);
 
        PG_RETURN_INT64(totalsize);
 }
index f100f4d87b5b7a185a6de4dde8e3bb08e400bdba..b2d454f129b19cae91de59bc5a06caf4c16b1b58 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.33 2002/08/23 00:33:24 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.34 2002/08/29 00:17:01 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -32,11 +32,7 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> ( INPUT = <rep
 )
 
 CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
-      ( <replaceable class="PARAMETER">column_definition_list</replaceable> )
-
-where <replaceable class="PARAMETER">column_definition_list</replaceable> can be:
-
-( <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] )
+    ( <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] )
   </synopsis>
   
   <refsect2 id="R2-SQL-CREATETYPE-1">
@@ -216,8 +212,12 @@ CREATE TYPE
    type names also must not conflict with table names in the same schema.)
   </para>
 
+  <refsect2>
+   <title>Base Types</title>
+
   <para>
-   The first form of <command>CREATE TYPE</command>  requires  the  
+   The first form of <command>CREATE TYPE</command> creates a new base type
+   (scalar type).  It  requires  the
    registration of two functions (using CREATE FUNCTION) before defining the
    type. The representation of a new base type is determined by
    <replaceable class="parameter">input_function</replaceable>, which
@@ -338,20 +338,27 @@ CREATE TYPE
    a row fit, but they will be kept in the main table preferentially over
    <literal>extended</literal> and <literal>external</literal> items.)
   </para>
+  </refsect2>
+
+  <refsect2>
+   <title>Composite Types</title>
 
   <para>
-   The second form of <command>CREATE TYPE</command> requires a column
-   definition list in the form ( <replaceable class="PARAMETER">column_name</replaceable> 
-   <replaceable class="PARAMETER">data_type</replaceable> [, ... ] ). This
-   creates a composite type, similar to that of a TABLE or VIEW relation.
-   A stand-alone composite type is useful as the return type of FUNCTION.
+   The second form of <command>CREATE TYPE</command>
+   creates a composite type.
+   The composite type is specified by a list of column names and datatypes.
+   This is essentially the same as the row type
+   of a table, but using <command>CREATE TYPE</command> avoids the need to
+   create an actual table when all that is wanted is to define a type.
+   A stand-alone composite type is useful as the return type of a function.
   </para>
+  </refsect2>
 
   <refsect2>
    <title>Array Types</title>
 
    <para>
-    Whenever a user-defined data type is created, 
+    Whenever a user-defined base data type is created, 
     <productname>PostgreSQL</productname> automatically creates an
     associated array type, whose name consists of the base type's
     name prepended with an underscore.  The parser understands this
@@ -436,8 +443,8 @@ CREATE TABLE big_objs (id int4, obj bigobj);
    This example creates a composite type and uses it in
    a table function definition:
 <programlisting>
-CREATE TYPE compfoo AS (f1 int, f2 int);
-CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, foorefid FROM foo' LANGUAGE SQL;
+CREATE TYPE compfoo AS (f1 int, f2 text);
+CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, fooname FROM foo' LANGUAGE SQL;
 </programlisting>
   </para>
  </refsect1>
index 5fdaf90f0acd2ea46c1a970c2cdd2cd3832d72ee..f6dd0397570a318f3aca20cd509b6450ae0eee87 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/select.sgml,v 1.57 2002/08/28 14:35:37 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/select.sgml,v 1.58 2002/08/29 00:17:01 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -40,10 +40,10 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be:
 ( <replaceable class="PARAMETER">select</replaceable> )
     [ AS ] <replaceable class="PARAMETER">alias</replaceable> [ ( <replaceable class="PARAMETER">column_alias_list</replaceable> ) ]
 |
-<replaceable class="PARAMETER">table_function_name</replaceable> ( [ <replaceable class="parameter">argtype</replaceable> [, ...] ] )
+<replaceable class="PARAMETER">table_function_name</replaceable> ( [ <replaceable class="parameter">argument</replaceable> [, ...] ] )
     [ AS ] <replaceable class="PARAMETER">alias</replaceable> [ ( <replaceable class="PARAMETER">column_alias_list</replaceable> | <replaceable class="PARAMETER">column_definition_list</replaceable> ) ]
 |
-<replaceable class="PARAMETER">table_function_name</replaceable> ( [ <replaceable class="parameter">argtype</replaceable> [, ...] ] )
+<replaceable class="PARAMETER">table_function_name</replaceable> ( [ <replaceable class="parameter">argument</replaceable> [, ...] ] )
     AS ( <replaceable class="PARAMETER">column_definition_list</replaceable> )
 |
 <replaceable class="PARAMETER">from_item</replaceable> [ NATURAL ] <replaceable class="PARAMETER">join_type</replaceable> <replaceable class="PARAMETER">from_item</replaceable>
@@ -142,10 +142,14 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be:
       <term><replaceable class="PARAMETER">alias</replaceable></term>
       <listitem>
        <para>
-       A substitute name for the preceding
-       <replaceable class="PARAMETER">table_name</replaceable>.
+       A substitute name for the FROM item containing the alias.
        An alias is used for brevity or to eliminate ambiguity for self-joins
-       (where the same table is scanned multiple times).  If an alias is
+       (where the same table is scanned multiple times).  When an alias
+       is provided, it completely hides the actual name of the table or
+       table function; for example given <literal>FROM foo AS f</>, the
+       remainder of the SELECT must refer to this FROM item as <literal>f</>
+       not <literal>foo</>.
+       If an alias is
        written, a column alias list can also be written to provide
        substitute names for one or more columns of the table.
        </para>
@@ -172,12 +176,15 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be:
        A table function can appear in the FROM clause.  This acts as though
        its output were created as a temporary table for the duration of
        this single SELECT command. An alias may also be used. If an alias is
-       written, a column alias list can also be written to provide     substitute names
-       for one or more columns of the table function. If the table function has been
-       defined as returning the RECORD data type, an alias, or the keyword AS, must
-    also be present, followed by a column definition list in the form
-       ( <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] ).
-       The column definition list must match the actual number and types returned by the function.
+       written, a column alias list can also be written to provide substitute
+       names for one or more columns of the table function. If the table
+       function has been defined as returning the <type>record</> data type,
+       an alias, or the keyword <literal>AS</>, must be present, followed by
+       a column definition list in the form ( <replaceable
+       class="PARAMETER">column_name</replaceable> <replaceable
+       class="PARAMETER">data_type</replaceable> [, ... ] ).
+       The column definition list must match the actual number and types
+       of columns returned by the function.
        </para>
       </listitem>
      </varlistentry>
@@ -395,7 +402,7 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be:
     this was the default result, and adding sub-tables was done
     by appending <command>*</command> to the table name.
     This old behavior is available via the command 
-    <command>SET SQL_Inheritance TO OFF;</command>
+    <command>SET SQL_Inheritance TO OFF</command>.
    </para>
 
    <para>
@@ -406,16 +413,22 @@ where <replaceable class="PARAMETER">from_item</replaceable> can be:
    </para>
 
    <para>
-    A FROM item can be a table function (i.e. a function that returns
-    multiple rows and columns).  When a table function is created, it may
-       be defined to return a named scalar or composite data type (an existing
-       scalar data type, or a table or view name), or it may be defined to return
-       a RECORD data type. When a table function is defined to return RECORD, it
-       must be followed in the FROM clause by an alias, or the keyword AS alone,
-       and then by a parenthesized list of column names and types. This provides
-       a query-time composite type definition. The FROM clause composite type
-       must match the actual composite type returned from the function or an
-       ERROR will be generated.
+    A FROM item can be a table function (typically, a function that returns
+    multiple rows and/or columns, though actually any function can be used).
+    The function is invoked with the given argument value(s), and then its
+    output is scanned as though it were a table.
+   </para>
+
+   <para>
+    In some cases it is useful to define table functions that can return
+    different column sets depending on how they are invoked.  To support this,
+    the table function can be declared as returning the pseudo-type
+    <type>record</>.  When such a function is used in FROM, it must be
+    followed by an alias, or the keyword <literal>AS</> alone,
+    and then by a parenthesized list of column names and types. This provides
+    a query-time composite type definition. The composite type definition
+    must match the actual composite type returned from the function, or an
+    error will be reported at run-time.
    </para>
 
    <para>
@@ -827,6 +840,38 @@ SELECT name FROM distributors ORDER BY code;
     unless ORDER BY is used to constrain the order.
    </para>
   </refsect2>
+
+  <refsect2 id="SQL-FOR-UPDATE">
+   <refsect2info>
+    <date>2002-08-28</date>
+   </refsect2info>
+   <title id="sql-for-update-title">
+    FOR UPDATE Clause
+   </title>
+   <para>
+    <synopsis>
+    FOR UPDATE [ OF <replaceable class="PARAMETER">tablename</replaceable> [, ...] ]
+    </synopsis>
+   </para>
+
+   <para>
+    FOR UPDATE causes the rows retrieved by the query to be locked as though
+    for update.  This prevents them from being modified or deleted by other
+    transactions until the current transaction ends.
+   </para>
+
+   <para>
+    If specific tables are named in FOR UPDATE, then only rows coming from
+    those tables are locked.
+   </para>
+
+   <para>
+    FOR UPDATE cannot be used in contexts where returned rows can't be clearly
+    identified with individual table rows; for example it can't be used with
+    aggregation.
+   </para>
+  </refsect2>
+
  </refsect1>
 
  <refsect1 id="R1-SQL-SELECT-2">
@@ -1019,8 +1064,7 @@ SELECT * FROM distributors_2(111) AS (f1 int, f2 text);
 <productname>PostgreSQL</productname> allows one to omit 
 the <command>FROM</command> clause from a query. This feature
 was retained from the original PostQuel query language.  It has
-a straightforward use to compute the results of simple constant
-expressions:
+a straightforward use to compute the results of simple expressions:
 
   <programlisting>
 SELECT 2+2;
@@ -1062,6 +1106,11 @@ and later will warn if the implicit-FROM feature is used in a query that also
 contains an explicit FROM clause.
 
    </para>
+
+   <para>
+    The table-function feature is a <productname>PostgreSQL</productname>
+    extension.
+   </para>
   </refsect2>
 
   <refsect2 id="R2-SQL-SELECT-5">
index 13e139ffbaa4fe8106e6682c4df507d2ebcae832..8eed28791a1e80fe1816165b743f5990aadeab4a 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/select_into.sgml,v 1.19 2002/08/28 14:35:37 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/select_into.sgml,v 1.20 2002/08/29 00:17:01 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -29,20 +29,9 @@ SELECT [ ALL | DISTINCT [ ON ( <replaceable class="PARAMETER">expression</replac
     [ HAVING <replaceable class="PARAMETER">condition</replaceable> [, ...] ]
     [ { UNION | INTERSECT | EXCEPT } [ ALL ] <replaceable class="PARAMETER">select</replaceable> ]
     [ ORDER BY <replaceable class="PARAMETER">expression</replaceable> [ ASC | DESC | USING <replaceable class="PARAMETER">operator</replaceable> ] [, ...] ]
-    [ LIMIT [ <replaceable class="PARAMETER">start</replaceable> , ] { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
+    [ LIMIT { <replaceable class="PARAMETER">count</replaceable> | ALL } ]
     [ OFFSET <replaceable class="PARAMETER">start</replaceable> ]
     [ FOR UPDATE [ OF <replaceable class="PARAMETER">tablename</replaceable> [, ...] ] ]
-
-where <replaceable class="PARAMETER">from_item</replaceable> can be:
-
-[ ONLY ] <replaceable class="PARAMETER">table_name</replaceable> [ * ]
-    [ [ AS ] <replaceable class="PARAMETER">alias</replaceable> [ ( <replaceable class="PARAMETER">column_alias_list</replaceable> ) ] ]
-|
-( <replaceable class="PARAMETER">select</replaceable> )
-    [ AS ] <replaceable class="PARAMETER">alias</replaceable> [ ( <replaceable class="PARAMETER">column_alias_list</replaceable> ) ]
-|
-<replaceable class="PARAMETER">from_item</replaceable> [ NATURAL ] <replaceable class="PARAMETER">join_type</replaceable> <replaceable class="PARAMETER">from_item</replaceable>
-    [ ON <replaceable class="PARAMETER">join_condition</replaceable> | USING ( <replaceable class="PARAMETER">join_column_list</replaceable> ) ]
   </synopsis>
   
   <refsect2 id="R2-SQL-SELECTINTO-1">
index e457504ebefcf4a5352d3dac79ac6525cf7fa45a..60c78d0588fd7c2e2b48c8152c6b490921c74655 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.152 2002/08/27 04:55:07 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.153 2002/08/29 00:17:01 tgl Exp $
 -->
 
 <appendix id="release">
@@ -26,6 +26,7 @@ worries about funny characters.
 <literallayout><![CDATA[
 PREPARE statement allows caching query plans for interactive statements
 Type OPAQUE is now deprecated in favor of pseudo-types cstring, trigger, etc
+Standalone composite types can now be created with CREATE TYPE
 Files larger than 2 GB are now supported (if supported by the operating system)
 SERIAL no longer implies UNIQUE; specify explicitly if index is wanted
 pg_dump -n and -N options have been removed.  The new behavior is like -n but knows about key words.
index a38305ce0bc64880684ad496d430ec4a9711d15e..b3f653a28a12fc59a1770e23875188a95068c514 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.56 2002/08/23 16:41:37 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.57 2002/08/29 00:17:02 tgl Exp $
 -->
 
  <chapter id="xfunc">
@@ -10,23 +10,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.56 2002/08/23 16:41:37 tgl E
   <sect1 id="xfunc-intro">
    <title>Introduction</title>
 
-  <comment>
-   Historically, functions were perhaps considered a tool for creating
-   types.  Today, few people build their own types but many write
-   their own functions.  This introduction ought to be changed to
-   reflect this.
-  </comment>
-
-  <para>
-   As  it  turns  out,  part of defining a new type is the
-   definition of functions  that  describe  its  behavior.
-   Consequently,  while  it  is  possible  to define a new
-   function without defining a new type,  the  reverse  is
-   not  true.   We therefore describe how to add new functions 
-   to <productname>PostgreSQL</productname> before  describing  
-   how  to  add  new types.
-  </para>
-
   <para>
    <productname>PostgreSQL</productname> provides four kinds of
    functions:
@@ -285,8 +268,6 @@ SELECT name, double_salary(EMP) AS dream
 
     <para>
      It is also possible to build a function that returns a composite type.
-     (However, as we'll see below, there are some
-     unfortunate restrictions on how the function may be used.)
      This is an example of a function 
      that returns a single <type>EMP</type> row:
 
@@ -330,12 +311,12 @@ ERROR:  function declared to return emp returns varchar instead of text at colum
     </para>     
 
     <para>
-     In the present release of <productname>PostgreSQL</productname>
-     there are some unpleasant restrictions on how functions returning
-     composite types can be used.  Briefly, when calling a function that
-     returns a row, we cannot retrieve the entire row.  We must either
+     A function that returns a row (composite type) can be used as a table
+     function, as described below.  It can also be called in the context
+     of an SQL expression, but only when you
      extract a single attribute out of the row or pass the entire row into
-     another function.  (Trying to display the entire row value will yield
+     another function that accepts the same composite type.  (Trying to
+     display the entire row value will yield 
      a meaningless number.)  For example,
 
 <programlisting>
@@ -357,8 +338,8 @@ ERROR:  parser: parse error at or near "."
     </para>
 
     <para>
-     Another approach is to use
-     functional notation for extracting attributes.  The  simple  way 
+     Another option is to use
+     functional notation for extracting an attribute.  The  simple  way 
      to explain this is that we can use the
      notations <literal>attribute(table)</>  and  <literal>table.attribute</>
      interchangeably:
@@ -412,26 +393,73 @@ SELECT getname(new_emp());
    </sect2>
 
    <sect2>
-    <title><acronym>SQL</acronym> Table Functions (Functions Returning Sets)</title>
+    <title><acronym>SQL</acronym> Table Functions</title>
 
     <para>
      A table function is one that may be used in the <command>FROM</command>
-     clause of a query. All SQL Language functions may be used in this manner.
+     clause of a query. All SQL language functions may be used in this manner,
+     but it is particularly useful for functions returning composite types.
      If the function is defined to return a base type, the table function
-     produces a one column result set. If the function is defined to
-     return <literal>SETOF <replaceable>sometype</></literal>, the table
-     function returns multiple rows. To illustrate a SQL table function,
-     consider the following, which returns <literal>SETOF</literal> a
-     composite type:
+     produces a one-column table.  If the function is defined to return
+     a composite type, the table function produces a column for each column
+     of the composite type.
+    </para>
+
+    <para>
+     Here is an example:
 
 <programlisting>
-CREATE TABLE foo (fooid int, foosubid int, fooname text, primary key(fooid,foosubid));
+CREATE TABLE foo (fooid int, foosubid int, fooname text);
 INSERT INTO foo VALUES(1,1,'Joe');
 INSERT INTO foo VALUES(1,2,'Ed');
 INSERT INTO foo VALUES(2,1,'Mary');
+
+CREATE FUNCTION getfoo(int) RETURNS foo AS '
+    SELECT * FROM foo WHERE fooid = $1;
+' LANGUAGE SQL;
+
+SELECT *, upper(fooname) FROM getfoo(1) AS t1;
+</programlisting>
+
+<screen>
+ fooid | foosubid | fooname | upper
+-------+----------+---------+-------
+     1 |        1 | Joe     | JOE
+(2 rows)
+</screen>
+
+     As the example shows, we can work with the columns of the function's
+     result just the same as if they were columns of a regular table.
+    </para>
+
+    <para>
+     Note that we only got one row out of the function.  This is because
+     we did not say <literal>SETOF</>.
+    </para>
+
+   </sect2>
+
+   <sect2>
+    <title><acronym>SQL</acronym> Functions Returning Sets</title>
+
+    <para>
+     When an SQL function is declared as returning <literal>SETOF</literal>
+     <replaceable>sometype</>, the function's final
+     <command>SELECT</> query is executed to completion, and each row it
+     outputs is returned as an element of the set.
+    </para>
+
+    <para>
+     This feature is normally used by calling the function as a table
+     function.  In this case each row returned by the function becomes
+     a row of the table seen by the query.  For example, assume that
+     table <literal>foo</> has the same contents as above, and we say:
+
+<programlisting>
 CREATE FUNCTION getfoo(int) RETURNS setof foo AS '
     SELECT * FROM foo WHERE fooid = $1;
 ' LANGUAGE SQL;
+
 SELECT * FROM getfoo(1) AS t1;
 </programlisting>
 
@@ -445,14 +473,7 @@ SELECT * FROM getfoo(1) AS t1;
     </para>
 
     <para>
-     When an SQL function is declared as returning <literal>SETOF
-     <replaceable>sometype</></literal>, the function's final
-     <command>SELECT</> query is executed to completion, and each row it
-     outputs is returned as an element of the set.
-    </para>
-
-    <para>
-     Functions returning sets may also currently be called in the target list
+     Currently, functions returning sets may also be called in the target list
      of a <command>SELECT</> query.  For each row that the <command>SELECT</>
      generates by itself, the function returning set is invoked, and an output
      row is generated for each element of the function's result set. Note,
@@ -1346,7 +1367,8 @@ concat_text(PG_FUNCTION_ARGS)
      <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function>
      guarantees to return a copy of the specified parameter which is
      safe for writing into. (The normal macros will sometimes return a
-     pointer to the value which must not be written to. Using the
+     pointer to a value that is physically stored in a table, and so
+     must not be written to. Using the
      <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function>
      macros guarantees a writable result.)
     </para>
@@ -1471,8 +1493,8 @@ LANGUAGE C;
     <title>Table Function API</title>
 
     <para>
-     The Table Function API assists in the creation of a user defined
-     C Language table functions (<xref linkend="xfunc-tablefunctions">).
+     The Table Function API assists in the creation of user-defined
+     C language table functions (<xref linkend="xfunc-tablefunctions">).
      Table functions are functions that produce a set of rows, made up of
      either base (scalar) data types, or composite (multi-column) data types.
      The API is split into two main components: support for returning
@@ -1482,105 +1504,124 @@ LANGUAGE C;
 
     <para>
      The Table Function API relies on macros and functions to suppress most
-     of the complexity of building composite data types and return multiple
-     results.  In addition to the version-1 conventions discussed elsewhere,
-     a table function always requires the following:
+     of the complexity of building composite data types and returning multiple
+     results.  A table function must follow the version-1 calling convention
+     described above.  In addition, the source file must include:
 <programlisting>
 #include "funcapi.h"
 </programlisting>
     </para>
 
+   <sect3>
+    <title>Returning Tuples (Composite Types)</title>
+
     <para>
      The Table Function API support for returning composite data types
      (or tuples) starts with the AttInMetadata struct. This struct holds
      arrays of individual attribute information needed to create a tuple from
-     raw C strings. It also requires a copy of the TupleDesc. The information
+     raw C strings. It also saves a pointer to the TupleDesc. The information
      carried here is derived from the TupleDesc, but it is stored here to
-     avoid redundant cpu cycles on each call to a Table Function.
+     avoid redundant CPU cycles on each call to a Table Function.  In the
+     case of a function returning a set, the AttInMetadata struct should be
+     computed once during the first call and saved for re-use in later calls.
 <programlisting>
-typedef struct
+typedef struct AttInMetadata
 {
-       /* full TupleDesc */
-       TupleDesc          tupdesc;
-
-       /* pointer to array of attribute "type"in finfo */
-       FmgrInfo           *attinfuncs;
+    /* full TupleDesc */
+    TupleDesc       tupdesc;
 
-       /* pointer to array of attribute type typelem */
-       Oid                        *attelems;
+    /* array of attribute type input function finfo */
+    FmgrInfo       *attinfuncs;
 
-       /* pointer to array of attribute type typtypmod */
-       int4               *atttypmods;
+    /* array of attribute type typelem */
+    Oid            *attelems;
 
+    /* array of attribute typmod */
+    int32         *atttypmods;
 }      AttInMetadata;
 </programlisting>
      To assist you in populating this struct, several functions and a macro
      are available. Use
 <programlisting>
-TupleDesc RelationNameGetTupleDesc(char *relname)
+TupleDesc RelationNameGetTupleDesc(const char *relname)
 </programlisting>
-     to get a TupleDesc based on the function's return type relation, or
+     to get a TupleDesc based on a specified relation, or
 <programlisting>
 TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
 </programlisting>
-     to get a TupleDesc based on the function's type oid. This can be used to
-     get a TupleDesc for a base (scalar), or composite (relation) type. Then
+     to get a TupleDesc based on a type OID. This can be used to
+     get a TupleDesc for a base (scalar) or composite (relation) type. Then
 <programlisting>
 AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)
 </programlisting>
      will return a pointer to an AttInMetadata struct, initialized based on
-     the function's TupleDesc. AttInMetadata is be used in conjunction with
+     the given TupleDesc. AttInMetadata can be used in conjunction with
      C strings to produce a properly formed tuple. The metadata is stored here
-     for use across calls to avoid redundant work.
+     to avoid redundant work across multiple calls.
     </para>
 
     <para>
-     In order to return a tuple you must create a tuple slot based on the
+     To return a tuple you must create a tuple slot based on the
      TupleDesc. You can use
 <programlisting>
 TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc)
 </programlisting>
      to initialize this tuple slot, or obtain one through other (user provided)
      means. The tuple slot is needed to create a Datum for return by the
-     function.
+     function.  The same slot can (and should) be re-used on each call.
     </para>
 
     <para>
-     If desired,
+     After constructing an AttInMetadata structure,
 <programlisting>
 HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
 </programlisting>
      can be used to build a HeapTuple given user data in C string form.
      "values" is an array of C strings, one for each attribute of the return
-     tuple. The C strings should be in the form expected by the "in" function
-     of the attribute data type. For more information on this requirement,
-     see the individual data type "in" functions in the source code
-     (e.g. textin() for data type TEXT). In order to return a NULL value for
+     tuple. Each C string should be in the form expected by the input function
+     of the attribute data type. In order to return a NULL value for
      one of the attributes, the corresponding pointer in the "values" array
-     should be set to NULL.
+     should be set to NULL.  This function will need to be called again
+     for each tuple you return.
     </para>
 
     <para>
-     In order to get an attribute "in" function and typelem value given the
-     typeid, use
-<programlisting>
-void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem)
-</programlisting>
+     Building a tuple via TupleDescGetAttInMetadata and BuildTupleFromCStrings
+     is only convenient if your function naturally computes the values to
+     be returned as text strings.  If your code naturally computes the
+     values as a set of Datums, you should instead use the underlying
+     heap_formtuple routine to convert the Datums directly into a tuple.
+     You will still need the TupleDesc and a TupleTableSlot, but not
+     AttInMetadata.
     </para>
 
     <para>
-     Finally, in order to return a tuple using the SRF portion of the API
-     (described below), the tuple must be converted into a Datum. Use
+     Once you have built a tuple to return from your function, the tuple must
+     be converted into a Datum. Use
 <programlisting>
 TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple)
 </programlisting>
-     to get a Datum given a tuple and a slot.
+     to get a Datum given a tuple and a slot.  This Datum can be returned
+     directly if you intend to return just a single row, or it can be used
+     as the current return value in a set-returning function.
+    </para>
+
+    <para>
+     An example appears below.
     </para>
 
+   </sect3>
+
+   <sect3>
+    <title>Returning Sets</title>
+
     <para>
-     The Table Function API support for set returning functions starts with
-     the FuncCallContext struct. This struct holds function context for
-     SRFs using fcinfo->flinfo->fn_extra to hold a pointer to it across calls.
+     A set-returning function (SRF) is normally called once for each item it
+     returns.  The SRF must therefore save enough state to remember what it
+     was doing and return the next item on each call.  The Table Function API
+     provides the FuncCallContext struct to help control this process.
+     <literal>fcinfo-&gt;flinfo-&gt;fn_extra</> is used to
+     hold a pointer to FuncCallContext across calls.
 <programlisting>
 typedef struct
 {
@@ -1639,12 +1680,13 @@ typedef struct
 
 }      FuncCallContext;
 </programlisting>
-     To assist you in populating this struct, several functions and macros
-     are available. Use
+     An SRF uses several functions and macros that automatically manipulate
+     the FuncCallContext struct (and expect to find it via
+     <literal>fn_extra</>).  Use
 <programlisting>
 SRF_IS_FIRSTCALL()
 </programlisting>
-     to determine if your function has been called for the first or a
+     to determine if your function is being called for the first or a
      subsequent time. On the first call (only) use
 <programlisting>
 SRF_FIRSTCALL_INIT()
@@ -1663,8 +1705,9 @@ SRF_PERCALL_SETUP()
 <programlisting>
 SRF_RETURN_NEXT(funcctx, result)
 </programlisting>
-     to send it and prepare for the next call. Finally, when your function
-     is finished returning data, use
+     to return it to the caller.  (The <literal>result</>
+     must be a Datum, either a single value or a tuple prepared as described
+     earlier.)  Finally, when your function is finished returning data, use
 <programlisting>
 SRF_RETURN_DONE(funcctx)
 </programlisting>
@@ -1677,136 +1720,139 @@ SRF_RETURN_DONE(funcctx)
 Datum
 my_Set_Returning_Function(PG_FUNCTION_ARGS)
 {
-       FuncCallContext    *funcctx;
-       Datum                           result;
-
-       [user defined declarations]
-
-       if(SRF_IS_FIRSTCALL())
-       {
-               [user defined code]
-               funcctx = SRF_FIRSTCALL_INIT();
-               [if returning composite]
-                       [obtain slot]
-                       funcctx->slot = slot;
-               [endif returning composite]
-               [user defined code]
-       }
-       [user defined code]
-       funcctx = SRF_PERCALL_SETUP();
-       [user defined code]
-
-       if (funcctx->call_cntr < funcctx->max_calls)
-       {
-               [user defined code]
-               [obtain result Datum]
-               SRF_RETURN_NEXT(funcctx, result);
-       }
-       else
-       {
-               SRF_RETURN_DONE(funcctx);
-       }
+    FuncCallContext     *funcctx;
+    Datum                result;
+    [user defined declarations]
+
+    if (SRF_IS_FIRSTCALL())
+    {
+        /* one-time setup code appears here: */
+        [user defined code]
+        funcctx = SRF_FIRSTCALL_INIT();
+        [if returning composite]
+            [build TupleDesc, and perhaps AttInMetadata]
+            [obtain slot]
+            funcctx-&gt;slot = slot;
+        [endif returning composite]
+        [user defined code]
+    }
+
+    /* each-time setup code appears here: */
+    [user defined code]
+    funcctx = SRF_PERCALL_SETUP();
+    [user defined code]
+
+    /* this is just one way we might test whether we are done: */
+    if (funcctx-&gt;call_cntr &lt; funcctx-&gt;max_calls)
+    {
+        /* here we want to return another item: */
+        [user defined code]
+        [obtain result Datum]
+        SRF_RETURN_NEXT(funcctx, result);
+    }
+    else
+    {
+        /* here we are done returning items, and just need to clean up: */
+        [user defined code]
+        SRF_RETURN_DONE(funcctx);
+    }
 }
 </programlisting>
     </para>
 
     <para>
-     An example of a simple composite returning SRF looks like:
+     A complete example of a simple SRF returning a composite type looks like:
 <programlisting>
 PG_FUNCTION_INFO_V1(testpassbyval);
 Datum
 testpassbyval(PG_FUNCTION_ARGS)
 {
-       FuncCallContext    *funcctx;
-       int                                     call_cntr;
-       int                                     max_calls;
-       TupleDesc                       tupdesc;
-       TupleTableSlot     *slot;
-       AttInMetadata      *attinmeta;
+    FuncCallContext     *funcctx;
+    int                  call_cntr;
+    int                  max_calls;
+    TupleDesc            tupdesc;
+    TupleTableSlot       *slot;
+    AttInMetadata       *attinmeta;
+
+     /* 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();
+
+        /* total number of tuples to be returned */
+        funcctx-&gt;max_calls = PG_GETARG_UINT32(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();
-
-               /* total number of tuples to be returned */
-               funcctx->max_calls = PG_GETARG_UINT32(0);
-
-               /*
-                * Build a tuple description for a __testpassbyval tuple
-                */
-               tupdesc = RelationNameGetTupleDesc("__testpassbyval");
+        /*
+         * Build a tuple description for a __testpassbyval tuple
+         */
+        tupdesc = RelationNameGetTupleDesc("__testpassbyval");
 
-               /* allocate a slot for a tuple with this tupdesc */
-               slot = TupleDescGetSlot(tupdesc);
+        /* allocate a slot for a tuple with this tupdesc */
+        slot = TupleDescGetSlot(tupdesc);
 
-               /* assign slot to function context */
-               funcctx->slot = slot;
+        /* assign slot to function context */
+        funcctx-&gt;slot = slot;
 
-               /*
-                * Generate attribute metadata needed later to produce tuples from raw
-                * C strings
-                */
-               attinmeta = TupleDescGetAttInMetadata(tupdesc);
-               funcctx->attinmeta = attinmeta;
+        /*
+         * Generate attribute metadata needed later to produce tuples from raw
+         * C strings
+         */
+        attinmeta = TupleDescGetAttInMetadata(tupdesc);
+        funcctx-&gt;attinmeta = attinmeta;
     }
 
-       /* stuff done on every call of the function */
-       funcctx = SRF_PERCALL_SETUP();
+    /* stuff done on every call of the function */
+    funcctx = SRF_PERCALL_SETUP();
 
-       call_cntr = funcctx->call_cntr;
-       max_calls = funcctx->max_calls;
-       slot = funcctx->slot;
-       attinmeta = funcctx->attinmeta;
+    call_cntr = funcctx-&gt;call_cntr;
+    max_calls = funcctx-&gt;max_calls;
+    slot = funcctx-&gt;slot;
+    attinmeta = funcctx-&gt;attinmeta;
  
-       if (call_cntr < max_calls)      /* do when there is more left to send */
-       {
-               char       **values;
-               HeapTuple       tuple;
-               Datum           result;
-
-               /*
-                * Prepare a values array for storage in our slot.
-                * This should be an array of C strings which will
-                * be processed later by the appropriate "in" functions.
-                */
-               values = (char **) palloc(3 * sizeof(char *));
-               values[0] = (char *) palloc(16 * sizeof(char));
-               values[1] = (char *) palloc(16 * sizeof(char));
-               values[2] = (char *) palloc(16 * sizeof(char));
-
-               snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
-               snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
-               snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));
-
-               /* build a tuple */
-               tuple = BuildTupleFromCStrings(attinmeta, values);
-
-               /* make the tuple into a datum */
-               result = TupleGetDatum(slot, tuple);
-
-               /* Clean up */
-               pfree(values[0]);
-               pfree(values[1]);
-               pfree(values[2]);
-               pfree(values);
-
-               SRF_RETURN_NEXT(funcctx, result);
-       }
-       else    /* do when there is no more left */
-       {
-               SRF_RETURN_DONE(funcctx);
-       }
+    if (call_cntr &lt; max_calls)    /* do when there is more left to send */
+    {
+        char       **values;
+        HeapTuple    tuple;
+        Datum        result;
+
+        /*
+         * Prepare a values array for storage in our slot.
+         * This should be an array of C strings which will
+         * be processed later by the appropriate "in" functions.
+         */
+        values = (char **) palloc(3 * sizeof(char *));
+        values[0] = (char *) palloc(16 * sizeof(char));
+        values[1] = (char *) palloc(16 * sizeof(char));
+        values[2] = (char *) palloc(16 * sizeof(char));
+
+        snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
+        snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
+        snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));
+
+        /* build a tuple */
+        tuple = BuildTupleFromCStrings(attinmeta, values);
+
+        /* make the tuple into a datum */
+        result = TupleGetDatum(slot, tuple);
+
+        /* Clean up */
+        pfree(values[0]);
+        pfree(values[1]);
+        pfree(values[2]);
+        pfree(values);
+
+         SRF_RETURN_NEXT(funcctx, result);
+    }
+    else    /* do when there is no more left */
+    {
+         SRF_RETURN_DONE(funcctx);
+    }
 }
 </programlisting>
      with supporting SQL code of
 <programlisting>
-CREATE VIEW __testpassbyval AS
-  SELECT
-    0::INT4 AS f1,
-    0::INT4 AS f2,
-    0::INT4 AS f3;
+CREATE TYPE __testpassbyval AS (f1 int4, f2 int4, f3 int4);
 
 CREATE OR REPLACE FUNCTION testpassbyval(int4, int4) RETURNS setof __testpassbyval
   AS 'MODULE_PATHNAME','testpassbyval' LANGUAGE 'c' IMMUTABLE STRICT;
@@ -1816,6 +1862,9 @@ CREATE OR REPLACE FUNCTION testpassbyval(int4, int4) RETURNS setof __testpassbyv
     <para>
      See contrib/tablefunc for more examples of Table Functions.
     </para>
+
+   </sect3>
+
    </sect2>
 
    <sect2>
@@ -2031,23 +2080,23 @@ CREATE FUNCTION test(int, int) RETURNS int
     Table functions work wherever tables do in <literal>SELECT</> statements.
     For example
 <programlisting>
-CREATE TABLE foo (fooid int, foosubid int, fooname text, primary key(fooid,foosubid));
-CREATE FUNCTION getfoo(int) RETURNS foo AS 'SELECT * FROM foo WHERE fooid = $1;' LANGUAGE SQL;
+CREATE TABLE foo (fooid int, foosubid int, fooname text);
+
+CREATE FUNCTION getfoo(int) RETURNS setof foo AS '
+    SELECT * FROM foo WHERE fooid = $1;
+' LANGUAGE SQL;
+
 SELECT * FROM getfoo(1) AS t1;
-SELECT * FROM foo where foosubid in (select foosubid from getfoo(foo.fooid) z where z.fooid = foo.fooid);
+
+SELECT * FROM foo
+WHERE foosubid in (select foosubid from getfoo(foo.fooid) z
+                   where z.fooid = foo.fooid);
+
 CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1);
 SELECT * FROM vw_getfoo;
 </programlisting>
     are all valid statements.
    </para>
-
-   <para>
-    Currently, table functions are supported as SQL language functions
-    (<xref linkend="xfunc-sql">) and C language functions
-    (<xref linkend="xfunc-c">). See these individual sections for more
-    details.
-   </para>
-
   </sect1>
 
   <sect1 id="xfunc-plhandler">
index 0e1765fc09ea9777bde238f231938eb125a2b968..8637c72b492aedd74ff67075ce9d16715a8d3d1e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.85 2002/08/05 02:30:49 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.86 2002/08/29 00:17:02 tgl Exp $
  *
  * NOTES
  *       some of the executor utility code such as "ExecTypeFromTL" should be
@@ -570,7 +570,7 @@ BuildDescForRelation(List *schema)
  * Given a (possibly qualified) relation name, build a TupleDesc.
  */
 TupleDesc
-RelationNameGetTupleDesc(char *relname)
+RelationNameGetTupleDesc(const char *relname)
 {
        RangeVar   *relvar;
        Relation        rel;
@@ -580,7 +580,7 @@ RelationNameGetTupleDesc(char *relname)
        /* Open relation and get the tuple description */
        relname_list = stringToQualifiedNameList(relname, "RelationNameGetTupleDesc");
        relvar = makeRangeVarFromNameList(relname_list);
-       rel = heap_openrv(relvar, AccessShareLock);
+       rel = relation_openrv(relvar, AccessShareLock);
        tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
        relation_close(rel, AccessShareLock);
 
@@ -611,50 +611,46 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases)
        {
                /* Composite data type, i.e. a table's row type */
                Oid                     relid = typeidTypeRelid(typeoid);
+               Relation        rel;
+               int                     natts;
 
-               if (OidIsValid(relid))
-               {
-                       Relation        rel;
-                       int                     natts;
+               if (!OidIsValid(relid))
+                       elog(ERROR, "Invalid typrelid for complex type %u", typeoid);
 
-                       rel = relation_open(relid, AccessShareLock);
-                       tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
-                       natts = tupdesc->natts;
-                       relation_close(rel, AccessShareLock);
+               rel = relation_open(relid, AccessShareLock);
+               tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
+               natts = tupdesc->natts;
+               relation_close(rel, AccessShareLock);
+               /* XXX should we hold the lock to ensure table doesn't change? */
 
-                       /* check to see if we've given column aliases */
-                       if(colaliases != NIL)
-                       {
-                               char       *label;
-                               int                     varattno;
+               if (colaliases != NIL)
+               {
+                       int                     varattno;
 
-                               /* does the List length match the number of attributes */
-                               if (length(colaliases) != natts)
-                                       elog(ERROR, "TypeGetTupleDesc: number of aliases does not match number of attributes");
+                       /* does the list length match the number of attributes? */
+                       if (length(colaliases) != natts)
+                               elog(ERROR, "TypeGetTupleDesc: number of aliases does not match number of attributes");
 
-                               /* OK, use the aliases instead */
-                               for (varattno = 0; varattno < natts; varattno++)
-                               {
-                                       label = strVal(nth(varattno, colaliases));
+                       /* OK, use the aliases instead */
+                       for (varattno = 0; varattno < natts; varattno++)
+                       {
+                               char       *label = strVal(nth(varattno, colaliases));
 
-                                       if (label != NULL)
-                                               namestrcpy(&(tupdesc->attrs[varattno]->attname), label);
-                               }
+                               if (label != NULL)
+                                       namestrcpy(&(tupdesc->attrs[varattno]->attname), label);
                        }
                }
-               else
-                       elog(ERROR, "Invalid return relation specified for function");
        }
        else if (functyptype == 'b' || functyptype == 'd')
        {
                /* Must be a base data type, i.e. scalar */
                char       *attname;
 
-               /* the alias List is required for base types */
+               /* the alias list is required for base types */
                if (colaliases == NIL)
                        elog(ERROR, "TypeGetTupleDesc: no column alias was provided");
 
-               /* the alias List length must be 1 */
+               /* the alias list length must be 1 */
                if (length(colaliases) != 1)
                        elog(ERROR, "TypeGetTupleDesc: number of aliases does not match number of attributes");
 
@@ -671,8 +667,7 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases)
                                                   false);
        }
        else if (functyptype == 'p' && typeoid == RECORDOID)
-               elog(ERROR, "Unable to determine tuple description for function"
-                                               " returning \"record\"");
+               elog(ERROR, "Unable to determine tuple description for function returning \"record\"");
        else
                elog(ERROR, "Unknown kind of return type specified for function");
 
index 325dff88dbcfc6e4a76f30316ba644f17cfe9cf7..89e0fec0ed5eed215eda1f1d00efe2674b8a5bc7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.145 2002/08/13 20:11:03 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.146 2002/08/29 00:17:02 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -607,6 +607,9 @@ heap_open(Oid relationId, LOCKMODE lockmode)
        else if (r->rd_rel->relkind == RELKIND_SPECIAL)
                elog(ERROR, "%s is a special relation",
                         RelationGetRelationName(r));
+       else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+               elog(ERROR, "%s is a composite type",
+                        RelationGetRelationName(r));
 
        pgstat_initstats(&r->pgstat_info, r);
 
@@ -633,6 +636,9 @@ heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
        else if (r->rd_rel->relkind == RELKIND_SPECIAL)
                elog(ERROR, "%s is a special relation",
                         RelationGetRelationName(r));
+       else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+               elog(ERROR, "%s is a composite type",
+                        RelationGetRelationName(r));
 
        pgstat_initstats(&r->pgstat_info, r);
 
@@ -659,6 +665,9 @@ heap_openr(const char *sysRelationName, LOCKMODE lockmode)
        else if (r->rd_rel->relkind == RELKIND_SPECIAL)
                elog(ERROR, "%s is a special relation",
                         RelationGetRelationName(r));
+       else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+               elog(ERROR, "%s is a composite type",
+                        RelationGetRelationName(r));
 
        pgstat_initstats(&r->pgstat_info, r);
 
index 0c21400ca1db0face1a80d63f3c7ed6b030c2835..c768ca2d55475a2348456f7513527219a471aad4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.221 2002/08/15 16:36:00 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.222 2002/08/29 00:17:02 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -69,6 +69,7 @@ static void AddNewRelationTuple(Relation pg_class_desc,
 static void AddNewRelationType(const char *typeName,
                                                           Oid typeNamespace,
                                                           Oid new_rel_oid,
+                                                          char new_rel_kind,
                                                           Oid new_type_oid);
 static void RelationRemoveInheritance(Relation relation);
 static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin);
@@ -357,7 +358,7 @@ CheckAttributeNames(TupleDesc tupdesc, bool relhasoids, char relkind)
        /*
         * first check for collision with system attribute names
         *
-        * Skip this for a view and type relation, since it doesn't have system
+        * Skip this for a view or type relation, since those don't have system
         * attributes.
         */
        if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
@@ -618,6 +619,7 @@ static void
 AddNewRelationType(const char *typeName,
                                   Oid typeNamespace,
                                   Oid new_rel_oid,
+                                  char new_rel_kind,
                                   Oid new_type_oid)
 {
        /*
@@ -633,6 +635,7 @@ AddNewRelationType(const char *typeName,
                           typeNamespace,       /* type namespace */
                           new_type_oid,        /* preassigned oid for type */
                           new_rel_oid,         /* relation oid */
+                          new_rel_kind,        /* relation kind */
                           sizeof(Oid),         /* internal size */
                           'c',                         /* type-type (complex) */
                           ',',                         /* default array delimiter */
@@ -728,7 +731,11 @@ heap_create_with_catalog(const char *relname,
         * NOTE: we could get a unique-index failure here, in case the same name
         * has already been used for a type.
         */
-       AddNewRelationType(relname, relnamespace, new_rel_oid, new_type_oid);
+       AddNewRelationType(relname,
+                                          relnamespace,
+                                          new_rel_oid,
+                                          relkind,
+                                          new_type_oid);
 
        /*
         * now add tuples to pg_attribute for the attributes in our new
@@ -904,7 +911,7 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
         * did this ... but when cascading from a drop of some other object,
         * we may not have any lock.)
         */
-       rel = heap_open(relid, AccessExclusiveLock);
+       rel = relation_open(relid, AccessExclusiveLock);
 
        attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
 
@@ -943,7 +950,7 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
 
        heap_close(attr_rel, RowExclusiveLock);
 
-       heap_close(rel, NoLock);
+       relation_close(rel, NoLock);
 }
 
 /*
@@ -1036,7 +1043,7 @@ RemoveAttrDefaultById(Oid attrdefId)
        myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;
 
        /* Get an exclusive lock on the relation owning the attribute */
-       myrel = heap_open(myrelid, AccessExclusiveLock);
+       myrel = relation_open(myrelid, AccessExclusiveLock);
 
        /* Now we can delete the pg_attrdef row */
        simple_heap_delete(attrdef_rel, &tuple->t_self);
@@ -1069,7 +1076,7 @@ RemoveAttrDefaultById(Oid attrdefId)
        heap_close(attr_rel, RowExclusiveLock);
 
        /* Keep lock on attribute's rel until end of xact */
-       heap_close(myrel, NoLock);
+       relation_close(myrel, NoLock);
 }
 
 /* ----------------------------------------------------------------
@@ -1099,7 +1106,7 @@ heap_drop_with_catalog(Oid rid)
        /*
         * Open and lock the relation.
         */
-       rel = heap_open(rid, AccessExclusiveLock);
+       rel = relation_open(rid, AccessExclusiveLock);
 
        /*
         * Release all buffers that belong to this relation, after writing any
@@ -1134,7 +1141,7 @@ heap_drop_with_catalog(Oid rid)
         * unlink the relation's physical file and finish up.
         */
        if (rel->rd_rel->relkind != RELKIND_VIEW &&
-                       rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
+               rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
                smgrunlink(DEFAULT_SMGR, rel);
 
        /*
@@ -1142,7 +1149,7 @@ heap_drop_with_catalog(Oid rid)
         * relation until transaction commit.  This ensures no one else will
         * try to do something with the doomed relation.
         */
-       heap_close(rel, NoLock);
+       relation_close(rel, NoLock);
 
        /*
         * flush the relation from the relcache
index 8f6caa5d4d9e688136f7658e8e74ee4420165095..33fc901e86717a5430eb704acadad34c492c98bc 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.31 2002/08/15 16:36:01 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.32 2002/08/29 00:17:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1585,7 +1585,6 @@ RemoveTempRelations(Oid tempNamespaceId)
                        case RELKIND_RELATION:
                        case RELKIND_SEQUENCE:
                        case RELKIND_VIEW:
-                       case RELKIND_COMPOSITE_TYPE:
                                AssertTupleDescHasOid(pgclass->rd_att);
                                object.classId = RelOid_pg_class;
                                object.objectId = HeapTupleGetOid(tuple);
index 1bdb3796e6670cdd04fde0ebb269dcab356f7089..e8608925bf51844b3c4bafcb34d61ec071bd83b7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.90 2002/08/23 16:41:37 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.91 2002/08/29 00:17:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -400,7 +400,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
                 * attributes to ensure that they match the datatypes of the
                 * non-resjunk columns.
                 */
-               reln = heap_open(typerelid, AccessShareLock);
+               reln = relation_open(typerelid, AccessShareLock);
                relnatts = reln->rd_rel->relnatts;
                rellogcols = 0;                         /* we'll count nondeleted cols as we go */
                colindex = 0;
@@ -447,7 +447,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
                        elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)",
                                 format_type_be(rettype), rellogcols);
 
-               heap_close(reln, AccessShareLock);
+               relation_close(reln, AccessShareLock);
        }
        else if (fn_typtype == 'p' && rettype == RECORDOID)
        {
index 6c6a135a0b9a0e567d0219f6fbbd5576d39f5bfc..ec0704b78e60e89c1d4920419800a0e2a5805657 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.79 2002/08/24 15:00:46 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.80 2002/08/29 00:17:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -129,7 +129,8 @@ Oid
 TypeCreate(const char *typeName,
                   Oid typeNamespace,
                   Oid assignedTypeOid,
-                  Oid relationOid,                     /* only for 'c'atalog typeTypes */
+                  Oid relationOid,                     /* only for 'c'atalog typeType */
+                  char relationKind,           /* ditto */
                   int16 internalSize,
                   char typeType,
                   char typDelim,
@@ -332,15 +333,11 @@ TypeCreate(const char *typeName,
                 */
                if (OidIsValid(relationOid))
                {
-                       Relation        rel = relation_open(relationOid, AccessShareLock);
-                       char            relkind = rel->rd_rel->relkind;
-                       relation_close(rel, AccessShareLock);
-
                        referenced.classId = RelOid_pg_class;
                        referenced.objectId = relationOid;
                        referenced.objectSubId = 0;
 
-                       if (relkind != RELKIND_COMPOSITE_TYPE)
+                       if (relationKind != RELKIND_COMPOSITE_TYPE)
                                recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
                        else
                                recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
index ce489280182a10ea4af5cc342b3c4e9a01cbb48d..ea04fd687dc08f6a22e828ceae2842d0a8b6d182 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (c) 1996-2001, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.57 2002/08/22 00:01:41 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.58 2002/08/29 00:17:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -362,7 +362,7 @@ CommentAttribute(List *qualname, char *comment)
 
        /* Open the containing relation to ensure it won't go away meanwhile */
        rel = makeRangeVarFromNameList(relname);
-       relation = heap_openrv(rel, AccessShareLock);
+       relation = relation_openrv(rel, AccessShareLock);
 
        /* Check object security */
 
@@ -383,7 +383,7 @@ CommentAttribute(List *qualname, char *comment)
 
        /* Done, but hold lock until commit */
 
-       heap_close(relation, NoLock);
+       relation_close(relation, NoLock);
 }
 
 /*
index c0b40c6e1431d34e41f41da090ccc131f9338746..b9eecf4b8be1f87fcbd657075aa36847393ae912 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.167 2002/08/24 15:00:46 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.168 2002/08/29 00:17:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -399,9 +399,6 @@ DoCopy(const CopyStmt *stmt)
                        if (rel->rd_rel->relkind == RELKIND_VIEW)
                                elog(ERROR, "You cannot copy view %s",
                                         RelationGetRelationName(rel));
-                       else if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-                               elog(ERROR, "You cannot copy type relation %s",
-                                        RelationGetRelationName(rel));
                        else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
                                elog(ERROR, "You cannot change sequence relation %s",
                                         RelationGetRelationName(rel));
@@ -447,9 +444,6 @@ DoCopy(const CopyStmt *stmt)
                        if (rel->rd_rel->relkind == RELKIND_VIEW)
                                elog(ERROR, "You cannot copy view %s",
                                         RelationGetRelationName(rel));
-                       else if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-                               elog(ERROR, "You cannot copy type relation %s",
-                                        RelationGetRelationName(rel));
                        else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
                                elog(ERROR, "You cannot copy sequence %s",
                                         RelationGetRelationName(rel));
index 13cf272525c85f79f68e039300fadb4af3def302..efae790dd8ce257141a77a2bfb978146d9d91f7d 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.84 2002/07/20 15:12:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.85 2002/08/29 00:17:03 tgl Exp $
  *
  */
 
@@ -79,7 +79,7 @@ ExplainQuery(ExplainStmt *stmt, CommandDest dest)
        if (query->commandType == CMD_UTILITY)
        {
                /* rewriter will not cope with utility statements */
-               PROJECT_LINE_OF_TEXT(tstate, "Utility statements have no plan structure");
+               do_text_output_oneline(tstate, "Utility statements have no plan structure");
        }
        else
        {
@@ -89,7 +89,7 @@ ExplainQuery(ExplainStmt *stmt, CommandDest dest)
                if (rewritten == NIL)
                {
                        /* In the case of an INSTEAD NOTHING, tell at least that */
-                       PROJECT_LINE_OF_TEXT(tstate, "Query rewrites to nothing");
+                       do_text_output_oneline(tstate, "Query rewrites to nothing");
                }
                else
                {
@@ -99,7 +99,7 @@ ExplainQuery(ExplainStmt *stmt, CommandDest dest)
                                ExplainOneQuery(lfirst(l), stmt, tstate);
                                /* put a blank line between plans */
                                if (lnext(l) != NIL)
-                                       PROJECT_LINE_OF_TEXT(tstate, "");
+                                       do_text_output_oneline(tstate, "");
                        }
                }
        }
@@ -122,9 +122,9 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
        if (query->commandType == CMD_UTILITY)
        {
                if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
-                       PROJECT_LINE_OF_TEXT(tstate, "NOTIFY");
+                       do_text_output_oneline(tstate, "NOTIFY");
                else
-                       PROJECT_LINE_OF_TEXT(tstate, "UTILITY");
+                       do_text_output_oneline(tstate, "UTILITY");
                return;
        }
 
@@ -189,7 +189,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
                        do_text_output_multiline(tstate, f);
                        pfree(f);
                        if (es->printCost)
-                               PROJECT_LINE_OF_TEXT(tstate, "");       /* separator line */
+                               do_text_output_oneline(tstate, "");     /* separator line */
                }
        }
 
index 81f1c4cfb7231ccc07f432d875309d7a94c1d0c9..04b0266dbc572c0041497754b6213b33229e2d9f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.35 2002/08/28 20:18:29 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.36 2002/08/29 00:17:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -228,7 +228,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
         * see the new rel anyway until we commit), but it keeps the lock
         * manager from complaining about deadlock risks.
         */
-       rel = heap_open(relationId, AccessExclusiveLock);
+       rel = relation_open(relationId, AccessExclusiveLock);
 
        /*
         * Now add any newly specified column default values and CHECK
@@ -293,7 +293,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
         * Clean up.  We keep lock on new relation (although it shouldn't be
         * visible to anyone else anyway, until commit).
         */
-       heap_close(rel, NoLock);
+       relation_close(rel, NoLock);
 
        return relationId;
 }
@@ -1064,7 +1064,7 @@ renameatt(Oid relid,
         * Grab an exclusive lock on the target table, which we will NOT
         * release until end of transaction.
         */
-       targetrelation = heap_open(relid, AccessExclusiveLock);
+       targetrelation = relation_open(relid, AccessExclusiveLock);
 
        /*
         * permissions checking.  this would normally be done in utility.c,
@@ -1210,7 +1210,7 @@ renameatt(Oid relid,
                                                           true, false);
        }
 
-       heap_close(targetrelation, NoLock); /* close rel but keep lock! */
+       relation_close(targetrelation, NoLock); /* close rel but keep lock! */
 }
 
 /*
@@ -3247,13 +3247,12 @@ CheckTupleType(Form_pg_class tuple_class)
                case RELKIND_RELATION:
                case RELKIND_INDEX:
                case RELKIND_VIEW:
-               case RELKIND_COMPOSITE_TYPE:
                case RELKIND_SEQUENCE:
                case RELKIND_TOASTVALUE:
                        /* ok to change owner */
                        break;
                default:
-                       elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table, TOAST table, index, view, type, or sequence",
+                       elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table, TOAST table, index, view, or sequence",
                                 NameStr(tuple_class->relname));
        }
 }
index 02e5a686e7758cba5bcd44a16dd09583c1bef044..bb1250b3572d3381b658c73431cda8ed6d000a83 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.11 2002/08/23 16:41:37 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.12 2002/08/29 00:17:03 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -233,6 +233,7 @@ DefineType(List *names, List *parameters)
                                   typeNamespace,       /* namespace */
                                   InvalidOid,          /* preassigned type oid (not done here) */
                                   InvalidOid,          /* relation oid (n/a here) */
+                                  0,                           /* relation kind (ditto) */
                                   internalLength,      /* internal size */
                                   'b',                         /* type-type (base type) */
                                   delimiter,           /* array element delimiter */
@@ -262,6 +263,7 @@ DefineType(List *names, List *parameters)
                           typeNamespace,       /* namespace */
                           InvalidOid,          /* preassigned type oid (not done here) */
                           InvalidOid,          /* relation oid (n/a here) */
+                          0,                           /* relation kind (ditto) */
                           -1,                          /* internal size */
                           'b',                         /* type-type (base type) */
                           DEFAULT_TYPDELIM,    /* array element delimiter */
@@ -562,6 +564,7 @@ DefineDomain(CreateDomainStmt *stmt)
                                   domainNamespace,             /* namespace */
                                   InvalidOid,                  /* preassigned type oid (none here) */
                                   InvalidOid,                  /* relation oid (n/a here) */
+                                  0,                                   /* relation kind (ditto) */
                                   internalLength,              /* internal size */
                                   'd',                                 /* type-type (domain type) */
                                   delimiter,                   /* array element delimiter */
index 7a6e1c69956aa8b654735dbee2c58646dae1e1fc..6318d79d4eb916331d02bedec1dcd23b0b83a0fc 100644 (file)
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.175 2002/08/28 20:46:22 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.176 2002/08/29 00:17:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -786,10 +786,6 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
                        elog(ERROR, "You can't change view relation %s",
                                 RelationGetRelationName(resultRelationDesc));
                        break;
-               case RELKIND_COMPOSITE_TYPE:
-                       elog(ERROR, "You can't change type relation %s",
-                                RelationGetRelationName(resultRelationDesc));
-                       break;
        }
 
        MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
index 06a784ce26d1f92d39395473ab064542ad46fb8f..afadcd3137b028ef74fb2ea4090b3c8ab6d083d6 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.56 2002/07/20 05:49:27 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.57 2002/08/29 00:17:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "funcapi.h"
 #include "access/heapam.h"
-#include "catalog/pg_type.h"
 #include "executor/executor.h"
+#include "utils/lsyscache.h"
+
 
 /* ----------------------------------------------------------------
  *                               tuple table create/delete functions
@@ -676,8 +677,7 @@ ExecTypeFromTL(List *targetList, hasoid_t withoid)
 }
 
 /*
- * TupleDescGetSlot - Initialize a slot based on the supplied
- * tupledesc
+ * TupleDescGetSlot - Initialize a slot based on the supplied tupledesc
  */
 TupleTableSlot *
 TupleDescGetSlot(TupleDesc tupdesc)
@@ -695,40 +695,36 @@ TupleDescGetSlot(TupleDesc tupdesc)
 }
 
 /*
- * TupleDescGetAttInMetadata - Get a pointer to AttInMetadata based on the
+ * TupleDescGetAttInMetadata - Build an AttInMetadata structure based on the
  * supplied TupleDesc. AttInMetadata can be used in conjunction with C strings
  * to produce a properly formed tuple.
  */
 AttInMetadata *
 TupleDescGetAttInMetadata(TupleDesc tupdesc)
 {
-       int                             natts;
+       int                             natts = tupdesc->natts;
        int                             i;
        Oid                             atttypeid;
        Oid                             attinfuncid;
-       Oid                             attelem;
        FmgrInfo           *attinfuncinfo;
        Oid                        *attelems;
-       int              *atttypmods;
+       int32              *atttypmods;
        AttInMetadata  *attinmeta;
 
        attinmeta = (AttInMetadata *) palloc(sizeof(AttInMetadata));
-       natts = tupdesc->natts;
 
        /*
         * Gather info needed later to call the "in" function for each attribute
         */
        attinfuncinfo = (FmgrInfo *) palloc(natts * sizeof(FmgrInfo));
        attelems = (Oid *) palloc(natts * sizeof(Oid));
-       atttypmods = (int4 *) palloc(natts * sizeof(int4));
+       atttypmods = (int32 *) palloc(natts * sizeof(int32));
 
        for (i = 0; i < natts; i++)
        {
                atttypeid = tupdesc->attrs[i]->atttypid;
-               get_type_metadata(atttypeid, &attinfuncid, &attelem);
-
+               getTypeInputInfo(atttypeid, &attinfuncid, &attelems[i]);
                fmgr_info(attinfuncid, &attinfuncinfo[i]);
-               attelems[i] = attelem;
                atttypmods[i] = tupdesc->attrs[i]->atttypmod;
        }
        attinmeta->tupdesc = tupdesc;
@@ -746,39 +742,35 @@ TupleDescGetAttInMetadata(TupleDesc tupdesc)
 HeapTuple
 BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
 {
-       TupleDesc                       tupdesc;
-       int                                     natts;
-       HeapTuple                       tuple;
+       TupleDesc                       tupdesc = attinmeta->tupdesc;
+       int                                     natts = tupdesc->natts;
+       Datum                      *dvalues;
        char                       *nulls;
        int                                     i;
-       Datum                      *dvalues;
-       FmgrInfo                        attinfuncinfo;
        Oid                                     attelem;
-       int4                            atttypmod;
-
-       tupdesc = attinmeta->tupdesc;
-       natts = tupdesc->natts;
+       int32                           atttypmod;
+       HeapTuple                       tuple;
 
        dvalues = (Datum *) palloc(natts * sizeof(Datum));
        nulls = (char *) palloc(natts * sizeof(char));
 
-       /* Call the "in" function for each attribute */
+       /* Call the "in" function for each non-null attribute */
        for (i = 0; i < natts; i++)
        {
                if (values[i] != NULL)
                {
-                       attinfuncinfo = attinmeta->attinfuncs[i];
                        attelem = attinmeta->attelems[i];
                        atttypmod = attinmeta->atttypmods[i];
 
-                       dvalues[i] = FunctionCall3(&attinfuncinfo, CStringGetDatum(values[i]),
-                                                                               ObjectIdGetDatum(attelem),
-                                                                               Int32GetDatum(atttypmod));
+                       dvalues[i] = FunctionCall3(&attinmeta->attinfuncs[i],
+                                                                          CStringGetDatum(values[i]),
+                                                                          ObjectIdGetDatum(attelem),
+                                                                          Int32GetDatum(atttypmod));
                        nulls[i] = ' ';
                }
                else
                {
-                       dvalues[i] = PointerGetDatum(NULL);
+                       dvalues[i] = (Datum) 0;
                        nulls[i] = 'n';
                }
        }
@@ -788,6 +780,13 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
         */
        tuple = heap_formtuple(tupdesc, dvalues, nulls);
 
+       /*
+        * Release locally palloc'd space.  XXX would probably be good to
+        * pfree values of pass-by-reference datums, as well.
+        */
+       pfree(dvalues);
+       pfree(nulls);
+
        return tuple;
 }
 
@@ -804,7 +803,7 @@ begin_tup_output_tupdesc(CommandDest dest, TupleDesc tupdesc)
 
        tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
 
-       tstate->tupdesc = tupdesc;
+       tstate->metadata = TupleDescGetAttInMetadata(tupdesc);
        tstate->destfunc = DestToFunction(dest);
 
        (*tstate->destfunc->setup) (tstate->destfunc, (int) CMD_SELECT,
@@ -823,20 +822,22 @@ void
 do_tup_output(TupOutputState *tstate, char **values)
 {
        /* build a tuple from the input strings using the tupdesc */
-       AttInMetadata *attinmeta = TupleDescGetAttInMetadata(tstate->tupdesc);
-       HeapTuple       tuple = BuildTupleFromCStrings(attinmeta, values);
+       HeapTuple       tuple = BuildTupleFromCStrings(tstate->metadata, values);
 
        /* send the tuple to the receiver */
        (*tstate->destfunc->receiveTuple) (tuple,
-                                                                          tstate->tupdesc,
+                                                                          tstate->metadata->tupdesc,
                                                                           tstate->destfunc);
        /* clean up */
        heap_freetuple(tuple);
 }
 
-/* write a chunk of text, breaking at newline characters
+/*
+ * write a chunk of text, breaking at newline characters
+ *
  * NB: scribbles on its input!
- * Should only be used for a single TEXT attribute tupdesc.
+ *
+ * Should only be used with a single-TEXT-attribute tupdesc.
  */
 void
 do_text_output_multiline(TupOutputState *tstate, char *text)
@@ -859,5 +860,6 @@ void
 end_tup_output(TupOutputState *tstate)
 {
        (*tstate->destfunc->cleanup) (tstate->destfunc);
+       /* XXX worth cleaning up the attinmetadata? */
        pfree(tstate);
 }
index eba919b8b66f8c650dbf11d63375dddb8693e621..fe473404b915c02cefaa1d04b2a309946f588f48 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.55 2002/08/23 16:41:37 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.56 2002/08/29 00:17:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -193,9 +193,10 @@ init_sql_fcache(FmgrInfo *finfo)
         */
        fcache->typlen = typeStruct->typlen;
 
-       if (typeStruct->typtype != 'c')
+       if (typeStruct->typtype != 'c' &&
+               procedureStruct->prorettype != RECORDOID)
        {
-               /* The return type is not a relation, so just use byval */
+               /* The return type is not a composite type, so just use byval */
                fcache->typbyval = typeStruct->typbyval;
                fcache->returnsTuple = false;
        }
index b8aecc2b82511c2ea13e55aec67af080e05fb7be..381b6047bf0729b022cd583d385544b50abac2df 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.5 2002/08/05 02:30:50 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.6 2002/08/29 00:17:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -130,10 +130,10 @@ FunctionNext(FunctionScan *node)
 /* ----------------------------------------------------------------
  *             ExecFunctionScan(node)
  *
- *             Scans the Function sequentially and returns the next qualifying
+ *             Scans the function sequentially and returns the next qualifying
  *             tuple.
  *             It calls the ExecScan() routine and passes it the access method
- *             which retrieve tuples sequentially.
+ *             which retrieves tuples sequentially.
  *
  */
 
@@ -156,7 +156,6 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
        FunctionScanState  *scanstate;
        RangeTblEntry      *rte;
        Oid                                     funcrettype;
-       Oid                                     funcrelid;
        char                            functyptype;
        TupleDesc                       tupdesc = NULL;
 
@@ -201,31 +200,26 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, Plan *parent)
 
        /*
         * Now determine if the function returns a simple or composite type,
-        * and check/add column aliases.
+        * and build an appropriate tupdesc.
         */
        functyptype = get_typtype(funcrettype);
 
-       /*
-        * Build a suitable tupledesc representing the output rows
-        */
        if (functyptype == 'c')
        {
-               funcrelid = typeidTypeRelid(funcrettype);
-               if (OidIsValid(funcrelid))
-               {
-                       /*
-                        * Composite data type, i.e. a table's row type
-                        * Same as ordinary relation RTE
-                        */
-                       Relation        rel;
+               /*
+                * Composite data type, i.e. a table's row type
+                */
+               Oid                     funcrelid;
+               Relation        rel;
 
-                       rel = relation_open(funcrelid, AccessShareLock);
-                       tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
-                       relation_close(rel, AccessShareLock);
-                       scanstate->returnsTuple = true;
-               }
-               else
-                       elog(ERROR, "Invalid return relation specified for function");
+               funcrelid = typeidTypeRelid(funcrettype);
+               if (!OidIsValid(funcrelid))
+                       elog(ERROR, "Invalid typrelid for complex type %u",
+                                funcrettype);
+               rel = relation_open(funcrelid, AccessShareLock);
+               tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
+               relation_close(rel, AccessShareLock);
+               scanstate->returnsTuple = true;
        }
        else if (functyptype == 'b' || functyptype == 'd')
        {
@@ -461,8 +455,7 @@ function_getonetuple(FunctionScanState *scanstate,
                         */
                        if (fn_typtype == 'p' && fn_typeid == RECORDOID)
                                if (tupledesc_mismatch(tupdesc, slot->ttc_tupleDescriptor))
-                                       elog(ERROR, "Query-specified return tuple and actual"
-                                                                       " function return tuple do not match");
+                                       elog(ERROR, "Query-specified return tuple and actual function return tuple do not match");
                }
                else
                {
@@ -480,7 +473,7 @@ function_getonetuple(FunctionScanState *scanstate,
                                                                  slot,                         /* slot to store in */
                                                                  InvalidBuffer,        /* buffer associated with
                                                                                                         * this tuple */
-                                                                 true);                        /* pfree this pointer */
+                                                                 true);                        /* pfree this tuple */
                }
        }
 
index 3a407753392029a5091eb679fe1ea3adcfb38af1..ca88b520f96212d5caa53eb8a35daa27000d37ba 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.169 2002/08/26 17:53:58 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.170 2002/08/29 00:17:04 tgl Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -145,7 +145,7 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
 static void
 _outNotifyStmt(StringInfo str, NotifyStmt *node)
 {
-       appendStringInfo(str, "NOTIFY :relation ");
+       appendStringInfo(str, " NOTIFY :relation ");
        _outNode(str, node->relation);
 }
 
@@ -153,14 +153,14 @@ static void
 _outSelectStmt(StringInfo str, SelectStmt *node)
 {
        /* XXX this is pretty durn incomplete */
-       appendStringInfo(str, "SELECT :where ");
+       appendStringInfo(str, " SELECT :where ");
        _outNode(str, node->whereClause);
 }
 
 static void
 _outFuncCall(StringInfo str, FuncCall *node)
 {
-       appendStringInfo(str, "FUNCTION ");
+       appendStringInfo(str, " FUNCCALL ");
        _outNode(str, node->funcname);
        appendStringInfo(str, " :args ");
        _outNode(str, node->args);
@@ -1006,7 +1006,7 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
                case RTE_FUNCTION:
                        appendStringInfo(str, ":funcexpr ");
                        _outNode(str, node->funcexpr);
-                       appendStringInfo(str, ":coldeflist ");
+                       appendStringInfo(str, " :coldeflist ");
                        _outNode(str, node->coldeflist);
                        break;
                case RTE_JOIN:
index 561145bb97de16f07c7ab2ea348b320e21c8ba75..463a8d5a4e538ee5f00d8eee47ed0a2eff8574a3 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.363 2002/08/28 20:46:23 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.364 2002/08/29 00:17:04 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -204,8 +204,8 @@ static void doNegateFloat(Value *v);
 
 %type <list>   stmtblock, stmtmulti,
                                OptTableElementList, TableElementList, OptInherit, definition,
-                               opt_distinct, opt_definition, func_args, rowdefinition
-                               func_args_list, func_as, createfunc_opt_list
+                               opt_distinct, opt_definition, func_args,
+                               func_args_list, func_as, createfunc_opt_list,
                                oper_argtypes, RuleActionList, RuleActionMulti,
                                opt_column_list, columnList, opt_name_list,
                                sort_clause, opt_sort_clause, sortby_list, index_params,
@@ -216,7 +216,7 @@ static void doNegateFloat(Value *v);
                                insert_target_list, def_list, opt_indirection,
                                group_clause, TriggerFuncArgs, select_limit,
                                opt_select_limit, opclass_item_list, trans_options,
-                               TableFuncElementList, OptTableFuncElementList,
+                               TableFuncElementList,
                                convert_args, prep_type_clause, prep_type_list,
                                execute_param_clause, execute_param_list
 
@@ -1424,13 +1424,13 @@ OptTableElementList:
                ;
 
 TableElementList:
-                       TableElementList ',' TableElement
+                       TableElement
                                {
-                                       $$ = lappend($1, $3);
+                                       $$ = makeList1($1);
                                }
-                       | TableElement
+                       | TableElementList ',' TableElement
                                {
-                                       $$ = makeList1($1);
+                                       $$ = lappend($1, $3);
                                }
                ;
 
@@ -2234,11 +2234,12 @@ DefineStmt:
                                        n->definition = $4;
                                        $$ = (Node *)n;
                                }
-                       | CREATE TYPE_P any_name AS rowdefinition
+                       | CREATE TYPE_P any_name AS '(' TableFuncElementList ')'
                                {
                                        CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
                                        RangeVar *r = makeNode(RangeVar);
 
+                                       /* can't use qualified_name, sigh */
                                        switch (length($3))
                                        {
                                                case 1:
@@ -2258,13 +2259,12 @@ DefineStmt:
                                                        break;
                                                default:
                                                        elog(ERROR,
-                                                       "Improper qualified name "
-                                                       "(too many dotted names): %s",
+                                                                "Improper qualified name (too many dotted names): %s",
                                                                 NameListToString($3));
                                                        break;
                                        }
                                        n->typevar = r;
-                                       n->coldeflist = $5;
+                                       n->coldeflist = $6;
                                        $$ = (Node *)n;
                                }
                        | CREATE CHARACTER SET opt_as any_name GET definition opt_collate
@@ -2277,9 +2277,6 @@ DefineStmt:
                                }
                ;
 
-rowdefinition: '(' TableFuncElementList ')'                    { $$ = $2; }
-               ;
-
 definition: '(' def_list ')'                                           { $$ = $2; }
                ;
 
@@ -4539,14 +4536,22 @@ table_ref:      relation_expr
                                        n->coldeflist = NIL;
                                        $$ = (Node *) n;
                                }
-                       | func_table AS '(' OptTableFuncElementList ')'
+                       | func_table alias_clause
+                               {
+                                       RangeFunction *n = makeNode(RangeFunction);
+                                       n->funccallnode = $1;
+                                       n->alias = $2;
+                                       n->coldeflist = NIL;
+                                       $$ = (Node *) n;
+                               }
+                       | func_table AS '(' TableFuncElementList ')'
                                {
                                        RangeFunction *n = makeNode(RangeFunction);
                                        n->funccallnode = $1;
                                        n->coldeflist = $4;
                                        $$ = (Node *) n;
                                }
-                       | func_table AS ColId '(' OptTableFuncElementList ')'
+                       | func_table AS ColId '(' TableFuncElementList ')'
                                {
                                        RangeFunction *n = makeNode(RangeFunction);
                                        Alias *a = makeNode(Alias);
@@ -4556,7 +4561,7 @@ table_ref:        relation_expr
                                        n->coldeflist = $5;
                                        $$ = (Node *) n;
                                }
-                       | func_table ColId '(' OptTableFuncElementList ')'
+                       | func_table ColId '(' TableFuncElementList ')'
                                {
                                        RangeFunction *n = makeNode(RangeFunction);
                                        Alias *a = makeNode(Alias);
@@ -4566,14 +4571,6 @@ table_ref:       relation_expr
                                        n->coldeflist = $4;
                                        $$ = (Node *) n;
                                }
-                       | func_table alias_clause
-                               {
-                                       RangeFunction *n = makeNode(RangeFunction);
-                                       n->funccallnode = $1;
-                                       n->alias = $2;
-                                       n->coldeflist = NIL;
-                                       $$ = (Node *) n;
-                               }
                        | select_with_parens
                                {
                                        /*
@@ -4815,24 +4812,18 @@ func_table: func_name '(' ')'
 
 where_clause:
                        WHERE a_expr                                                    { $$ = $2; }
-                                                                                                       /* no qualifiers */
                        | /*EMPTY*/                                                             { $$ = NULL; }
                ;
 
 
-OptTableFuncElementList:
-                       TableFuncElementList                            { $$ = $1; }
-                       | /*EMPTY*/                                                     { $$ = NIL; }
-               ;
-
 TableFuncElementList:
-                       TableFuncElementList ',' TableFuncElement
+                       TableFuncElement
                                {
-                                       $$ = lappend($1, $3);
+                                       $$ = makeList1($1);
                                }
-                       | TableFuncElement
+                       | TableFuncElementList ',' TableFuncElement
                                {
-                                       $$ = makeList1($1);
+                                       $$ = lappend($1, $3);
                                }
                ;
 
@@ -4842,7 +4833,6 @@ TableFuncElement: ColId Typename
                                        n->colname = $1;
                                        n->typename = $2;
                                        n->constraints = NIL;
-
                                        $$ = (Node *)n;
                                }
                ;
index 6713c665098dac020ad90e1bdf4fa8c13c920123..174c05790d9b3af81b8f7ea8e5f0ba2178659233 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.77 2002/08/08 17:00:19 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.78 2002/08/29 00:17:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -900,17 +900,14 @@ addRangeTableEntryForFunction(ParseState *pstate,
         * Now determine if the function returns a simple or composite type,
         * and check/add column aliases.
         */
-       functyptype = get_typtype(funcrettype);
-
        if (coldeflist != NIL)
        {
                /*
                 * we *only* allow a coldeflist for functions returning a
                 * RECORD pseudo-type
                 */
-               if (functyptype != 'p' || (functyptype == 'p' && funcrettype != RECORDOID))
-                       elog(ERROR, "A column definition list is only allowed for"
-                                               " functions returning RECORD");
+               if (funcrettype != RECORDOID)
+                       elog(ERROR, "A column definition list is only allowed for functions returning RECORD");
        }
        else
        {
@@ -918,57 +915,55 @@ addRangeTableEntryForFunction(ParseState *pstate,
                 * ... and a coldeflist is *required* for functions returning a
                 * RECORD pseudo-type
                 */
-               if (functyptype == 'p' && funcrettype == RECORDOID)
-                       elog(ERROR, "A column definition list is required for functions"
-                                               " returning RECORD");
+               if (funcrettype == RECORDOID)
+                       elog(ERROR, "A column definition list is required for functions returning RECORD");
        }
 
+       functyptype = get_typtype(funcrettype);
+
        if (functyptype == 'c')
        {
                /*
                 * Named composite data type, i.e. a table's row type
                 */
                Oid                     funcrelid = typeidTypeRelid(funcrettype);
+               Relation        rel;
+               int                     maxattrs;
 
-               if (OidIsValid(funcrelid))
-               {
-                       /*
-                        * Get the rel's relcache entry.  This access ensures that we have an
-                        * up-to-date relcache entry for the rel.
-                        */
-                       Relation        rel;
-                       int                     maxattrs;
+               if (!OidIsValid(funcrelid))
+                       elog(ERROR, "Invalid typrelid for complex type %u",
+                                funcrettype);
 
-                       rel = heap_open(funcrelid, AccessShareLock);
-
-                       /*
-                        * Since the rel is open anyway, let's check that the number of column
-                        * aliases is reasonable.
-                        */
-                       maxattrs = RelationGetNumberOfAttributes(rel);
-                       if (maxattrs < numaliases)
-                               elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
-                                        RelationGetRelationName(rel), maxattrs, numaliases);
+               /*
+                * Get the rel's relcache entry.  This access ensures that we have an
+                * up-to-date relcache entry for the rel.
+                */
+               rel = relation_open(funcrelid, AccessShareLock);
 
-                       /* fill in alias columns using actual column names */
-                       for (varattno = numaliases; varattno < maxattrs; varattno++)
-                       {
-                               char       *attrname;
+               /*
+                * Since the rel is open anyway, let's check that the number of column
+                * aliases is reasonable.
+                */
+               maxattrs = RelationGetNumberOfAttributes(rel);
+               if (maxattrs < numaliases)
+                       elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
+                                RelationGetRelationName(rel), maxattrs, numaliases);
 
-                               attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
-                               eref->colnames = lappend(eref->colnames, makeString(attrname));
-                       }
+               /* fill in alias columns using actual column names */
+               for (varattno = numaliases; varattno < maxattrs; varattno++)
+               {
+                       char       *attrname;
 
-                       /*
-                        * Drop the rel refcount, but keep the access lock till end of
-                        * transaction so that the table can't be deleted or have its schema
-                        * modified underneath us.
-                        */
-                       heap_close(rel, NoLock);
+                       attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
+                       eref->colnames = lappend(eref->colnames, makeString(attrname));
                }
-               else
-                       elog(ERROR, "Invalid return relation specified for function %s",
-                                funcname);
+
+               /*
+                * Drop the rel refcount, but keep the access lock till end of
+                * transaction so that the table can't be deleted or have its schema
+                * modified underneath us.
+                */
+               relation_close(rel, NoLock);
        }
        else if (functyptype == 'b' || functyptype == 'd')
        {
@@ -986,10 +981,12 @@ addRangeTableEntryForFunction(ParseState *pstate,
        {
                List       *col;
 
+               /* Use the column definition list to form the alias list */
+               eref->colnames = NIL;
                foreach(col, coldeflist)
                {
-                       char       *attrname;
                        ColumnDef  *n = lfirst(col);
+                       char       *attrname;
 
                        attrname = pstrdup(n->colname);
                        eref->colnames = lappend(eref->colnames, makeString(attrname));
@@ -1277,63 +1274,58 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
                                char functyptype = get_typtype(funcrettype);
                                List *coldeflist = rte->coldeflist;
 
-                               /*
-                                * Build a suitable tupledesc representing the output rows
-                                */
                                if (functyptype == 'c')
                                {
+                                       /*
+                                        * Composite data type, i.e. a table's row type
+                                        * Same as ordinary relation RTE
+                                        */
                                        Oid     funcrelid = typeidTypeRelid(funcrettype);
-                                       if (OidIsValid(funcrelid))
+                                       Relation        rel;
+                                       int                     maxattrs;
+                                       int                     numaliases;
+
+                                       if (!OidIsValid(funcrelid))
+                                               elog(ERROR, "Invalid typrelid for complex type %u",
+                                                        funcrettype);
+
+                                       rel = relation_open(funcrelid, AccessShareLock);
+                                       maxattrs = RelationGetNumberOfAttributes(rel);
+                                       numaliases = length(rte->eref->colnames);
+
+                                       for (varattno = 0; varattno < maxattrs; varattno++)
                                        {
-                                               /*
-                                                * Composite data type, i.e. a table's row type
-                                                * Same as ordinary relation RTE
-                                                */
-                                               Relation        rel;
-                                               int                     maxattrs;
-                                               int                     numaliases;
-
-                                               rel = heap_open(funcrelid, AccessShareLock);
-                                               maxattrs = RelationGetNumberOfAttributes(rel);
-                                               numaliases = length(rte->eref->colnames);
-
-                                               for (varattno = 0; varattno < maxattrs; varattno++)
+                                               Form_pg_attribute attr = rel->rd_att->attrs[varattno];
+
+                                               if (attr->attisdropped)
+                                                       continue;
+
+                                               if (colnames)
                                                {
-                                                       Form_pg_attribute attr = rel->rd_att->attrs[varattno];
-
-                                                       if (attr->attisdropped)
-                                                               continue;
-
-                                                       if (colnames)
-                                                       {
-                                                               char       *label;
-
-                                                               if (varattno < numaliases)
-                                                                       label = strVal(nth(varattno, rte->eref->colnames));
-                                                               else
-                                                                       label = NameStr(attr->attname);
-                                                               *colnames = lappend(*colnames, makeString(pstrdup(label)));
-                                                       }
-
-                                                       if (colvars)
-                                                       {
-                                                               Var                *varnode;
-
-                                                               varnode = makeVar(rtindex,
-                                                                                               attr->attnum,
-                                                                                               attr->atttypid,
-                                                                                               attr->atttypmod,
-                                                                                               sublevels_up);
-
-                                                               *colvars = lappend(*colvars, varnode);
-                                                       }
+                                                       char       *label;
+
+                                                       if (varattno < numaliases)
+                                                               label = strVal(nth(varattno, rte->eref->colnames));
+                                                       else
+                                                               label = NameStr(attr->attname);
+                                                       *colnames = lappend(*colnames, makeString(pstrdup(label)));
                                                }
 
-                                               heap_close(rel, AccessShareLock);
+                                               if (colvars)
+                                               {
+                                                       Var                *varnode;
+
+                                                       varnode = makeVar(rtindex,
+                                                                                         attr->attnum,
+                                                                                         attr->atttypid,
+                                                                                         attr->atttypmod,
+                                                                                         sublevels_up);
+
+                                                       *colvars = lappend(*colvars, varnode);
+                                               }
                                        }
-                                       else
-                                               elog(ERROR, "Invalid return relation specified"
-                                                                       " for function");
+
+                                       relation_close(rel, AccessShareLock);
                                }
                                else if (functyptype == 'b' || functyptype == 'd')
                                {
@@ -1376,12 +1368,9 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
                                                if (colvars)
                                                {
                                                        Var                *varnode;
-                                                       HeapTuple       typeTuple;
                                                        Oid                     atttypid;
 
-                                                       typeTuple = typenameType(colDef->typename);
-                                                       atttypid = HeapTupleGetOid(typeTuple);
-                                                       ReleaseSysCache(typeTuple);
+                                                       atttypid = typenameTypeId(colDef->typename);
 
                                                        varnode = makeVar(rtindex,
                                                                                        attnum,
@@ -1394,8 +1383,7 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
                                        }
                                }
                                else
-                                       elog(ERROR, "Unknown kind of return type specified"
-                                                               " for function");
+                                       elog(ERROR, "Unknown kind of return type specified for function");
                        }
                        break;
                case RTE_JOIN:
@@ -1595,9 +1583,6 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
                                char functyptype = get_typtype(funcrettype);
                                List *coldeflist = rte->coldeflist;
 
-                               /*
-                                * Build a suitable tupledesc representing the output rows
-                                */
                                if (functyptype == 'c')
                                {
                                        /*
@@ -1605,36 +1590,33 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
                                         * Same as ordinary relation RTE
                                         */
                                        Oid funcrelid = typeidTypeRelid(funcrettype);
+                                       HeapTuple                       tp;
+                                       Form_pg_attribute       att_tup;
 
-                                       if (OidIsValid(funcrelid))
-                                       {
-                                               HeapTuple                       tp;
-                                               Form_pg_attribute       att_tup;
-
-                                               tp = SearchSysCache(ATTNUM,
-                                                                                       ObjectIdGetDatum(funcrelid),
-                                                                                       Int16GetDatum(attnum),
-                                                                                       0, 0);
-                                               /* this shouldn't happen... */
-                                               if (!HeapTupleIsValid(tp))
-                                                       elog(ERROR, "Relation %s does not have attribute %d",
-                                                                get_rel_name(funcrelid), attnum);
-                                               att_tup = (Form_pg_attribute) GETSTRUCT(tp);
-                                               /*
-                                                * If dropped column, pretend it ain't there.  See notes
-                                                * in scanRTEForColumn.
-                                                */
-                                               if (att_tup->attisdropped)
-                                                       elog(ERROR, "Relation \"%s\" has no column \"%s\"",
-                                                                get_rel_name(funcrelid),
-                                                                NameStr(att_tup->attname));
-                                               *vartype = att_tup->atttypid;
-                                               *vartypmod = att_tup->atttypmod;
-                                               ReleaseSysCache(tp);
-                                       }
-                                       else
-                                               elog(ERROR, "Invalid return relation specified"
-                                                                       " for function");
+                                       if (!OidIsValid(funcrelid))
+                                               elog(ERROR, "Invalid typrelid for complex type %u",
+                                                        funcrettype);
+
+                                       tp = SearchSysCache(ATTNUM,
+                                                                               ObjectIdGetDatum(funcrelid),
+                                                                               Int16GetDatum(attnum),
+                                                                               0, 0);
+                                       /* this shouldn't happen... */
+                                       if (!HeapTupleIsValid(tp))
+                                               elog(ERROR, "Relation \"%s\" does not have attribute %d",
+                                                        get_rel_name(funcrelid), attnum);
+                                       att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+                                       /*
+                                        * If dropped column, pretend it ain't there.  See notes
+                                        * in scanRTEForColumn.
+                                        */
+                                       if (att_tup->attisdropped)
+                                               elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+                                                        get_rel_name(funcrelid),
+                                                        NameStr(att_tup->attname));
+                                       *vartype = att_tup->atttypid;
+                                       *vartypmod = att_tup->atttypmod;
+                                       ReleaseSysCache(tp);
                                }
                                else if (functyptype == 'b' || functyptype == 'd')
                                {
@@ -1647,19 +1629,12 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
                                else if (functyptype == 'p' && funcrettype == RECORDOID)
                                {
                                        ColumnDef  *colDef = nth(attnum - 1, coldeflist);
-                                       HeapTuple       typeTuple;
-                                       Oid                     atttypid;
-
-                                       typeTuple = typenameType(colDef->typename);
-                                       atttypid = HeapTupleGetOid(typeTuple);
-                                       ReleaseSysCache(typeTuple);
 
-                                       *vartype = atttypid;
+                                       *vartype = typenameTypeId(colDef->typename);
                                        *vartypmod = -1;
                                }
                                else
-                                       elog(ERROR, "Unknown kind of return type specified"
-                                                               " for function");
+                                       elog(ERROR, "Unknown kind of return type specified for function");
                        }
                        break;
                case RTE_JOIN:
index b16adef54dbce3e68463c23891c3f929c4b8053f..65745be3c00173cfbb66ae37be37310530a9c274 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.173 2002/08/27 04:55:11 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.174 2002/08/29 00:17:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -583,14 +583,9 @@ ProcessUtility(Node *parsetree,
 
                case T_CompositeTypeStmt:               /* CREATE TYPE (composite) */
                        {
-                               Oid     relid;
                                CompositeTypeStmt   *stmt = (CompositeTypeStmt *) parsetree;
 
-                               /*
-                                * DefineCompositeType returns relid for use when creating
-                                * an implicit composite type during function creation
-                                */
-                               relid = DefineCompositeType(stmt->typevar, stmt->coldeflist);
+                               DefineCompositeType(stmt->typevar, stmt->coldeflist);
                        }
                        break;
 
index 38e540e3c85f161d2731682955c87b827d7b21ee..83d0d1051df974056d7122a049f1c79762f0ebb8 100644 (file)
@@ -5,22 +5,22 @@
  * Copyright (c) 2002, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *             $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.2 2002/08/27 04:00:28 momjian Exp $
+ *             $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.3 2002/08/29 00:17:05 tgl Exp $
  */
-
 #include "postgres.h"
-#include "fmgr.h"
+
 #include "funcapi.h"
 #include "catalog/pg_type.h"
 #include "storage/lmgr.h"
 #include "storage/lock.h"
 #include "storage/lwlock.h"
 #include "storage/proc.h"
+#include "utils/builtins.h"
 
-Datum pg_lock_status(PG_FUNCTION_ARGS);
 
 static int next_lock(int locks[]);
 
+
 Datum
 pg_lock_status(PG_FUNCTION_ARGS)
 {
index bd642a26e9719471dc999efc3a8534e91b3a0786..d90c20adf981bce9e8bbd0f72c450ce7b6c12ffd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.34 2002/08/28 20:46:24 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.35 2002/08/29 00:17:05 tgl Exp $
  *
  * NOTES
  *       input routine largely stolen from boxin().
@@ -226,9 +226,6 @@ currtid_byreloid(PG_FUNCTION_ARGS)
        if (rel->rd_rel->relkind == RELKIND_VIEW)
                return currtid_for_view(rel, tid);
 
-       if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-               elog(ERROR, "currtid can't handle type relations");
-
        ItemPointerCopy(tid, result);
        heap_get_latest_tid(rel, SnapshotNow, result);
 
@@ -252,9 +249,6 @@ currtid_byrelname(PG_FUNCTION_ARGS)
        if (rel->rd_rel->relkind == RELKIND_VIEW)
                return currtid_for_view(rel, tid);
 
-       if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-               elog(ERROR, "currtid can't handle type relations");
-
        result = (ItemPointer) palloc(sizeof(ItemPointerData));
        ItemPointerCopy(tid, result);
 
index 079ba2152a7f0de1891fce09541c2afd519ee239..66dc58d6c4b4935706ce3aa003da7e36d0d556cd 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.80 2002/08/26 17:53:59 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.81 2002/08/29 00:17:05 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
@@ -1190,6 +1190,33 @@ get_typtype(Oid typid)
                return '\0';
 }
 
+/*
+ * getTypeInputInfo
+ *
+ *             Get info needed for converting values of a type to internal form
+ */
+void
+getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem)
+{
+       HeapTuple       typeTuple;
+       Form_pg_type pt;
+
+       typeTuple = SearchSysCache(TYPEOID,
+                                                          ObjectIdGetDatum(type),
+                                                          0, 0, 0);
+       if (!HeapTupleIsValid(typeTuple))
+               elog(ERROR, "getTypeInputInfo: Cache lookup of type %u failed", type);
+       pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+       if (!pt->typisdefined)
+               elog(ERROR, "Type \"%s\" is only a shell", NameStr(pt->typname));
+
+       *typInput = pt->typinput;
+       *typElem = pt->typelem;
+
+       ReleaseSysCache(typeTuple);
+}
+
 /*
  * getTypeOutputInfo
  *
index a8d4e4fb5f599621d61e9e04646f9e16e1fc0bf5..28311c26b7b2ec3db8901244afb10d4d8beb7bc0 100644 (file)
@@ -6,13 +6,18 @@
  *
  * Copyright (c) 2002, PostgreSQL Global Development Group
  *
+ * IDENTIFICATION
+ *       $Header: /cvsroot/pgsql/src/backend/utils/fmgr/funcapi.c,v 1.3 2002/08/29 00:17:05 tgl Exp $
+ *
  *-------------------------------------------------------------------------
  */
+#include "postgres.h"
 
 #include "funcapi.h"
 #include "catalog/pg_type.h"
 #include "utils/syscache.h"
 
+
 /*
  * init_MultiFuncCall
  * Create an empty FuncCallContext data structure
@@ -99,8 +104,6 @@ per_MultiFuncCall(PG_FUNCTION_ARGS)
 void
 end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
 {
-       MemoryContext oldcontext;
-
        /* unbind from fcinfo */
        fcinfo->flinfo->fn_extra = NULL;
 
@@ -108,32 +111,8 @@ end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx)
         * Caller is responsible to free up memory for individual
         * struct elements other than att_in_funcinfo and elements.
         */
-       oldcontext = MemoryContextSwitchTo(funcctx->fmctx);
-
        if (funcctx->attinmeta != NULL)
                pfree(funcctx->attinmeta);
 
        pfree(funcctx);
-
-       MemoryContextSwitchTo(oldcontext);
-}
-
-void
-get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem)
-{
-       HeapTuple               typeTuple;
-       Form_pg_type    typtup;
-
-       typeTuple = SearchSysCache(TYPEOID,
-                                                          ObjectIdGetDatum(typeid),
-                                                          0, 0, 0);
-       if (!HeapTupleIsValid(typeTuple))
-               elog(ERROR, "get_type_metadata: Cache lookup of type %u failed", typeid);
-
-       typtup = (Form_pg_type) GETSTRUCT(typeTuple);
-
-       *attinfuncid = typtup->typinput;
-       *attelem = typtup->typelem;
-
-       ReleaseSysCache(typeTuple);
 }
index b73118289fce6779125de125a7792a58c8357bc1..660cd124ba90c6afec74c5bb34a5d760109af516 100644 (file)
@@ -5,7 +5,7 @@
  * command, configuration file, and command line options.
  * See src/backend/utils/misc/README for more information.
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.84 2002/08/26 17:53:59 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.85 2002/08/29 00:17:05 tgl Exp $
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -2284,7 +2284,7 @@ ShowGUCConfigOption(const char *name)
        tstate = begin_tup_output_tupdesc(dest, tupdesc);
 
        /* Send it */
-       PROJECT_LINE_OF_TEXT(tstate, value);
+       do_text_output_oneline(tstate, value);
 
        end_tup_output(tstate);
 }
@@ -2462,7 +2462,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 
        if (call_cntr < max_calls)      /* do when there is more left to send */
        {
-               char       **values;
+               char       *values[2];
                char       *varname;
                char       *varval;
                bool            noshow;
@@ -2474,7 +2474,9 @@ show_all_settings(PG_FUNCTION_ARGS)
                 */
                do
                {
-                       varval = GetConfigOptionByNum(call_cntr, (const char **) &varname, &noshow);
+                       varval = GetConfigOptionByNum(call_cntr,
+                                                                                 (const char **) &varname,
+                                                                                 &noshow);
                        if (noshow)
                        {
                                /* varval is a palloc'd copy, so free it */
@@ -2495,9 +2497,8 @@ show_all_settings(PG_FUNCTION_ARGS)
                 * This should be an array of C strings which will
                 * be processed later by the appropriate "in" functions.
                 */
-               values = (char **) palloc(2 * sizeof(char *));
-               values[0] = pstrdup(varname);
-               values[1] = varval;     /* varval is already a palloc'd copy */
+               values[0] = varname;
+               values[1] = varval;
 
                /* build a tuple */
                tuple = BuildTupleFromCStrings(attinmeta, values);
@@ -2506,10 +2507,8 @@ show_all_settings(PG_FUNCTION_ARGS)
                result = TupleGetDatum(slot, tuple);
 
                /* Clean up */
-               pfree(values[0]);
                if (varval != NULL)
-                       pfree(values[1]);
-               pfree(values);
+                       pfree(varval);
 
                SRF_RETURN_NEXT(funcctx, result);
        }
index 4f33ff4e4fd46f85f3d7ad46b355b1af007cc7de..ddcb617974527d4ef707c34d0d875f8359dfddab 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.68 2002/08/15 16:36:06 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.69 2002/08/29 00:17:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -215,10 +215,9 @@ flagInhTables(TableInfo *tblinfo, int numTables,
 
        for (i = 0; i < numTables; i++)
        {
-               /* Sequences, views, and types never have parents */
+               /* Sequences and views never have parents */
                if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
-                       tblinfo[i].relkind == RELKIND_VIEW ||
-                       tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
+                       tblinfo[i].relkind == RELKIND_VIEW)
                        continue;
 
                /* Don't bother computing anything for non-target tables, either */
@@ -270,10 +269,9 @@ flagInhAttrs(TableInfo *tblinfo, int numTables,
 
        for (i = 0; i < numTables; i++)
        {
-               /* Sequences, views, and types never have parents */
+               /* Sequences and views never have parents */
                if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
-                       tblinfo[i].relkind == RELKIND_VIEW ||
-                       tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
+                       tblinfo[i].relkind == RELKIND_VIEW)
                        continue;
 
                /* Don't bother computing anything for non-target tables, either */
index a56f176841a3a3c8b4347fe754636e0eb23f8233..d552f63a3a81b4a37e6e9e84580bc7f6605bc4fd 100644 (file)
@@ -22,7 +22,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.294 2002/08/28 20:57:22 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.295 2002/08/29 00:17:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1148,10 +1148,6 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
                if (tblinfo[i].relkind == RELKIND_VIEW)
                        continue;
 
-               /* Skip TYPE relations */
-               if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
-                       continue;
-
                if (tblinfo[i].relkind == RELKIND_SEQUENCE)             /* already dumped */
                        continue;
 
@@ -1581,7 +1577,8 @@ getTypes(int *numTypes)
                                                  "typnamespace, "
                                                  "(select usename from pg_user where typowner = usesysid) as usename, "
                                                  "typelem, typrelid, "
-                                                 "(select relkind from pg_class where oid = typrelid) as typrelkind, "
+                                                 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
+                                                 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
                                                  "typtype, typisdefined "
                                                  "FROM pg_type");
        }
@@ -1591,7 +1588,8 @@ getTypes(int *numTypes)
                                                  "0::oid as typnamespace, "
                                                  "(select usename from pg_user where typowner = usesysid) as usename, "
                                                  "typelem, typrelid, "
-                                                 "''::char as typrelkind, "
+                                                 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
+                                                 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
                                                  "typtype, typisdefined "
                                                  "FROM pg_type");
        }
@@ -2120,7 +2118,6 @@ getTables(int *numTables)
        }
        else if (g_fout->remoteVersion >= 70200)
        {
-               /* before 7.3 there were no type relations with relkind 'c' */
                appendPQExpBuffer(query,
                                                  "SELECT pg_class.oid, relname, relacl, relkind, "
                                                  "0::oid as relnamespace, "
@@ -2392,10 +2389,6 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                if (tbinfo->relkind == RELKIND_SEQUENCE)
                        continue;
 
-               /* Don't bother to collect info for type relations */
-               if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE)
-                       continue;
-
                /* Don't bother with uninteresting tables, either */
                if (!tbinfo->interesting)
                        continue;
@@ -3210,7 +3203,7 @@ dumpOneDomain(Archive *fout, TypeInfo *tinfo)
        /* DROP must be fully qualified in case same name appears in pg_catalog */
        appendPQExpBuffer(delq, "DROP DOMAIN %s.",
                                          fmtId(tinfo->typnamespace->nspname));
-       appendPQExpBuffer(delq, "%s RESTRICT;\n",
+       appendPQExpBuffer(delq, "%s;\n",
                                          fmtId(tinfo->typname));
 
        appendPQExpBuffer(q,
@@ -3263,15 +3256,10 @@ dumpOneCompositeType(Archive *fout, TypeInfo *tinfo)
        PQExpBuffer query = createPQExpBuffer();
        PGresult   *res;
        int                     ntups;
-       char       *attname;
-       char       *atttypdefn;
-       char       *attbasetype;
-       const char *((*deps)[]);
-       int                     depIdx = 0;
+       int             i_attname;
+       int             i_atttypdefn;
        int                     i;
 
-       deps = malloc(sizeof(char *) * 10);
-
        /* Set proper schema search path so type references list correctly */
        selectSourceSchema(tinfo->typnamespace->nspname);
 
@@ -3279,11 +3267,12 @@ dumpOneCompositeType(Archive *fout, TypeInfo *tinfo)
        /* We assume here that remoteVersion must be at least 70300 */
 
        appendPQExpBuffer(query, "SELECT a.attname, "
-                                         "pg_catalog.format_type(a.atttypid, a.atttypmod) as atttypdefn, "
-                                         "a.atttypid as attbasetype "
+                                         "pg_catalog.format_type(a.atttypid, a.atttypmod) as atttypdefn "
                                          "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
                                          "WHERE t.oid = '%s'::pg_catalog.oid "
-                                         "AND a.attrelid = t.typrelid",
+                                         "AND a.attrelid = t.typrelid "
+                                         "AND NOT a.attisdropped "
+                                         "ORDER BY a.attnum ",
                                          tinfo->oid);
 
        res = PQexec(g_conn, query->data);
@@ -3302,37 +3291,35 @@ dumpOneCompositeType(Archive *fout, TypeInfo *tinfo)
                exit_nicely();
        }
 
-       /* DROP must be fully qualified in case same name appears in pg_catalog */
-       appendPQExpBuffer(delq, "DROP TYPE %s.",
-                                         fmtId(tinfo->typnamespace->nspname));
-       appendPQExpBuffer(delq, "%s RESTRICT;\n",
-                                         fmtId(tinfo->typname));
+       i_attname = PQfnumber(res, "attname");
+       i_atttypdefn = PQfnumber(res, "atttypdefn");
 
-       appendPQExpBuffer(q,
-                                         "CREATE TYPE %s AS (",
+       appendPQExpBuffer(q, "CREATE TYPE %s AS (",
                                          fmtId(tinfo->typname));
 
        for (i = 0; i < ntups; i++)
        {
-               attname = PQgetvalue(res, i, PQfnumber(res, "attname"));
-               atttypdefn = PQgetvalue(res, i, PQfnumber(res, "atttypdefn"));
-               attbasetype = PQgetvalue(res, i, PQfnumber(res, "attbasetype"));
+               char       *attname;
+               char       *atttypdefn;
 
-               if (i > 0)
-                       appendPQExpBuffer(q, ",\n\t %s %s", attname, atttypdefn);
-               else
-                       appendPQExpBuffer(q, "%s %s", attname, atttypdefn);
+               attname = PQgetvalue(res, i, i_attname);
+               atttypdefn = PQgetvalue(res, i, i_atttypdefn);
 
-               /* Depends on the base type */
-               (*deps)[depIdx++] = strdup(attbasetype);
+               if (i > 0)
+                       appendPQExpBuffer(q, ",\n\t");
+               appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
        }
        appendPQExpBuffer(q, ");\n");
 
-       (*deps)[depIdx++] = NULL;               /* End of List */
+       /* DROP must be fully qualified in case same name appears in pg_catalog */
+       appendPQExpBuffer(delq, "DROP TYPE %s.",
+                                         fmtId(tinfo->typnamespace->nspname));
+       appendPQExpBuffer(delq, "%s;\n",
+                                         fmtId(tinfo->typname));
 
        ArchiveEntry(fout, tinfo->oid, tinfo->typname,
                                 tinfo->typnamespace->nspname,
-                                tinfo->usename, "TYPE", deps,
+                                tinfo->usename, "TYPE", NULL,
                                 q->data, delq->data, NULL, NULL, NULL);
 
        /*** Dump Type Comments ***/
@@ -3365,7 +3352,7 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
                if (!tinfo[i].typnamespace->dump)
                        continue;
 
-               /* skip relation types for non-stand-alone type relations*/
+               /* skip complex types, except for standalone composite types */
                if (atooid(tinfo[i].typrelid) != 0 && tinfo[i].typrelkind != 'c')
                        continue;
 
@@ -5046,8 +5033,6 @@ dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
 
                        if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */
                                continue;
-                       if (tbinfo->relkind == RELKIND_COMPOSITE_TYPE) /* dumped as a type */
-                               continue;
 
                        if (tbinfo->dump)
                        {
index 64cef431701437a20b49b87563e3081c28a32ff5..4bf3b6cc4916d7b2c8978f4909a49c9a51a9febd 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2000-2002 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.66 2002/08/27 20:16:48 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.67 2002/08/29 00:17:05 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "describe.h"
@@ -196,8 +196,10 @@ describeTypes(const char *pattern, bool verbose)
        if (verbose)
                appendPQExpBuffer(&buf,
                                 "  t.typname AS \"%s\",\n"
-                                "  CASE WHEN t.typlen < 0\n"
-                                "    THEN CAST('var' AS pg_catalog.text)\n"
+                                "  CASE WHEN t.typrelid != 0\n"
+                                "      THEN CAST('tuple' AS pg_catalog.text)\n"
+                                "    WHEN t.typlen < 0\n"
+                                "      THEN CAST('var' AS pg_catalog.text)\n"
                                 "    ELSE CAST(t.typlen AS pg_catalog.text)\n"
                                 "  END AS \"%s\",\n",
                                 _("Internal name"), _("Size"));
@@ -209,12 +211,12 @@ describeTypes(const char *pattern, bool verbose)
                         "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace\n");
 
        /*
-        * do not include array types (start with underscore), do not include
-        * user relations (typrelid!=0) unless they are type relations
+        * do not include array types (start with underscore); do not include
+        * complex types (typrelid!=0) unless they are standalone composite types
         */
        appendPQExpBuffer(&buf, "WHERE (t.typrelid = 0 ");
-       appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_class c "
-                                                         "where c.oid = t.typrelid)) ");
+       appendPQExpBuffer(&buf, "OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c "
+                                                         "WHERE c.oid = t.typrelid)) ");
        appendPQExpBuffer(&buf, "AND t.typname !~ '^_'\n");
 
        /* Match name pattern against either internal or external name */
@@ -801,6 +803,10 @@ describeOneTableDetails(const char *schemaname,
                        printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
                                                          schemaname, relationname);
                        break;
+               case 'c':
+                       printfPQExpBuffer(&title, _("Composite type \"%s.%s\""),
+                                                         schemaname, relationname);
+                       break;
                default:
                        printfPQExpBuffer(&title, _("?%c? \"%s.%s\""),
                                                          tableinfo.relkind, schemaname, relationname);
index 8efb6c07a3d439f470cf8903824d8dd80d01ab68..3708a71bab9ede8646fc85c2ff3c59f87523cff4 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_type.h,v 1.130 2002/08/26 17:54:01 tgl Exp $
+ * $Id: pg_type.h,v 1.131 2002/08/29 00:17:06 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -542,6 +542,7 @@ extern Oid TypeCreate(const char *typeName,
                   Oid typeNamespace,
                   Oid assignedTypeOid,
                   Oid relationOid,
+                  char relationKind,
                   int16 internalSize,
                   char typeType,
                   char typDelim,
index 2fdb5bc210ca503dae8483334093003efdb4793b..88104565976736d15467b93a144b912113675725 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.73 2002/08/02 18:15:09 tgl Exp $
+ * $Id: executor.h,v 1.74 2002/08/29 00:17:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -123,7 +123,8 @@ extern void SetChangedParamList(Plan *node, List *newchg);
 
 typedef struct TupOutputState
 {
-       TupleDesc       tupdesc;
+       /* use "struct" here to allow forward reference */
+       struct AttInMetadata *metadata;
        DestReceiver *destfunc;
 } TupOutputState;
 
@@ -132,10 +133,15 @@ extern void do_tup_output(TupOutputState *tstate, char **values);
 extern void do_text_output_multiline(TupOutputState *tstate, char *text);
 extern void end_tup_output(TupOutputState *tstate);
 
-#define PROJECT_LINE_OF_TEXT(tstate, text_to_project) \
+/*
+ * Write a single line of text given as a C string.
+ *
+ * Should only be used with a single-TEXT-attribute tupdesc.
+ */
+#define do_text_output_oneline(tstate, text_to_emit) \
        do { \
                char *values_[1]; \
-               values_[0] = (text_to_project); \
+               values_[0] = (text_to_emit); \
                do_tup_output(tstate, values_); \
        } while (0)
 
index 294147538206bc2aa2f8e7c08f825f6d6766209d..27dbdf20e62061a9207d0bee6ca64ad464807733 100644 (file)
@@ -9,26 +9,18 @@
  *
  * Copyright (c) 2002, PostgreSQL Global Development Group
  *
+ * $Id: funcapi.h,v 1.5 2002/08/29 00:17:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef FUNCAPI_H
 #define FUNCAPI_H
 
-#include "postgres.h"
-
 #include "fmgr.h"
-#include "access/htup.h"
 #include "access/tupdesc.h"
 #include "executor/executor.h"
 #include "executor/tuptable.h"
 
-/*
- * All functions that can be called directly by fmgr must have this signature.
- * (Other functions can be called by using a handler that does have this
- * signature.)
- */
-
 
 /*-------------------------------------------------------------------------
  *     Support to ease writing Functions returning composite types
  * is derived from the TupleDesc, but it is stored here to
  * avoid redundant cpu cycles on each call to an SRF.
  */
-typedef struct
+typedef struct AttInMetadata
 {
        /* full TupleDesc */
        TupleDesc          tupdesc;
 
-       /* pointer to array of attribute "type"in finfo */
+       /* array of attribute type input function finfo */
        FmgrInfo           *attinfuncs;
 
-       /* pointer to array of attribute type typelem */
+       /* array of attribute type typelem */
        Oid                        *attelems;
 
-       /* pointer to array of attribute type typtypmod */
-       int4               *atttypmods;
-
+       /* array of attribute typmod */
+       int32              *atttypmods;
 }      AttInMetadata;
 
 /*-------------------------------------------------------------------------
@@ -63,7 +54,7 @@ typedef struct
  * This struct holds function context for Set Returning Functions.
  * Use fn_extra to hold a pointer to it across calls
  */
-typedef struct
+typedef struct FuncCallContext
 {
        /*
         * Number of times we've been called before.
@@ -120,35 +111,34 @@ typedef struct
 
 }      FuncCallContext;
 
-/*-------------------------------------------------------------------------
+/*----------
  *     Support to ease writing Functions returning composite types
  *
  * External declarations:
- * TupleDesc RelationNameGetTupleDesc(char *relname) - Use to get a TupleDesc
- *             based on the function's return type relation.
+ * TupleDesc RelationNameGetTupleDesc(const char *relname) - Use to get a
+ *             TupleDesc based on a specified relation.
  * TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases) - Use to get a
- *             TupleDesc based on the function's type oid. This can be used to get
- *             a TupleDesc for a base (scalar), or composite (relation) type.
+ *             TupleDesc based on a type OID. This can be used to get
+ *             a TupleDesc for a base (scalar) or composite (relation) type.
  * TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc) - Initialize a slot
  *             given a TupleDesc.
- * AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc) - Get a pointer
- *             to AttInMetadata based on the function's TupleDesc. AttInMetadata can
+ * AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc) - Build an
+ *             AttInMetadata struct based on the given TupleDesc. AttInMetadata can
  *             be used in conjunction with C strings to produce a properly formed
  *             tuple. Store the metadata here for use across calls to avoid redundant
  *             work.
  * HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) -
  *             build a HeapTuple given user data in C string form. values is an array
  *             of C strings, one for each attribute of the return tuple.
- * void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem) - Get
- *      an attribute "in" function and typelem value given the typeid.
  *
  * Macro declarations:
  * TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple) - get a Datum
  *             given a tuple and a slot.
+ *----------
  */
 
 /* from tupdesc.c */
-extern TupleDesc RelationNameGetTupleDesc(char *relname);
+extern TupleDesc RelationNameGetTupleDesc(const char *relname);
 extern TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases);
 
 /* from execTuples.c */
@@ -156,13 +146,11 @@ extern TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc);
 extern AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc);
 extern HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values);
 
-/* from funcapi.c */
-extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem);
-
 #define TupleGetDatum(_slot, _tuple) \
        PointerGetDatum(ExecStoreTuple(_tuple, _slot, InvalidBuffer, true))
 
-/*-------------------------------------------------------------------------
+
+/*----------
  *             Support for Set Returning Functions (SRFs)
  *
  * The basic API for SRFs looks something like:
@@ -200,6 +188,7 @@ extern void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem);
  *     }
  * }
  *
+ *----------
  */
 
 /* from funcapi.c */
@@ -208,12 +197,15 @@ extern FuncCallContext *per_MultiFuncCall(PG_FUNCTION_ARGS);
 extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx);
 
 #define SRF_IS_FIRSTCALL() (fcinfo->flinfo->fn_extra == NULL)
+
 #define SRF_FIRSTCALL_INIT() init_MultiFuncCall(fcinfo)
+
 #define SRF_PERCALL_SETUP() per_MultiFuncCall(fcinfo)
+
 #define SRF_RETURN_NEXT(_funcctx, _result) \
        do { \
                ReturnSetInfo      *rsi; \
-               _funcctx->call_cntr++; \
+               (_funcctx)->call_cntr++; \
                rsi = (ReturnSetInfo *) fcinfo->resultinfo; \
                rsi->isDone = ExprMultipleResult; \
                PG_RETURN_DATUM(_result); \
@@ -225,7 +217,6 @@ extern void end_MultiFuncCall(PG_FUNCTION_ARGS, FuncCallContext *funcctx);
                end_MultiFuncCall(fcinfo, _funcctx); \
                rsi = (ReturnSetInfo *) fcinfo->resultinfo; \
                rsi->isDone = ExprEndResult; \
-               _funcctx->slot = NULL; \
                PG_RETURN_NULL(); \
        } while (0)
 
index ee25cc62c95a44e282e7019ec272fdf0689c37b0..6e146e2ca6d67b6ca179c951b9c121b8ddb51ccb 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.71 2002/08/04 19:48:10 momjian Exp $
+ * $Id: execnodes.h,v 1.72 2002/08/29 00:17:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -509,17 +509,13 @@ typedef struct SubqueryScanState
  *             Function nodes are used to scan the results of a
  *             function appearing in FROM (typically a function returning set).
  *
- *             functionmode            function operating mode:
- *                                                     - repeated call
- *                                                     - materialize
- *                                                     - return query
+ *             functionmode            function operating mode
  *             tupdesc                         function's return tuple description
  *             tuplestorestate         private state of tuplestore.c
  *             funcexpr                        function expression being evaluated
  *             returnsTuple            does function return tuples?
  *             fn_typeid                       OID of function return type
- *             fn_typtype                      return Datum type, i.e. 'b'ase,
- *                                                     'c'atalog, or 'p'seudo
+ *             fn_typtype                      return type's typtype
  * ----------------
  */
 typedef enum FunctionMode
index bdee336b002eeb8dffb8144e36b908de3514aa9e..6f33ee4e42c9a541d8aa563d4d2754f20826c9c2 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.195 2002/08/22 03:24:01 momjian Exp $
+ * $Id: builtins.h,v 1.196 2002/08/29 00:17:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -690,6 +690,9 @@ extern Datum show_config_by_name(PG_FUNCTION_ARGS);
 extern Datum set_config_by_name(PG_FUNCTION_ARGS);
 extern Datum show_all_settings(PG_FUNCTION_ARGS);
 
+/* lockfuncs.c */
+extern Datum pg_lock_status(PG_FUNCTION_ARGS);
+
 /* catalog/pg_conversion.c */
 extern Datum pg_convert3(PG_FUNCTION_ARGS);
 
index 78d099086592a3d239c4cbf52eea11994bfec67f..2681d67139f97767c5a6d65ccaee25d25f45cec0 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lsyscache.h,v 1.59 2002/08/26 17:54:02 tgl Exp $
+ * $Id: lsyscache.h,v 1.60 2002/08/29 00:17:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -54,6 +54,7 @@ extern void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
 extern char get_typstorage(Oid typid);
 extern Node *get_typdefault(Oid typid);
 extern char get_typtype(Oid typid);
+extern void getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem);
 extern bool getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
                                                          bool *typIsVarlena);
 extern Oid getBaseType(Oid typid);
index 582859d15a5ee38010b0fc01501ce317f7f3f04f..bf7d2df24dc96b970a7693805d334dd734048666 100644 (file)
@@ -134,6 +134,44 @@ SELECT * FROM vw_getfoo;
      1 |        2 | Ed
 (2 rows)
 
+-- sql, proretset = f, prorettype = record
+DROP VIEW vw_getfoo;
+DROP FUNCTION getfoo(int);
+CREATE FUNCTION getfoo(int) RETURNS RECORD AS 'SELECT * FROM foo WHERE fooid = $1;' LANGUAGE SQL;
+SELECT * FROM getfoo(1) AS t1(fooid int, foosubid int, fooname text);
+ fooid | foosubid | fooname 
+-------+----------+---------
+     1 |        1 | Joe
+(1 row)
+
+CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1) AS 
+(fooid int, foosubid int, fooname text);
+SELECT * FROM vw_getfoo;
+ fooid | foosubid | fooname 
+-------+----------+---------
+     1 |        1 | Joe
+(1 row)
+
+-- sql, proretset = t, prorettype = record
+DROP VIEW vw_getfoo;
+DROP FUNCTION getfoo(int);
+CREATE FUNCTION getfoo(int) RETURNS setof record AS 'SELECT * FROM foo WHERE fooid = $1;' LANGUAGE SQL;
+SELECT * FROM getfoo(1) AS t1(fooid int, foosubid int, fooname text);
+ fooid | foosubid | fooname 
+-------+----------+---------
+     1 |        1 | Joe
+     1 |        2 | Ed
+(2 rows)
+
+CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1) AS
+(fooid int, foosubid int, fooname text);
+SELECT * FROM vw_getfoo;
+ fooid | foosubid | fooname 
+-------+----------+---------
+     1 |        1 | Joe
+     1 |        2 | Ed
+(2 rows)
+
 -- plpgsql, proretset = f, prorettype = b
 DROP VIEW vw_getfoo;
 DROP FUNCTION getfoo(int);
index 0ace80e5d4d5771e49bec5231d05dd201579b340..03a3a558461493884402216183427751e5ba7d8c 100644 (file)
@@ -63,6 +63,24 @@ SELECT * FROM getfoo(1) AS t1;
 CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1);
 SELECT * FROM vw_getfoo;
 
+-- sql, proretset = f, prorettype = record
+DROP VIEW vw_getfoo;
+DROP FUNCTION getfoo(int);
+CREATE FUNCTION getfoo(int) RETURNS RECORD AS 'SELECT * FROM foo WHERE fooid = $1;' LANGUAGE SQL;
+SELECT * FROM getfoo(1) AS t1(fooid int, foosubid int, fooname text);
+CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1) AS 
+(fooid int, foosubid int, fooname text);
+SELECT * FROM vw_getfoo;
+
+-- sql, proretset = t, prorettype = record
+DROP VIEW vw_getfoo;
+DROP FUNCTION getfoo(int);
+CREATE FUNCTION getfoo(int) RETURNS setof record AS 'SELECT * FROM foo WHERE fooid = $1;' LANGUAGE SQL;
+SELECT * FROM getfoo(1) AS t1(fooid int, foosubid int, fooname text);
+CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1) AS
+(fooid int, foosubid int, fooname text);
+SELECT * FROM vw_getfoo;
+
 -- plpgsql, proretset = f, prorettype = b
 DROP VIEW vw_getfoo;
 DROP FUNCTION getfoo(int);