Code review for standalone composite types, query-specified composite
authorTom Lane
Thu, 29 Aug 2002 00:17:06 +0000 (00:17 +0000)
committerTom Lane
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 @@
 
 
@@ -32,11 +32,7 @@ CREATE TYPE typename ( INPUT = 
 )
 
 CREATE TYPE typename AS
-      ( column_definition_list )
-
-where column_definition_list can be:
-
-( column_name data_type [, ... ] )
+    ( column_name data_type [, ... ] )
   
   
   
@@ -216,8 +212,12 @@ CREATE TYPE
    type names also must not conflict with table names in the same schema.)
   
 
+  
+   Base Types
+
   
-   The first form of CREATE TYPE  requires  the  
+   The first form of CREATE TYPE 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
    input_function, which
@@ -338,20 +338,27 @@ CREATE TYPE
    a row fit, but they will be kept in the main table preferentially over
    extended and external items.)
   
+  
+
+  
+   Composite Types
 
   
-   The second form of CREATE TYPE requires a column
-   definition list in the form ( column_name 
-   data_type [, ... ] ). 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 CREATE TYPE
+   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 CREATE TYPE 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.
   
+  
 
   
    Array Types
 
    
-    Whenever a user-defined data type is created, 
+    Whenever a user-defined base data type is created, 
     PostgreSQL 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:
 
-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;
 
   
  
index 5fdaf90f0acd2ea46c1a970c2cdd2cd3832d72ee..f6dd0397570a318f3aca20cd509b6450ae0eee87 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -40,10 +40,10 @@ where from_item can be:
 ( select )
     [ AS ] alias [ ( column_alias_list ) ]
 |
-table_function_name ( [ argtype [, ...] ] )
+table_function_name ( [ argument [, ...] ] )
     [ AS ] alias [ ( column_alias_list | column_definition_list ) ]
 |
-table_function_name ( [ argtype [, ...] ] )
+table_function_name ( [ argument [, ...] ] )
     AS ( column_definition_list )
 |
 from_item [ NATURAL ] join_type from_item
@@ -142,10 +142,14 @@ where from_item can be:
       alias
       
        
-   A substitute name for the preceding
-   table_name.
+   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 FROM foo AS f, the
+   remainder of the SELECT must refer to this FROM item as f
+   not 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.
        
@@ -172,12 +176,15 @@ where from_item 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
-   ( column_name data_type [, ... ] ).
-   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 record data type,
+   an alias, or the keyword AS, must be present, followed by
+   a column definition list in the form ( 
+   class="PARAMETER">column_name 
+   class="PARAMETER">data_type [, ... ] ).
+   The column definition list must match the actual number and types
+   of columns returned by the function.
        
       
      
@@ -395,7 +402,7 @@ where from_item can be:
     this was the default result, and adding sub-tables was done
     by appending * to the table name.
     This old behavior is available via the command 
-    SET SQL_Inheritance TO OFF;
+    SET SQL_Inheritance TO OFF.
    
 
    
@@ -406,16 +413,22 @@ where from_item can be:
    
 
    
-    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.
+   
+
+   
+    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
+    record.  When such a function is used in FROM, it must be
+    followed 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 composite type definition
+    must match the actual composite type returned from the function, or an
+    error will be reported at run-time.
    
 
    
@@ -827,6 +840,38 @@ SELECT name FROM distributors ORDER BY code;
     unless ORDER BY is used to constrain the order.
    
   
+
+  
+   
+    2002-08-28
+   
+   
+    FOR UPDATE Clause
+   
+   
+    
+    FOR UPDATE [ OF tablename [, ...] ]
+    
+   
+
+   
+    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.
+   
+
+   
+    If specific tables are named in FOR UPDATE, then only rows coming from
+    those tables are locked.
+   
+
+   
+    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.
+   
+  
+
  
 
  
@@ -1019,8 +1064,7 @@ SELECT * FROM distributors_2(111) AS (f1 int, f2 text);
 PostgreSQL allows one to omit 
 the FROM 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:
 
   
 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.
 
    
+
+   
+    The table-function feature is a PostgreSQL
+    extension.
+   
   
 
   
index 13e139ffbaa4fe8106e6682c4df507d2ebcae832..8eed28791a1e80fe1816165b743f5990aadeab4a 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -29,20 +29,9 @@ SELECT [ ALL | DISTINCT [ ON ( expression
     [ HAVING condition [, ...] ]
     [ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]
     [ ORDER BY expression [ ASC | DESC | USING operator ] [, ...] ]
-    [ LIMIT start , ] count | ALL } ]
+    [ LIMIT { count | ALL } ]
     [ OFFSET start ]
     [ FOR UPDATE [ OF tablename [, ...] ] ]
-
-where from_item can be:
-
-[ ONLY ] table_name [ * ]
-    [ [ AS ] alias [ ( column_alias_list ) ] ]
-|
-( select )
-    [ AS ] alias [ ( column_alias_list ) ]
-|
-from_item [ NATURAL ] join_type from_item
-    [ ON join_condition | USING ( join_column_list ) ]
   
   
   
index e457504ebefcf4a5352d3dac79ac6525cf7fa45a..60c78d0588fd7c2e2b48c8152c6b490921c74655 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -26,6 +26,7 @@ worries about funny characters.
 
 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 @@
 
 
  
@@ -10,23 +10,6 @@ $Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.56 2002/08/23 16:41:37 tgl E
   
    Introduction
 
-  
-   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.
-  
-
-  
-   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 PostgreSQL before  describing  
-   how  to  add  new types.
-  
-
   
    PostgreSQL provides four kinds of
    functions:
@@ -285,8 +268,6 @@ SELECT name, double_salary(EMP) AS dream
 
     
      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 EMP row:
 
@@ -330,12 +311,12 @@ ERROR:  function declared to return emp returns varchar instead of text at colum
          
 
     
-     In the present release of PostgreSQL
-     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,
 
 
@@ -357,8 +338,8 @@ ERROR:  parser: parse error at or near "."
     
 
     
-     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 attribute(table)  and  table.attribute
      interchangeably:
@@ -412,26 +393,73 @@ SELECT getname(new_emp());
    
 
    
-    <acronym>SQL</acronym> Table Functions<span class="marked"> (Functions Returning Sets)</span>
+    <acronym>SQL</acronym> Table Functions
 
     
      A table function is one that may be used in the FROM
-     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 SETOF sometype, the table
-     function returns multiple rows. To illustrate a SQL table function,
-     consider the following, which returns SETOF 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.
+    
+
+    
+     Here is an example:
 
 
-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;
+
+
+
+ fooid | foosubid | fooname | upper
+-------+----------+---------+-------
+     1 |        1 | Joe     | JOE
+(2 rows)
+
+
+     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.
+    
+
+    
+     Note that we only got one row out of the function.  This is because
+     we did not say SETOF.
+    
+
+   
+
+   
+    <acronym>SQL</acronym> Functions Returning Sets
+
+    
+     When an SQL function is declared as returning SETOF
+     sometype, the function's final
+     SELECT query is executed to completion, and each row it
+     outputs is returned as an element of the set.
+    
+
+    
+     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 foo has the same contents as above, and we say:
+
+
 CREATE FUNCTION getfoo(int) RETURNS setof foo AS '
     SELECT * FROM foo WHERE fooid = $1;
 ' LANGUAGE SQL;
+
 SELECT * FROM getfoo(1) AS t1;
 
 
@@ -445,14 +473,7 @@ SELECT * FROM getfoo(1) AS t1;
     
 
     
-     When an SQL function is declared as returning SETOF
-     sometype, the function's final
-     SELECT query is executed to completion, and each row it
-     outputs is returned as an element of the set.
-    
-
-    
-     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 SELECT query.  For each row that the 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)
      PG_GETARG_xxx_COPY()
      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
      PG_GETARG_xxx_COPY()
      macros guarantees a writable result.)
     
@@ -1471,8 +1493,8 @@ LANGUAGE C;
     Table Function API
 
     
-     The Table Function API assists in the creation of a user defined
-     C Language table functions ().
+     The Table Function API assists in the creation of user-defined
+     C language table functions ().
      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;
 
     
      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:
 
 #include "funcapi.h"
 
     
 
+   
+    Returning Tuples (Composite Types)
+
     
      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.
 
-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;
 
      To assist you in populating this struct, several functions and a macro
      are available. Use
 
-TupleDesc RelationNameGetTupleDesc(char *relname)
+TupleDesc RelationNameGetTupleDesc(const char *relname)
 
-     to get a TupleDesc based on the function's return type relation, or
+     to get a TupleDesc based on a specified relation, or
 
 TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
 
-     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
 
 AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)
 
      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.
     
 
     
-     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
 
 TupleTableSlot *TupleDescGetSlot(TupleDesc tupdesc)
 
      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.
     
 
     
-     If desired,
+     After constructing an AttInMetadata structure,
 
 HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
 
      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.
     
 
     
-     In order to get an attribute "in" function and typelem value given the
-     typeid, use
-
-void get_type_metadata(Oid typeid, Oid *attinfuncid, Oid *attelem)
-
+     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.
     
 
     
-     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
 
 TupleGetDatum(TupleTableSlot *slot, HeapTuple tuple)
 
-     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.
+    
+
+    
+     An example appears below.
     
 
+   
+
+   
+    Returning Sets
+
     
-     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.
+     fcinfo->flinfo->fn_extra is used to
+     hold a pointer to FuncCallContext across calls.
 
 typedef struct
 {
@@ -1639,12 +1680,13 @@ typedef struct
 
 }  FuncCallContext;
 
-     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
+     fn_extra).  Use
 
 SRF_IS_FIRSTCALL()
 
-     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
 
 SRF_FIRSTCALL_INIT()
@@ -1663,8 +1705,9 @@ SRF_PERCALL_SETUP()
 
 SRF_RETURN_NEXT(funcctx, result)
 
-     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 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
 
 SRF_RETURN_DONE(funcctx)
 
@@ -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->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->call_cntr < funcctx->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);
+    }
 }
 
     
 
     
-     An example of a simple composite returning SRF looks like:
+     A complete example of a simple SRF returning a composite type looks like:
 
 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->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->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->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->call_cntr;
+    max_calls = funcctx->max_calls;
+    slot = funcctx->slot;
+    attinmeta = funcctx->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 < 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);
+    }
 }
 
      with supporting SQL code of
 
-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
     
      See contrib/tablefunc for more examples of Table Functions.
     
+
+   
+
    
 
    
@@ -2031,23 +2080,23 @@ CREATE FUNCTION test(int, int) RETURNS int
     Table functions work wherever tables do in SELECT statements.
     For example
 
-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;
 
     are all valid statements.
    
-
-   
-    Currently, table functions are supported as SQL language functions
-    () and C language functions
-    (). See these individual sections for more
-    details.
-   
-
   
 
   
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    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 .
@@ -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);