]> granicus.if.org Git - postgresql/commitdiff
Change nextval and other sequence functions to specify their sequence
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 2 Oct 2005 23:50:16 +0000 (23:50 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 2 Oct 2005 23:50:16 +0000 (23:50 +0000)
argument as a 'regclass' value instead of a text string.  The frontend
conversion of text string to pg_class OID is now encapsulated as an
implicitly-invocable coercion from text to regclass.  This provides
backwards compatibility to the old behavior when the sequence argument
is explicitly typed as 'text'.  When the argument is just an unadorned
literal string, it will be taken as 'regclass', which means that the
stored representation will be an OID.  This solves longstanding problems
with renaming sequences that are referenced in default expressions, as
well as new-in-8.1 problems with renaming such sequences' schemas or
moving them to another schema.  All per recent discussion.
Along the way, fix some rather serious problems in dbmirror's support
for mirroring sequence operations (int4 vs int8 confusion for instance).

25 files changed:
contrib/dbmirror/MirrorSetup.sql
contrib/dbmirror/README.dbmirror
contrib/dbmirror/pending.c
doc/src/sgml/datatype.sgml
doc/src/sgml/func.sgml
doc/src/sgml/release.sgml
src/backend/catalog/dependency.c
src/backend/catalog/information_schema.sql
src/backend/commands/sequence.c
src/backend/commands/tablecmds.c
src/backend/parser/analyze.c
src/backend/utils/adt/regproc.c
src/bin/psql/describe.c
src/include/catalog/catversion.h
src/include/catalog/pg_cast.h
src/include/catalog/pg_proc.h
src/include/commands/sequence.h
src/include/utils/builtins.h
src/test/regress/expected/domain.out
src/test/regress/expected/rules.out
src/test/regress/expected/sequence.out
src/test/regress/input/constraints.source
src/test/regress/output/constraints.source
src/test/regress/sql/domain.sql
src/test/regress/sql/sequence.sql

index 19ac1b280fc23406027942a962ffffde208ea636..18c5b0693e3258d8b0519ecd99ee237d5dad1f15 100644 (file)
@@ -2,7 +2,7 @@ BEGIN;
 
 
 CREATE FUNCTION "recordchange" () RETURNS trigger AS
-'$libdir/pending.so', 'recordchange' LANGUAGE 'C';
+'$libdir/pending', 'recordchange' LANGUAGE 'C';
 
 
 
@@ -48,15 +48,15 @@ CASCADE ON DELETE CASCADE
 
 UPDATE pg_proc SET proname='nextval_pg' WHERE proname='nextval';
 
-CREATE FUNCTION pg_catalog.nextval(text) RETURNS int8  AS
-'$libdir/pending.so', 'nextval' LANGUAGE 'C' STRICT;
+CREATE FUNCTION pg_catalog.nextval(regclass) RETURNS int8 AS
+  '$libdir/pending', 'nextval_mirror' LANGUAGE 'C' STRICT;
 
 
 UPDATE pg_proc set proname='setval_pg' WHERE proname='setval';
 
-CREATE FUNCTION pg_catalog.setval("unknown",integer,boolean) RETURNS int8  AS
-'$libdir/pending.so', 'setval' LANGUAGE 'C' STRICT;
-CREATE FUNCTION pg_catalog.setval("unknown",integer) RETURNS int8  AS
-'$libdir/pending.so', 'setval' LANGUAGE 'C' STRICT;
+CREATE FUNCTION pg_catalog.setval(regclass, int8, boolean) RETURNS int8 AS
+  '$libdir/pending', 'setval3_mirror' LANGUAGE 'C' STRICT;
+CREATE FUNCTION pg_catalog.setval(regclass, int8) RETURNS int8 AS
+  '$libdir/pending', 'setval_mirror' LANGUAGE 'C' STRICT;
 
 COMMIT;
index 8dfdf7a84b02722f21c4fa985007d0c61a5b60d4..1c4c9a09140bc750b7145cce55b3a8115eb2fa06 100644 (file)
@@ -56,7 +56,7 @@ Pending tables.
 
 Requirements:
 ---------------------------------
--PostgreSQL-7.4 (Older versions are no longer supported)
+-PostgreSQL-8.1 (Older versions are no longer supported)
 -Perl 5.6 or 5.8 (Other versions might work)
 -PgPerl (http://gborg.postgresql.org/project/pgperl/projdisplay.php)
 
@@ -177,15 +177,15 @@ If you are starting with an empty master database then the slave should
 be empty as well.  Otherwise use pg_dump to ensure that the slave database
 tables are initially identical to the master.
 
-6) Add entries in the MirrorHost table.
+6) Add entries in the dbmirror_MirrorHost table.
 
-Each slave database must have an entry in the MirrorHost table.
+Each slave database must have an entry in the dbmirror_MirrorHost table.
 
-The name of the host in the MirrorHost table must exactly match the
+The name of the host in the dbmirror_MirrorHost table must exactly match the
 slaveHost variable for that slave in the configuration file.
 
 For example
-INSERT INTO "MirrorHost" ("SlaveName") VALUES ('backup_system');
+INSERT INTO dbmirror_MirrorHost (SlaveName) VALUES ('backup_system');
 
 
 6)  Start DBMirror.pl
index 3ed9d2128cfdb4ab6e051e094bc0fe4f6761c15a..36f5837bbd8bc1bad77d7a6e9e4d17af2d94274c 100644 (file)
@@ -1,7 +1,7 @@
 /****************************************************************************
  * pending.c
- * $Id: pending.c,v 1.21 2005/03/29 00:16:48 tgl Exp $
- * $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.21 2005/03/29 00:16:48 tgl Exp $
+ * $Id: pending.c,v 1.22 2005/10/02 23:50:05 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.22 2005/10/02 23:50:05 tgl Exp $
  *
  * This file contains a trigger for Postgresql-7.x to record changes to tables
  * to a pending table for mirroring.
  *
  *
  ***************************************************************************/
-#include <postgres.h>
+#include "postgres.h"
 
-#include <executor/spi.h>
-#include <commands/trigger.h>
-#include <utils/lsyscache.h>
-#include <utils/array.h>
+#include "executor/spi.h"
+#include "commands/sequence.h"
+#include "commands/trigger.h"
+#include "utils/lsyscache.h"
+#include "utils/array.h"
 
 enum FieldUsage
 {
@@ -81,11 +82,11 @@ PG_FUNCTION_INFO_V1(recordchange);
 
 
 
-extern Datum nextval(PG_FUNCTION_ARGS);
-extern Datum setval(PG_FUNCTION_ARGS);
+extern Datum setval_mirror(PG_FUNCTION_ARGS);
+extern Datum setval3_mirror(PG_FUNCTION_ARGS);
+extern Datum nextval_mirror(PG_FUNCTION_ARGS);
 
-int saveSequenceUpdate(const text *sequenceName,
-                                  int nextSequenceValue);
+static void saveSequenceUpdate(Oid relid, int64 nextValue, bool iscalled);
 
 
 /*****************************************************************************
@@ -310,11 +311,9 @@ storeKeyInfo(char *cpTableName, HeapTuple tTupleData,
                SPI_pfree(cpKeyData);
 
        if (iRetCode != SPI_OK_INSERT)
-       {
-               ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION)
-                                               ,errmsg("error inserting row in pendingDelete")));
-               return -1;
-       }
+               ereport(ERROR,
+                               (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
+                                errmsg("error inserting row in pendingDelete")));
 
        debug_msg("insert successful");
 
@@ -583,161 +582,75 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc, Oid tableOid,
 }
 
 
-PG_FUNCTION_INFO_V1(setval);
+/*
+ * Support for mirroring sequence objects.
+ */
+
+PG_FUNCTION_INFO_V1(setval_mirror);
 
 Datum
-setval(PG_FUNCTION_ARGS)
+setval_mirror(PG_FUNCTION_ARGS)
 {
+       Oid                     relid = PG_GETARG_OID(0);
+       int64           next = PG_GETARG_INT64(1);
+       int64           result;
 
+       result = DatumGetInt64(DirectFunctionCall2(setval_oid,
+                                                                                          ObjectIdGetDatum(relid),
+                                                                                          Int64GetDatum(next)));
 
-       text       *sequenceName;
-
-       Oid                     setvalArgTypes[3] = {TEXTOID, INT4OID,BOOLOID};
-       int                     nextValue;
-       void       *setvalPlan = NULL;
-       Datum           setvalData[3];
-       const char *setvalQuery = "SELECT setval_pg($1,$2,$3)";
-       int                     ret;
-        char                    is_called;
-
-       sequenceName = PG_GETARG_TEXT_P(0);
-       nextValue = PG_GETARG_INT32(1);
-       is_called = PG_GETARG_BOOL(2);
-
-       setvalData[0] = PointerGetDatum(sequenceName);
-       setvalData[1] = Int32GetDatum(nextValue);
-       if(PG_NARGS() > 2)
-         {
-           setvalData[2] = BoolGetDatum(is_called);
-         }
-       else
-         {
-           setvalData[2]=1;
-         }
-
-       if (SPI_connect() < 0)
-       {
-               ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
-                                       errmsg("dbmirror:setval could not connect to SPI")));
-               return -1;
-       }
-
-       setvalPlan = SPI_prepare(setvalQuery, 3, setvalArgTypes);
-       if (setvalPlan == NULL)
-       {
-               ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
-                                         errmsg("dbmirror:setval could not prepare plan")));
-               return -1;
-       }
-
-       ret = SPI_execp(setvalPlan, setvalData, NULL, 1);
-
-       if (ret != SPI_OK_SELECT || SPI_processed != 1)
-               return -1;
-
-       debug_msg2("dbmirror:setval: setval_pg returned ok:%d", nextValue);
-
-       ret = saveSequenceUpdate(sequenceName, nextValue);
-
-       SPI_pfree(setvalPlan);
-
-       SPI_finish();
-       debug_msg("dbmirror:setval about to return");
-       return Int64GetDatum(nextValue);
+       saveSequenceUpdate(relid, result, true);
 
+       PG_RETURN_INT64(result);
 }
 
-
-
-PG_FUNCTION_INFO_V1(nextval);
+PG_FUNCTION_INFO_V1(setval3_mirror);
 
 Datum
-nextval(PG_FUNCTION_ARGS)
+setval3_mirror(PG_FUNCTION_ARGS)
 {
-       text       *sequenceName;
-
-       const char *nextvalQuery = "SELECT nextval_pg($1)";
-       Oid                     nextvalArgTypes[1] = {TEXTOID};
-       void       *nextvalPlan = NULL;
-       Datum           nextvalData[1];
-
-
-       int                     ret;
-       HeapTuple       resTuple;
-       char            isNull;
-       int                     nextSequenceValue;
-
-
-
-       debug_msg("dbmirror:nextval Starting pending.so:nextval");
-
-
-       sequenceName = PG_GETARG_TEXT_P(0);
-
-       if (SPI_connect() < 0)
-       {
-               ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
-                                  errmsg("dbmirror:nextval could not connect to SPI")));
-               return -1;
-       }
-
-       nextvalPlan = SPI_prepare(nextvalQuery, 1, nextvalArgTypes);
-
-
-       debug_msg("prepared plan to call nextval_pg");
-
-
-       if (nextvalPlan == NULL)
-       {
-               ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
-                                               errmsg("dbmirror:nextval error creating plan")));
-               return -1;
-       }
-       nextvalData[0] = PointerGetDatum(sequenceName);
-
-       ret = SPI_execp(nextvalPlan, nextvalData, NULL, 1);
-
-       debug_msg("dbmirror:Executed call to nextval_pg");
-
-
-       if (ret != SPI_OK_SELECT || SPI_processed != 1)
-               return -1;
-
-       resTuple = SPI_tuptable->vals[0];
+       Oid                     relid = PG_GETARG_OID(0);
+       int64           next = PG_GETARG_INT64(1);
+       bool            iscalled = PG_GETARG_BOOL(2);
+       int64           result;
 
-       debug_msg("dbmirror:nextval Set resTuple");
-
-       nextSequenceValue = *(unsigned int *) (DatumGetPointer(SPI_getbinval(resTuple,
-                                                                                                  SPI_tuptable->tupdesc,
-                                                                                                                  1, &isNull)));
+       result = DatumGetInt64(DirectFunctionCall3(setval3_oid,
+                                                                                          ObjectIdGetDatum(relid),
+                                                                                          Int64GetDatum(next),
+                                                                                          BoolGetDatum(iscalled)));
 
+       saveSequenceUpdate(relid, result, iscalled);
 
+       PG_RETURN_INT64(result);
+}
 
-       debug_msg2("dbmirror:nextval Set SPI_getbinval:%d", nextSequenceValue);
+PG_FUNCTION_INFO_V1(nextval_mirror);
 
+Datum
+nextval_mirror(PG_FUNCTION_ARGS)
+{
+       Oid                     relid = PG_GETARG_OID(0);
+       int64           result;
 
-       saveSequenceUpdate(sequenceName, nextSequenceValue);
-       SPI_pfree(resTuple);
-       SPI_pfree(nextvalPlan);
+       result = DatumGetInt64(DirectFunctionCall1(nextval_oid,
+                                                                                          ObjectIdGetDatum(relid)));
 
-       SPI_finish();
+       saveSequenceUpdate(relid, result, true);
 
-       return Int64GetDatum(nextSequenceValue);
+       PG_RETURN_INT64(result);
 }
 
 
-int
-saveSequenceUpdate(const text *sequenceName,
-                                  int nextSequenceVal)
+static void
+saveSequenceUpdate(Oid relid, int64 nextValue, bool iscalled)
 {
-
-       Oid                     insertArgTypes[2] = {TEXTOID, INT4OID};
+       Oid                     insertArgTypes[2] = {NAMEOID, INT4OID};
        Oid                     insertDataArgTypes[1] = {NAMEOID};
-       void       *insertPlan = NULL;
-       void       *insertDataPlan = NULL;
+       void       *insertPlan;
+       void       *insertDataPlan;
        Datum           insertDatum[2];
        Datum           insertDataDatum[1];
-       char            nextSequenceText[32];
+       char            nextSequenceText[64];
 
        const char *insertQuery =
        "INSERT INTO dbmirror_Pending (TableName,Op,XID) VALUES" \
@@ -746,36 +659,50 @@ saveSequenceUpdate(const text *sequenceName,
        "INSERT INTO dbmirror_PendingData(SeqId,IsKey,Data) VALUES " \
        "(currval('dbmirror_pending_seqid_seq'),'t',$1)";
 
-       int                     ret;
-
+       if (SPI_connect() < 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+                                errmsg("dbmirror:savesequenceupdate could not connect to SPI")));
 
        insertPlan = SPI_prepare(insertQuery, 2, insertArgTypes);
        insertDataPlan = SPI_prepare(insertDataQuery, 1, insertDataArgTypes);
 
-       debug_msg("Prepared insert query");
-
-
        if (insertPlan == NULL || insertDataPlan == NULL)
-               ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), errmsg("dbmirror:nextval error creating plan")));
+               ereport(ERROR,
+                               (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+                                errmsg("dbmirror:savesequenceupdate error creating plan")));
 
+       insertDatum[0] = PointerGetDatum(get_rel_name(relid));
        insertDatum[1] = Int32GetDatum(GetCurrentTransactionId());
-       insertDatum[0] = PointerGetDatum(sequenceName);
 
-       sprintf(nextSequenceText, "%d", nextSequenceVal);
+       snprintf(nextSequenceText, sizeof(nextSequenceText),
+                        INT64_FORMAT ",'%c'",
+                        nextValue, iscalled ? 't' : 'f');
+
+       /*
+        * note type cheat here: we prepare a C string and then claim it is a
+        * NAME, which the system will coerce to varchar for us.
+        */
        insertDataDatum[0] = PointerGetDatum(nextSequenceText);
-       debug_msg2("dbmirror:savesequenceupdate: Setting value %s",
+
+       debug_msg2("dbmirror:savesequenceupdate: Setting value as %s",
                           nextSequenceText);
 
        debug_msg("dbmirror:About to execute insert query");
 
-       ret = SPI_execp(insertPlan, insertDatum, NULL, 1);
+       if (SPI_execp(insertPlan, insertDatum, NULL, 1) != SPI_OK_INSERT)
+               ereport(ERROR,
+                               (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+                                errmsg("error inserting row in dbmirror_Pending")));
 
-       ret = SPI_execp(insertDataPlan, insertDataDatum, NULL, 1);
+       if (SPI_execp(insertDataPlan, insertDataDatum, NULL, 1) != SPI_OK_INSERT)
+               ereport(ERROR,
+                               (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+                                errmsg("error inserting row in dbmirror_PendingData")));
 
        debug_msg("dbmirror:Insert query finished");
        SPI_pfree(insertPlan);
        SPI_pfree(insertDataPlan);
 
-       return ret;
-
+       SPI_finish();
 }
index 099f5e8ab671b2c44505c1eabea6da2844293b29..48caaa2994ffcb26a6e24b340ff6e909f57772c8 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.159 2005/09/13 15:24:56 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.160 2005/10/02 23:50:06 tgl Exp $
 -->
 
  <chapter id="datatype">
@@ -3113,6 +3113,18 @@ SELECT * FROM pg_attribute
     operand.
    </para>
 
+   <para>
+    An additional property of the OID alias types is that if a
+    constant of one of these types appears in a stored expression
+    (such as a column default expression or view), it creates a dependency
+    on the referenced object.  For example, if a column has a default
+    expression <literal>nextval('my_seq'::regclass)</>,
+    <productname>PostgreSQL</productname>
+    understands that the default expression depends on the sequence
+    <literal>my_seq</>; the system will not let the sequence be dropped
+    without first removing the default expression.
+   </para>
+
    <para>
     Another identifier type used by the system is <type>xid</>, or transaction
     (abbreviated <abbrev>xact</>) identifier.  This is the data type of the system columns
index c6c9d87e8a5024b3cbcfffa9f02daa7404e3f208..a641db7ee7481c785bc329c25d2e162b56b30ece 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.286 2005/09/16 05:35:39 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.287 2005/10/02 23:50:06 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -6875,12 +6875,12 @@ SELECT TIMESTAMP 'now';  -- incorrect for use with DEFAULT
 
      <tbody>
       <row>
-        <entry><literal><function>nextval</function>(<type>text</type>)</literal></entry>
+        <entry><literal><function>nextval</function>(<type>regclass</type>)</literal></entry>
         <entry><type>bigint</type></entry>
         <entry>Advance sequence and return new value</entry>
       </row>
       <row>
-        <entry><literal><function>currval</function>(<type>text</type>)</literal></entry>
+        <entry><literal><function>currval</function>(<type>regclass</type>)</literal></entry>
         <entry><type>bigint</type></entry>
         <entry>Return value most recently obtained with
         <function>nextval</function> for specified sequence</entry>
@@ -6891,12 +6891,12 @@ SELECT TIMESTAMP 'now';  -- incorrect for use with DEFAULT
         <entry>Return value most recently obtained with <function>nextval</function></entry>
       </row>
       <row>
-        <entry><literal><function>setval</function>(<type>text</type>, <type>bigint</type>)</literal></entry>
+        <entry><literal><function>setval</function>(<type>regclass</type>, <type>bigint</type>)</literal></entry>
         <entry><type>bigint</type></entry>
         <entry>Set sequence's current value</entry>
       </row>
       <row>
-        <entry><literal><function>setval</function>(<type>text</type>, <type>bigint</type>, <type>boolean</type>)</literal></entry>
+        <entry><literal><function>setval</function>(<type>regclass</type>, <type>bigint</type>, <type>boolean</type>)</literal></entry>
         <entry><type>bigint</type></entry>
         <entry>Set sequence's current value and <literal>is_called</literal> flag</entry>
       </row>
@@ -6905,11 +6905,15 @@ SELECT TIMESTAMP 'now';  -- incorrect for use with DEFAULT
    </table>
 
   <para>
-   For largely historical reasons, the sequence to be operated on by a
-   sequence-function call is specified by a text-string argument.  To
+   The sequence to be operated on by a sequence-function call is specified by
+   a <type>regclass</> argument, which is just the OID of the sequence in the
+   <structname>pg_class</> system catalog.  You do not have to look up the
+   OID by hand, however, since the <type>regclass</> datatype's input
+   converter will do the work for you.  Just write the sequence name enclosed
+   in single quotes, so that it looks like a literal constant.  To
    achieve some compatibility with the handling of ordinary
-   <acronym>SQL</acronym> names, the sequence functions convert their
-   argument to lowercase unless the string is double-quoted.  Thus
+   <acronym>SQL</acronym> names, the string will be converted to lowercase
+   unless it contains double quotes around the sequence name.  Thus
 <programlisting>
 nextval('foo')      <lineannotation>operates on sequence <literal>foo</literal></>
 nextval('FOO')      <lineannotation>operates on sequence <literal>foo</literal></>
@@ -6921,10 +6925,46 @@ nextval('myschema.foo')     <lineannotation>operates on <literal>myschema.foo</l
 nextval('"myschema".foo')   <lineannotation>same as above</lineannotation>
 nextval('foo')              <lineannotation>searches search path for <literal>foo</literal></>
 </programlisting>
-   Of course, the text argument can be the result of an expression,
-   not only a simple literal, which is occasionally useful.
+   See <xref linkend="datatype-oid"> for more information about
+   <type>regclass</>.
   </para>
 
+  <note>
+   <para>
+    Before <productname>PostgreSQL</productname> 8.1, the arguments of the
+    sequence functions were of type <type>text</>, not <type>regclass</>, and
+    the above-described conversion from a text string to an OID value would
+    happen at runtime during each call.  For backwards compatibility, this
+    facility still exists, but internally it is now handled as an implicit
+    coercion from <type>text</> to <type>regclass</> before the function is
+    invoked.
+   </para>
+
+   <para>
+    When you write the argument of a sequence function as an unadorned
+    literal string, it becomes a constant of type <type>regclass</>.
+    Since this is really just an OID, it will track the originally
+    identified sequence despite later renaming, schema reassignment,
+    etc.  This <quote>early binding</> behavior is usually desirable for
+    sequence references in column defaults and views.  But sometimes you will
+    want <quote>late binding</> where the sequence reference is resolved
+    at runtime.  To get late-binding behavior, force the constant to be
+    stored as a <type>text</> constant instead of <type>regclass</>:
+<programlisting>
+nextval('foo'::text)      <lineannotation><literal>foo</literal> is looked up at runtime</>
+</programlisting>
+    Note that late binding was the only behavior supported in
+    <productname>PostgreSQL</productname> releases before 8.1, so you
+    may need to do this to preserve the semantics of old applications.
+   </para>
+
+   <para>
+    Of course, the argument of a sequence function can be an expression
+    as well as a constant.  If it is a text expression then the implicit
+    coercion will result in a run-time lookup.
+   </para>
+  </note>
+
   <para>
    The available sequence functions are:
 
@@ -7001,6 +7041,14 @@ SELECT setval('foo', 42, false);    <lineannotation>Next <function>nextval</> wi
     </variablelist>
   </para>
 
+  <para>
+   If a sequence object has been created with default parameters,
+   <function>nextval</function> calls on it will return successive values
+   beginning with 1.  Other behaviors can be obtained by using
+   special parameters in the <xref linkend="sql-createsequence" endterm="sql-createsequence-title"> command;
+   see its command reference page for more information.
+  </para>
+
   <important>
    <para>
     To avoid blocking of concurrent transactions that obtain numbers from the
@@ -7013,14 +7061,6 @@ SELECT setval('foo', 42, false);    <lineannotation>Next <function>nextval</> wi
    </para>
   </important>
 
-  <para>
-   If a sequence object has been created with default parameters,
-   <function>nextval</function> calls on it will return successive values
-   beginning with 1.  Other behaviors can be obtained by using
-   special parameters in the <xref linkend="sql-createsequence" endterm="sql-createsequence-title"> command;
-   see its command reference page for more information.
-  </para>
-
  </sect1>
 
 
index 092179f01bced875a03a4c9df3fe530da4143280..37d67a94797f1eb667c39a67f5d3df1b11e53428 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/release.sgml,v 1.380 2005/09/28 21:22:12 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/release.sgml,v 1.381 2005/10/02 23:50:06 tgl Exp $
 
 Typical markup:
 
@@ -391,6 +391,25 @@ pg_[A-Za-z0-9_]                 <application>
       </para>
      </listitem>
 
+     <listitem>
+      <para>
+       Sequence arguments of <function>nextval()</> and related functions
+       are now bound early by default (Tom)
+      </para>
+      <para>
+       When an expression like <literal>nextval('myseq')</> appears in a
+       column default expression or view, the referenced sequence (here
+       <literal>myseq</>) is now looked up immediately, and its pg_class
+       OID is placed in the stored expression.  This representation will
+       survive renaming of the referenced sequence, as well as changes in
+       schema search paths.  The system also understands that the sequence
+       reference represents a dependency, so the sequence cannot be dropped
+       without dropping the referencing object.  To get the old behavior of
+       run-time lookup of the sequence by name, cast the argument to
+       <type>text</>, for example <literal>nextval('myseq'::text)</>.
+      </para>
+     </listitem>
+
      <listitem>
       <para>
        In <application>psql</application>, treat unquoted
index 227b21c6564b15ca8d979ac20494da79a27dbe47..8060055ff72869abc17b175e30bf9984c1025607 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.45 2005/07/07 20:39:57 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.46 2005/10/02 23:50:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1030,6 +1030,59 @@ find_expr_references_walker(Node *node,
                }
                return false;
        }
+       if (IsA(node, Const))
+       {
+               Const      *con = (Const *) node;
+               Oid                     objoid;
+
+               /*
+                * If it's a regclass or similar literal referring to an existing
+                * object, add a reference to that object.  (Currently, only the
+                * regclass case has any likely use, but we may as well handle all
+                * the OID-alias datatypes consistently.)
+                */
+               if (!con->constisnull)
+               {
+                       switch (con->consttype)
+                       {
+                               case REGPROCOID:
+                               case REGPROCEDUREOID:
+                                       objoid = DatumGetObjectId(con->constvalue);
+                                       if (SearchSysCacheExists(PROCOID,
+                                                                                        ObjectIdGetDatum(objoid),
+                                                                                        0, 0, 0))
+                                               add_object_address(OCLASS_PROC, objoid, 0,
+                                                                                  &context->addrs);
+                                       break;
+                               case REGOPEROID:
+                               case REGOPERATOROID:
+                                       objoid = DatumGetObjectId(con->constvalue);
+                                       if (SearchSysCacheExists(OPEROID,
+                                                                                        ObjectIdGetDatum(objoid),
+                                                                                        0, 0, 0))
+                                               add_object_address(OCLASS_OPERATOR, objoid, 0,
+                                                                                  &context->addrs);
+                                       break;
+                               case REGCLASSOID:
+                                       objoid = DatumGetObjectId(con->constvalue);
+                                       if (SearchSysCacheExists(RELOID,
+                                                                                        ObjectIdGetDatum(objoid),
+                                                                                        0, 0, 0))
+                                               add_object_address(OCLASS_CLASS, objoid, 0,
+                                                                                  &context->addrs);
+                                       break;
+                               case REGTYPEOID:
+                                       objoid = DatumGetObjectId(con->constvalue);
+                                       if (SearchSysCacheExists(TYPEOID,
+                                                                                        ObjectIdGetDatum(objoid),
+                                                                                        0, 0, 0))
+                                               add_object_address(OCLASS_TYPE, objoid, 0,
+                                                                                  &context->addrs);
+                                       break;
+                       }
+               }
+               return false;
+       }
        if (IsA(node, FuncExpr))
        {
                FuncExpr   *funcexpr = (FuncExpr *) node;
index b56117a806f22003650992c8a86506b20e9a300f..4671f81f9148ac7a9cf0b7d164416c558bac068b 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2003-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.30 2005/07/26 00:04:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.31 2005/10/02 23:50:07 tgl Exp $
  */
 
 /*
@@ -357,7 +357,8 @@ CREATE VIEW columns AS
            CAST(a.attname AS sql_identifier) AS column_name,
            CAST(a.attnum AS cardinal_number) AS ordinal_position,
            CAST(
-             CASE WHEN pg_has_role(c.relowner, 'MEMBER') THEN ad.adsrc ELSE null END
+             CASE WHEN pg_has_role(c.relowner, 'MEMBER') THEN pg_get_expr(ad.adbin, ad.adrelid)
+                  ELSE null END
              AS character_data)
              AS column_default,
            CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END
index 5af9ba55b6e128c4deec48c418f1d4c563470e0e..9bf801f2308657c8fa04efb6ac000c7257cfa736 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.123 2005/06/07 07:08:34 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.124 2005/10/02 23:50:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,12 +75,12 @@ static SeqTable seqtab = NULL;      /* Head of list of SeqTable items */
  */
 static SeqTableData *last_used_seq = NULL;
 
+static int64 nextval_internal(Oid relid);
 static void acquire_share_lock(Relation seqrel, SeqTable seq);
-static void init_sequence(RangeVar *relation,
-                         SeqTable *p_elm, Relation *p_rel);
+static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
 static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
 static void init_params(List *options, Form_pg_sequence new, bool isInit);
-static void do_setval(RangeVar *sequence, int64 next, bool iscalled);
+static void do_setval(Oid relid, int64 next, bool iscalled);
 
 /*
  * DefineSequence
@@ -302,6 +302,7 @@ DefineSequence(CreateSeqStmt *seq)
 void
 AlterSequence(AlterSeqStmt *stmt)
 {
+       Oid                     relid;
        SeqTable        elm;
        Relation        seqrel;
        Buffer          buf;
@@ -310,7 +311,8 @@ AlterSequence(AlterSeqStmt *stmt)
        FormData_pg_sequence new;
 
        /* open and AccessShareLock sequence */
-       init_sequence(stmt->sequence, &elm, &seqrel);
+       relid = RangeVarGetRelid(stmt->sequence, false);
+       init_sequence(relid, &elm, &seqrel);
 
        /* allow ALTER to sequence owner only */
        if (!pg_class_ownercheck(elm->relid, GetUserId()))
@@ -372,11 +374,35 @@ AlterSequence(AlterSeqStmt *stmt)
 }
 
 
+/*
+ * Note: nextval with a text argument is no longer exported as a pg_proc
+ * entry, but we keep it around to ease porting of C code that may have
+ * called the function directly.
+ */
 Datum
 nextval(PG_FUNCTION_ARGS)
 {
        text       *seqin = PG_GETARG_TEXT_P(0);
        RangeVar   *sequence;
+       Oid                     relid;
+
+       sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
+       relid = RangeVarGetRelid(sequence, false);
+
+       PG_RETURN_INT64(nextval_internal(relid));
+}
+
+Datum
+nextval_oid(PG_FUNCTION_ARGS)
+{
+       Oid                     relid = PG_GETARG_OID(0);
+
+       PG_RETURN_INT64(nextval_internal(relid));
+}
+
+static int64
+nextval_internal(Oid relid)
+{
        SeqTable        elm;
        Relation        seqrel;
        Buffer          buf;
@@ -394,23 +420,21 @@ nextval(PG_FUNCTION_ARGS)
                                rescnt = 0;
        bool            logit = false;
 
-       sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
-
        /* open and AccessShareLock sequence */
-       init_sequence(sequence, &elm, &seqrel);
+       init_sequence(relid, &elm, &seqrel);
 
        if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 errmsg("permission denied for sequence %s",
-                                               sequence->relname)));
+                                               RelationGetRelationName(seqrel))));
 
        if (elm->last != elm->cached)           /* some numbers were cached */
        {
                last_used_seq = elm;
                elm->last += elm->increment;
                relation_close(seqrel, NoLock);
-               PG_RETURN_INT64(elm->last);
+               return elm->last;
        }
 
        /* lock page' buffer and read tuple */
@@ -481,7 +505,7 @@ nextval(PG_FUNCTION_ARGS)
                                        ereport(ERROR,
                                          (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                           errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
-                                                         sequence->relname, buf)));
+                                                         RelationGetRelationName(seqrel), buf)));
                                }
                                next = minv;
                        }
@@ -504,7 +528,7 @@ nextval(PG_FUNCTION_ARGS)
                                        ereport(ERROR,
                                          (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                           errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
-                                                         sequence->relname, buf)));
+                                                         RelationGetRelationName(seqrel), buf)));
                                }
                                next = maxv;
                        }
@@ -576,34 +600,31 @@ nextval(PG_FUNCTION_ARGS)
 
        relation_close(seqrel, NoLock);
 
-       PG_RETURN_INT64(result);
+       return result;
 }
 
 Datum
-currval(PG_FUNCTION_ARGS)
+currval_oid(PG_FUNCTION_ARGS)
 {
-       text       *seqin = PG_GETARG_TEXT_P(0);
-       RangeVar   *sequence;
+       Oid                     relid = PG_GETARG_OID(0);
+       int64           result;
        SeqTable        elm;
        Relation        seqrel;
-       int64           result;
-
-       sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
 
        /* open and AccessShareLock sequence */
-       init_sequence(sequence, &elm, &seqrel);
+       init_sequence(relid, &elm, &seqrel);
 
        if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK)
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 errmsg("permission denied for sequence %s",
-                                               sequence->relname)));
+                                               RelationGetRelationName(seqrel))));
 
        if (elm->increment == 0)        /* nextval/read_info were not called */
                ereport(ERROR,
                                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                 errmsg("currval of sequence \"%s\" is not yet defined in this session",
-                                               sequence->relname)));
+                                               RelationGetRelationName(seqrel))));
 
        result = elm->last;
 
@@ -645,6 +666,7 @@ lastval(PG_FUNCTION_ARGS)
 
        result = last_used_seq->last;
        relation_close(seqrel, NoLock);
+
        PG_RETURN_INT64(result);
 }
 
@@ -662,7 +684,7 @@ lastval(PG_FUNCTION_ARGS)
  * sequence.
  */
 static void
-do_setval(RangeVar *sequence, int64 next, bool iscalled)
+do_setval(Oid relid, int64 next, bool iscalled)
 {
        SeqTable        elm;
        Relation        seqrel;
@@ -670,13 +692,13 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled)
        Form_pg_sequence seq;
 
        /* open and AccessShareLock sequence */
-       init_sequence(sequence, &elm, &seqrel);
+       init_sequence(relid, &elm, &seqrel);
 
        if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
                ereport(ERROR,
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                 errmsg("permission denied for sequence %s",
-                                               sequence->relname)));
+                                               RelationGetRelationName(seqrel))));
 
        /* lock page' buffer and read tuple */
        seq = read_info(elm, seqrel, &buf);
@@ -693,7 +715,8 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled)
                ereport(ERROR,
                                (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                                 errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)",
-                                               bufv, sequence->relname, bufm, bufx)));
+                                               bufv, RelationGetRelationName(seqrel),
+                                               bufm, bufx)));
        }
 
        /* save info in local cache */
@@ -753,15 +776,12 @@ do_setval(RangeVar *sequence, int64 next, bool iscalled)
  * See do_setval for discussion.
  */
 Datum
-setval(PG_FUNCTION_ARGS)
+setval_oid(PG_FUNCTION_ARGS)
 {
-       text       *seqin = PG_GETARG_TEXT_P(0);
+       Oid                     relid = PG_GETARG_OID(0);
        int64           next = PG_GETARG_INT64(1);
-       RangeVar   *sequence;
 
-       sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
-
-       do_setval(sequence, next, true);
+       do_setval(relid, next, true);
 
        PG_RETURN_INT64(next);
 }
@@ -771,16 +791,13 @@ setval(PG_FUNCTION_ARGS)
  * See do_setval for discussion.
  */
 Datum
-setval_and_iscalled(PG_FUNCTION_ARGS)
+setval3_oid(PG_FUNCTION_ARGS)
 {
-       text       *seqin = PG_GETARG_TEXT_P(0);
+       Oid                     relid = PG_GETARG_OID(0);
        int64           next = PG_GETARG_INT64(1);
        bool            iscalled = PG_GETARG_BOOL(2);
-       RangeVar   *sequence;
 
-       sequence = makeRangeVarFromNameList(textToQualifiedNameList(seqin));
-
-       do_setval(sequence, next, iscalled);
+       do_setval(relid, next, iscalled);
 
        PG_RETURN_INT64(next);
 }
@@ -822,15 +839,14 @@ acquire_share_lock(Relation seqrel, SeqTable seq)
 }
 
 /*
- * Given a relation name, open and lock the sequence.  p_elm and p_rel are
+ * Given a relation OID, open and lock the sequence.  p_elm and p_rel are
  * output parameters.
  */
 static void
-init_sequence(RangeVar *relation, SeqTable *p_elm, Relation *p_rel)
+init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
 {
-       Oid                     relid = RangeVarGetRelid(relation, false);
-       volatile SeqTable elm;
        Relation        seqrel;
+       volatile SeqTable elm;
 
        /*
         * Open the sequence relation.
@@ -841,7 +857,7 @@ init_sequence(RangeVar *relation, SeqTable *p_elm, Relation *p_rel)
                ereport(ERROR,
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                 errmsg("\"%s\" is not a sequence",
-                                               relation->relname)));
+                                               RelationGetRelationName(seqrel))));
 
        /* Look to see if we already have a seqtable entry for relation */
        for (elm = seqtab; elm != NULL; elm = elm->next)
index b3d0e017f15fc6c1e1537d5ef0ce2858aa321971..b2877cebb760adc18c8b5353d3dd84426ca44831 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.171 2005/09/24 22:54:36 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.172 2005/10/02 23:50:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -168,8 +168,6 @@ static void AlterIndexNamespaces(Relation classRel, Relation rel,
 static void AlterSeqNamespaces(Relation classRel, Relation rel,
                                                           Oid oldNspOid, Oid newNspOid,
                                                           const char *newNspName);
-static void RebuildSerialDefaultExpr(Relation rel, AttrNumber attnum,
-                                                                        const char *seqname, const char *nspname);
 static int transformColumnNameList(Oid relId, List *colList,
                                                int16 *attnums, Oid *atttypids);
 static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
@@ -6313,15 +6311,6 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
                 */
                AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype,
                                                                   newNspOid, false);
-               /*
-                * And we need to rebuild the column default expression that
-                * relies on this sequence.
-                */
-               if (depForm->refobjsubid > 0)
-                       RebuildSerialDefaultExpr(rel,
-                                                                        depForm->refobjsubid,
-                                                                        RelationGetRelationName(seqRel),
-                                                                        newNspName);
 
                /* Now we can close it.  Keep the lock till end of transaction. */
                relation_close(seqRel, NoLock);
@@ -6332,56 +6321,6 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
        relation_close(depRel, AccessShareLock);
 }
 
-/*
- * Rebuild the default expression for a SERIAL column identified by rel
- * and attnum.  This is annoying, but we have to do it because the
- * stored expression has the schema name as a text constant.
- *
- * The caller must be sure the specified column is really a SERIAL column,
- * because no further checks are done here.
- */
-static void
-RebuildSerialDefaultExpr(Relation rel, AttrNumber attnum,
-                                                const char *seqname, const char *nspname)
-{
-       char       *qstring;
-       A_Const    *snamenode;
-       FuncCall   *funccallnode;
-       RawColumnDefault *rawEnt;
-
-       /*
-        * Create raw parse tree for the updated column default expression.
-        * This should match transformColumnDefinition() in parser/analyze.c.
-        */
-       qstring = quote_qualified_identifier(nspname, seqname);
-       snamenode = makeNode(A_Const);
-       snamenode->val.type = T_String;
-       snamenode->val.val.str = qstring;
-       funccallnode = makeNode(FuncCall);
-       funccallnode->funcname = SystemFuncName("nextval");
-       funccallnode->args = list_make1(snamenode);
-       funccallnode->agg_star = false;
-       funccallnode->agg_distinct = false;
-
-       /*
-        * Remove any old default for the column.  We use RESTRICT here for
-        * safety, but at present we do not expect anything to depend on the
-        * default.
-        */
-       RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false);
-
-       /* Do the equivalent of ALTER TABLE ... SET DEFAULT */
-       rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
-       rawEnt->attnum = attnum;
-       rawEnt->raw_default = (Node *) funccallnode;
-
-       /*
-        * This function is intended for CREATE TABLE, so it processes a
-        * _list_ of defaults, but we just do one.
-        */
-       AddRelationRawConstraints(rel, list_make1(rawEnt), NIL);
-}
-
 
 /*
  * This code supports
index 099bb7148316ea16768af77706912e9e8e640b18..be91872df556dc7ee80d4dd94bf22df96a403dd0 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.324 2005/08/01 20:31:09 tgl Exp $
+ *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.325 2005/10/02 23:50:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -912,12 +912,15 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                 * DEFAULT).
                 *
                 * Create an expression tree representing the function call
-                * nextval('"sequencename"')
+                * nextval('sequencename').  We cannot reduce the raw tree
+                * to cooked form until after the sequence is created, but
+                * there's no need to do so.
                 */
                qstring = quote_qualified_identifier(snamespace, sname);
                snamenode = makeNode(A_Const);
                snamenode->val.type = T_String;
                snamenode->val.val.str = qstring;
+               snamenode->typename = SystemTypeName("regclass");
                funccallnode = makeNode(FuncCall);
                funccallnode->funcname = SystemFuncName("nextval");
                funccallnode->args = list_make1(snamenode);
index 3f150010273358f8a60e7ec86e0deb2f73e7d110..3a52c8756d1a93e10b8a158bac239e7912ca0bac 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.94 2005/04/14 20:03:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.95 2005/10/02 23:50:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1089,6 +1089,23 @@ regtypesend(PG_FUNCTION_ARGS)
 }
 
 
+/*
+ * text_regclass: convert text to regclass
+ */
+Datum
+text_regclass(PG_FUNCTION_ARGS)
+{
+       text       *relname = PG_GETARG_TEXT_P(0);
+       Oid                     result;
+       RangeVar   *rv;
+
+       rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
+       result = RangeVarGetRelid(rv, false);
+
+       PG_RETURN_OID(result);
+}
+
+
 /*
  * Given a C string, parse it into a qualified-name list.
  */
index dde008c17364a676803cd8ede59ed1814b1a522d..33299a6dd32e64cd31c6c0843faa83d9111b6b1e 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.124 2005/08/14 19:20:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.125 2005/10/02 23:50:10 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "describe.h"
@@ -763,7 +763,8 @@ describeOneTableDetails(const char *schemaname,
        /* Get column info (index requires additional checks) */
        printfPQExpBuffer(&buf, "SELECT a.attname,");
        appendPQExpBuffer(&buf, "\n  pg_catalog.format_type(a.atttypid, a.atttypmod),"
-       "\n  (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d"
+                                         "\n  (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)"
+                                         "\n   FROM pg_catalog.pg_attrdef d"
                                          "\n   WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),"
                                          "\n  a.attnotnull, a.attnum");
        if (verbose)
index cd44e8c1559778049d668aea28194f2695c1a7c6..569945bd49fa0f438605c6eace3a3a9bfd1fd44b 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.302 2005/09/16 05:35:40 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.303 2005/10/02 23:50:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200509161
+#define CATALOG_VERSION_NO     200510011
 
 #endif
index 99410eeb77890675b439c33b2967325bbc3b5dbd..7f9e30a5b243dcae3d69175515014a3b0053c725 100644 (file)
@@ -10,7 +10,7 @@
  *
  * Copyright (c) 2002-2005, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.21 2005/04/14 01:38:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.22 2005/10/02 23:50:11 tgl Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -116,7 +116,9 @@ DATA(insert (       16      23  2558 e ));
  * from OID to int4 or int8.  Similarly for each OID-alias type.  Also allow
  * implicit coercions between OID and each OID-alias type, as well as
  * regproc<->regprocedure and regoper<->regoperator.  (Other coercions
- * between alias types must pass through OID.)
+ * between alias types must pass through OID.)  Lastly, there is an implicit
+ * cast from text to regclass, which exists mainly to support legacy forms
+ * of nextval() and related functions.
  */
 DATA(insert (  20       26 1287 i ));
 DATA(insert (  21       26  313 i ));
@@ -169,6 +171,7 @@ DATA(insert (       21 2206  313 i ));
 DATA(insert (  23 2206    0 i ));
 DATA(insert ( 2206      20 1288 a ));
 DATA(insert ( 2206      23    0 a ));
+DATA(insert (  25 2205 1079 i ));
 
 /*
  * String category: this needs to be tightened up
index 4b25833b17f536158eefb4b659baae1ef75a7edc..8c7f5b438cf6900da832b717a00e4324aa4b652b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.385 2005/09/16 05:35:40 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.386 2005/10/02 23:50:11 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -2073,14 +2073,14 @@ DATA(insert OID = 1572 (  notlike                       PGNSP PGUID 12 f f t f i 2 16 "19 25" _null_
 DESCR("does not match LIKE expression");
 
 
-/* SEQUENCEs nextval & currval functions */
-DATA(insert OID = 1574 (  nextval                      PGNSP PGUID 12 f f t f v 1 20 "25" _null_ _null_ _null_ nextval - _null_ ));
+/* SEQUENCE functions */
+DATA(insert OID = 1574 (  nextval                      PGNSP PGUID 12 f f t f v 1 20 "2205" _null_ _null_ _null_       nextval_oid - _null_ ));
 DESCR("sequence next value");
-DATA(insert OID = 1575 (  currval                      PGNSP PGUID 12 f f t f v 1 20 "25" _null_ _null_ _null_ currval - _null_ ));
+DATA(insert OID = 1575 (  currval                      PGNSP PGUID 12 f f t f v 1 20 "2205" _null_ _null_ _null_       currval_oid - _null_ ));
 DESCR("sequence current value");
-DATA(insert OID = 1576 (  setval                       PGNSP PGUID 12 f f t f v 2 20 "25 20" _null_ _null_ _null_  setval - _null_ ));
+DATA(insert OID = 1576 (  setval                       PGNSP PGUID 12 f f t f v 2 20 "2205 20" _null_ _null_ _null_  setval_oid - _null_ ));
 DESCR("set sequence value");
-DATA(insert OID = 1765 (  setval                       PGNSP PGUID 12 f f t f v 3 20 "25 20 16" _null_ _null_ _null_ setval_and_iscalled - _null_ ));
+DATA(insert OID = 1765 (  setval                       PGNSP PGUID 12 f f t f v 3 20 "2205 20 16" _null_ _null_ _null_ setval3_oid - _null_ ));
 DESCR("set sequence value and iscalled status");
 
 DATA(insert OID = 1579 (  varbit_in                    PGNSP PGUID 12 f f t f i 3 1562 "2275 26 23" _null_ _null_ _null_ varbit_in - _null_ ));
@@ -3190,6 +3190,8 @@ DATA(insert OID = 2220 (  regtypein                       PGNSP PGUID 12 f f t f s 1 2206 "2275" _nu
 DESCR("I/O");
 DATA(insert OID = 2221 (  regtypeout           PGNSP PGUID 12 f f t f s 1 2275 "2206" _null_ _null_ _null_     regtypeout - _null_ ));
 DESCR("I/O");
+DATA(insert OID = 1079 (  regclass                     PGNSP PGUID 12 f f t f s 1 2205 "25" _null_ _null_ _null_       text_regclass - _null_ ));
+DESCR("convert text to regclass");
 
 DATA(insert OID = 2246 ( fmgr_internal_validator PGNSP PGUID 12 f f t f s 1 2278 "26" _null_ _null_ _null_ fmgr_internal_validator - _null_ ));
 DESCR("(internal)");
index 38538236c7a9ebaa429bee47edcaeb806f85413b..13cbdc403ff5832746f626b54683f773f27d6e2b 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/sequence.h,v 1.32 2005/06/07 07:08:35 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/commands/sequence.h,v 1.33 2005/10/02 23:50:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -81,10 +81,11 @@ typedef struct xl_seq_rec
 } xl_seq_rec;
 
 extern Datum nextval(PG_FUNCTION_ARGS);
-extern Datum currval(PG_FUNCTION_ARGS);
+extern Datum nextval_oid(PG_FUNCTION_ARGS);
+extern Datum currval_oid(PG_FUNCTION_ARGS);
+extern Datum setval_oid(PG_FUNCTION_ARGS);
+extern Datum setval3_oid(PG_FUNCTION_ARGS);
 extern Datum lastval(PG_FUNCTION_ARGS);
-extern Datum setval(PG_FUNCTION_ARGS);
-extern Datum setval_and_iscalled(PG_FUNCTION_ARGS);
 
 extern void DefineSequence(CreateSeqStmt *stmt);
 extern void AlterSequence(AlterSeqStmt *stmt);
index ca31f3098930f8bb3b0efba9958c2fffde11a511..50855daf8d2f7fb7711f6758587c0edbc21f8a5d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.264 2005/09/16 05:35:41 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.265 2005/10/02 23:50:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -482,6 +482,7 @@ extern Datum regtypein(PG_FUNCTION_ARGS);
 extern Datum regtypeout(PG_FUNCTION_ARGS);
 extern Datum regtyperecv(PG_FUNCTION_ARGS);
 extern Datum regtypesend(PG_FUNCTION_ARGS);
+extern Datum text_regclass(PG_FUNCTION_ARGS);
 extern List *stringToQualifiedNameList(const char *string, const char *caller);
 extern char *format_procedure(Oid procedure_oid);
 extern char *format_operator(Oid operator_oid);
index e959b4a9b753882695e461e5e9084c28ea220aa7..d2766ee2a4e863a751c126d3651a06badf21aaed 100644 (file)
@@ -162,7 +162,7 @@ create domain ddef2 oid DEFAULT '12';
 -- Type mixing, function returns int8
 create domain ddef3 text DEFAULT 5;
 create sequence ddef4_seq;
-create domain ddef4 int4 DEFAULT nextval(cast('ddef4_seq' as text));
+create domain ddef4 int4 DEFAULT nextval('ddef4_seq');
 create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
 create table defaulttest
             ( col1 ddef1
@@ -189,7 +189,6 @@ select * from defaulttest;
     3 |   12 | 5    |    4 |   42 |   88 | 8000 | 12.12
 (4 rows)
 
-drop sequence ddef4_seq;
 drop table defaulttest cascade;
 -- Test ALTER DOMAIN .. NOT NULL
 create domain dnotnulltest integer;
@@ -300,6 +299,7 @@ drop domain ddef2 restrict;
 drop domain ddef3 restrict;
 drop domain ddef4 restrict;
 drop domain ddef5 restrict;
+drop sequence ddef4_seq;
 -- Make sure that constraints of newly-added domain columns are
 -- enforced correctly, even if there's no default value for the new
 -- column. Per bug #1433
index 756a716ecabbaca92711a1ada062fda41bf52dc8..978a6dcd63e94bf98a5a9031eee3c3815726e0db 100644 (file)
@@ -1335,10 +1335,10 @@ SELECT tablename, rulename, definition FROM pg_rules
  rtest_nothn1  | rtest_nothn_r2  | CREATE RULE rtest_nothn_r2 AS ON INSERT TO rtest_nothn1 WHERE ((new.a >= 30) AND (new.a < 40)) DO INSTEAD NOTHING;
  rtest_nothn2  | rtest_nothn_r3  | CREATE RULE rtest_nothn_r3 AS ON INSERT TO rtest_nothn2 WHERE (new.a >= 100) DO INSTEAD INSERT INTO rtest_nothn3 (a, b) VALUES (new.a, new.b);
  rtest_nothn2  | rtest_nothn_r4  | CREATE RULE rtest_nothn_r4 AS ON INSERT TO rtest_nothn2 DO INSTEAD NOTHING;
- rtest_order1  | rtest_order_r1  | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 1 - this should run 1st'::text);
- rtest_order1  | rtest_order_r2  | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 2 - this should run 2nd'::text);
- rtest_order1  | rtest_order_r3  | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 3 - this should run 3rd'::text);
- rtest_order1  | rtest_order_r4  | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 4 - this should run 4th'::text);
+ rtest_order1  | rtest_order_r1  | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::regclass), 'rule 1 - this should run 1st'::text);
+ rtest_order1  | rtest_order_r2  | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::regclass), 'rule 2 - this should run 2nd'::text);
+ rtest_order1  | rtest_order_r3  | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::regclass), 'rule 3 - this should run 3rd'::text);
+ rtest_order1  | rtest_order_r4  | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::regclass), 'rule 4 - this should run 4th'::text);
  rtest_person  | rtest_pers_del  | CREATE RULE rtest_pers_del AS ON DELETE TO rtest_person DO DELETE FROM rtest_admin WHERE (rtest_admin.pname = old.pname);
  rtest_person  | rtest_pers_upd  | CREATE RULE rtest_pers_upd AS ON UPDATE TO rtest_person DO UPDATE rtest_admin SET pname = new.pname WHERE (rtest_admin.pname = old.pname);
  rtest_system  | rtest_sys_del   | CREATE RULE rtest_sys_del AS ON DELETE TO rtest_system DO (DELETE FROM rtest_interface WHERE (rtest_interface.sysname = old.sysname); DELETE FROM rtest_admin WHERE (rtest_admin.sysname = old.sysname); );
index 6e919d1f1de08c1c9aab82d76301725411c6fde7..ca9ece284b080744eb5af3a39abd1500b89b6609 100644 (file)
@@ -19,18 +19,82 @@ SELECT * FROM serialTest;
  force | 100
 (3 rows)
 
+-- basic sequence operations using both text and oid references
 CREATE SEQUENCE sequence_test;
  
-BEGIN;
-SELECT nextval('sequence_test');
+SELECT nextval('sequence_test'::text);
  nextval 
 ---------
        1
 (1 row)
 
+SELECT nextval('sequence_test'::regclass);
+ nextval 
+---------
+       2
+(1 row)
+
+SELECT currval('sequence_test'::text);
+ currval 
+---------
+       2
+(1 row)
+
+SELECT currval('sequence_test'::regclass);
+ currval 
+---------
+       2
+(1 row)
+
+SELECT setval('sequence_test'::text, 32);
+ setval 
+--------
+     32
+(1 row)
+
+SELECT nextval('sequence_test'::regclass);
+ nextval 
+---------
+      33
+(1 row)
+
+SELECT setval('sequence_test'::text, 99, false);
+ setval 
+--------
+     99
+(1 row)
+
+SELECT nextval('sequence_test'::regclass);
+ nextval 
+---------
+      99
+(1 row)
+
+SELECT setval('sequence_test'::regclass, 32);
+ setval 
+--------
+     32
+(1 row)
+
+SELECT nextval('sequence_test'::text);
+ nextval 
+---------
+      33
+(1 row)
+
+SELECT setval('sequence_test'::regclass, 99, false);
+ setval 
+--------
+     99
+(1 row)
+
+SELECT nextval('sequence_test'::text);
+ nextval 
+---------
+      99
+(1 row)
+
 DROP SEQUENCE sequence_test;
-END;
 -- renaming sequences
 CREATE SEQUENCE foo_seq;
 ALTER TABLE foo_seq RENAME TO foo_seq_new;
@@ -41,6 +105,45 @@ SELECT * FROM foo_seq_new;
 (1 row)
 
 DROP SEQUENCE foo_seq_new;
+-- renaming serial sequences
+ALTER TABLE serialtest_f2_seq RENAME TO serialtest_f2_foo;
+INSERT INTO serialTest VALUES ('more');
+SELECT * FROM serialTest;
+  f1   | f2  
+-------+-----
+ foo   |   1
+ bar   |   2
+ force | 100
+ more  |   3
+(4 rows)
+
+--
+-- Check dependencies of serial and ordinary sequences
+--
+CREATE TEMP SEQUENCE myseq2;
+CREATE TEMP SEQUENCE myseq3;
+CREATE TEMP TABLE t1 (
+  f1 serial,
+  f2 int DEFAULT nextval('myseq2'),
+  f3 int DEFAULT nextval('myseq3'::text)
+);
+NOTICE:  CREATE TABLE will create implicit sequence "t1_f1_seq" for serial column "t1.f1"
+-- Both drops should fail, but with different error messages:
+DROP SEQUENCE t1_f1_seq;
+ERROR:  cannot drop sequence t1_f1_seq because table t1 column f1 requires it
+HINT:  You may drop table t1 column f1 instead.
+DROP SEQUENCE myseq2;
+NOTICE:  default for table t1 column f2 depends on sequence myseq2
+ERROR:  cannot drop sequence myseq2 because other objects depend on it
+HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+-- This however will work:
+DROP SEQUENCE myseq3;
+DROP TABLE t1;
+-- Fails because no longer existent:
+DROP SEQUENCE t1_f1_seq;
+ERROR:  sequence "t1_f1_seq" does not exist
+-- Now OK:
+DROP SEQUENCE myseq2;
 --
 -- Alter sequence
 --
index f92f55af2bd7dbc0691af257589f7cfafafa27aa..350f29152a2ffc08f4125276ee1f4c2afd1e52ea 100644 (file)
@@ -147,9 +147,8 @@ DROP TABLE INSERT_CHILD;
 --
 
 DELETE FROM INSERT_TBL;
-DROP SEQUENCE INSERT_SEQ;
 
-CREATE SEQUENCE INSERT_SEQ START 4;
+ALTER SEQUENCE INSERT_SEQ RESTART WITH 4;
 
 CREATE TABLE tmp (xd INT, yd TEXT, zd INT);
 
index 70ab60ac40013ffbaa28741807e64f85c76c1f05..5ba46c062fc77cdbb3c74cd70a8c29a3c5e73c44 100644 (file)
@@ -213,8 +213,7 @@ DROP TABLE INSERT_CHILD;
 -- Check constraints on INSERT INTO
 --
 DELETE FROM INSERT_TBL;
-DROP SEQUENCE INSERT_SEQ;
-CREATE SEQUENCE INSERT_SEQ START 4;
+ALTER SEQUENCE INSERT_SEQ RESTART WITH 4;
 CREATE TABLE tmp (xd INT, yd TEXT, zd INT);
 INSERT INTO tmp VALUES (null, 'Y', null);
 INSERT INTO tmp VALUES (5, '!check failed', null);
index 386adede1659943acd90f5edfebcc5070ab04329..c80b81262679125b49f37357c7a83bb99d232dd7 100644 (file)
@@ -131,7 +131,7 @@ create domain ddef2 oid DEFAULT '12';
 -- Type mixing, function returns int8
 create domain ddef3 text DEFAULT 5;
 create sequence ddef4_seq;
-create domain ddef4 int4 DEFAULT nextval(cast('ddef4_seq' as text));
+create domain ddef4 int4 DEFAULT nextval('ddef4_seq');
 create domain ddef5 numeric(8,2) NOT NULL DEFAULT '12.12';
 
 create table defaulttest
@@ -155,7 +155,6 @@ COPY defaulttest(col5) FROM stdin;
 
 select * from defaulttest;
 
-drop sequence ddef4_seq;
 drop table defaulttest cascade;
 
 -- Test ALTER DOMAIN .. NOT NULL
@@ -244,6 +243,7 @@ drop domain ddef2 restrict;
 drop domain ddef3 restrict;
 drop domain ddef4 restrict;
 drop domain ddef5 restrict;
+drop sequence ddef4_seq;
 
 -- Make sure that constraints of newly-added domain columns are
 -- enforced correctly, even if there's no default value for the new
index a8b73c02bf85587d552b7f0ac2359ed79906cfeb..806a71819269710d21152e2ce6f5faed70bc8676 100644 (file)
@@ -10,13 +10,24 @@ INSERT INTO serialTest VALUES ('force', 100);
 INSERT INTO serialTest VALUES ('wrong', NULL);
  
 SELECT * FROM serialTest;
+
+-- basic sequence operations using both text and oid references
 CREATE SEQUENCE sequence_test;
  
-BEGIN;
-SELECT nextval('sequence_test');
+SELECT nextval('sequence_test'::text);
+SELECT nextval('sequence_test'::regclass);
+SELECT currval('sequence_test'::text);
+SELECT currval('sequence_test'::regclass);
+SELECT setval('sequence_test'::text, 32);
+SELECT nextval('sequence_test'::regclass);
+SELECT setval('sequence_test'::text, 99, false);
+SELECT nextval('sequence_test'::regclass);
+SELECT setval('sequence_test'::regclass, 32);
+SELECT nextval('sequence_test'::text);
+SELECT setval('sequence_test'::regclass, 99, false);
+SELECT nextval('sequence_test'::text);
+
 DROP SEQUENCE sequence_test;
-END;
 
 -- renaming sequences
 CREATE SEQUENCE foo_seq;
@@ -24,6 +35,32 @@ ALTER TABLE foo_seq RENAME TO foo_seq_new;
 SELECT * FROM foo_seq_new;
 DROP SEQUENCE foo_seq_new;
 
+-- renaming serial sequences
+ALTER TABLE serialtest_f2_seq RENAME TO serialtest_f2_foo;
+INSERT INTO serialTest VALUES ('more');
+SELECT * FROM serialTest;
+
+--
+-- Check dependencies of serial and ordinary sequences
+--
+CREATE TEMP SEQUENCE myseq2;
+CREATE TEMP SEQUENCE myseq3;
+CREATE TEMP TABLE t1 (
+  f1 serial,
+  f2 int DEFAULT nextval('myseq2'),
+  f3 int DEFAULT nextval('myseq3'::text)
+);
+-- Both drops should fail, but with different error messages:
+DROP SEQUENCE t1_f1_seq;
+DROP SEQUENCE myseq2;
+-- This however will work:
+DROP SEQUENCE myseq3;
+DROP TABLE t1;
+-- Fails because no longer existent:
+DROP SEQUENCE t1_f1_seq;
+-- Now OK:
+DROP SEQUENCE myseq2;
+
 --
 -- Alter sequence
 --