diff --git a/contrib/dbmirror/MirrorSetup.sql b/contrib/dbmirror/MirrorSetup.sql index 19ac1b280fc23406027942a962ffffde208ea636..18c5b0693e3258d8b0519ecd99ee237d5dad1f15 100644 --- a/contrib/dbmirror/MirrorSetup.sql +++ b/contrib/dbmirror/MirrorSetup.sql @@ -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; diff --git a/contrib/dbmirror/README.dbmirror b/contrib/dbmirror/README.dbmirror index 8dfdf7a84b02722f21c4fa985007d0c61a5b60d4..1c4c9a09140bc750b7145cce55b3a8115eb2fa06 100644 --- a/contrib/dbmirror/README.dbmirror +++ b/contrib/dbmirror/README.dbmirror @@ -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 diff --git a/contrib/dbmirror/pending.c b/contrib/dbmirror/pending.c index 3ed9d2128cfdb4ab6e051e094bc0fe4f6761c15a..36f5837bbd8bc1bad77d7a6e9e4d17af2d94274c 100644 --- a/contrib/dbmirror/pending.c +++ b/contrib/dbmirror/pending.c @@ -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. @@ -30,12 +30,13 @@ * * ***************************************************************************/ -#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(); } diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 099f5e8ab671b2c44505c1eabea6da2844293b29..48caaa2994ffcb26a6e24b340ff6e909f57772c8 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -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 diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index c6c9d87e8a5024b3cbcfffa9f02daa7404e3f208..a641db7ee7481c785bc329c25d2e162b56b30ece 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -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> diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml index 092179f01bced875a03a4c9df3fe530da4143280..37d67a94797f1eb667c39a67f5d3df1b11e53428 100644 --- a/doc/src/sgml/release.sgml +++ b/doc/src/sgml/release.sgml @@ -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 diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 227b21c6564b15ca8d979ac20494da79a27dbe47..8060055ff72869abc17b175e30bf9984c1025607 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -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; diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index b56117a806f22003650992c8a86506b20e9a300f..4671f81f9148ac7a9cf0b7d164416c558bac068b 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -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 diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 5af9ba55b6e128c4deec48c418f1d4c563470e0e..9bf801f2308657c8fa04efb6ac000c7257cfa736 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -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) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index b3d0e017f15fc6c1e1537d5ef0ce2858aa321971..b2877cebb760adc18c8b5353d3dd84426ca44831 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -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 diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 099bb7148316ea16768af77706912e9e8e640b18..be91872df556dc7ee80d4dd94bf22df96a403dd0 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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); diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 3f150010273358f8a60e7ec86e0deb2f73e7d110..3a52c8756d1a93e10b8a158bac239e7912ca0bac 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -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. */ diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index dde008c17364a676803cd8ede59ed1814b1a522d..33299a6dd32e64cd31c6c0843faa83d9111b6b1e 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -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) diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index cd44e8c1559778049d668aea28194f2695c1a7c6..569945bd49fa0f438605c6eace3a3a9bfd1fd44b 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h index 99410eeb77890675b439c33b2967325bbc3b5dbd..7f9e30a5b243dcae3d69175515014a3b0053c725 100644 --- a/src/include/catalog/pg_cast.h +++ b/src/include/catalog/pg_cast.h @@ -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 diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 4b25833b17f536158eefb4b659baae1ef75a7edc..8c7f5b438cf6900da832b717a00e4324aa4b652b 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -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)"); diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 38538236c7a9ebaa429bee47edcaeb806f85413b..13cbdc403ff5832746f626b54683f773f27d6e2b 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -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); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index ca31f3098930f8bb3b0efba9958c2fffde11a511..50855daf8d2f7fb7711f6758587c0edbc21f8a5d 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -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); diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out index e959b4a9b753882695e461e5e9084c28ea220aa7..d2766ee2a4e863a751c126d3651a06badf21aaed 100644 --- a/src/test/regress/expected/domain.out +++ b/src/test/regress/expected/domain.out @@ -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 diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 756a716ecabbaca92711a1ada062fda41bf52dc8..978a6dcd63e94bf98a5a9031eee3c3815726e0db 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -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); ); diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out index 6e919d1f1de08c1c9aab82d76301725411c6fde7..ca9ece284b080744eb5af3a39abd1500b89b6609 100644 --- a/src/test/regress/expected/sequence.out +++ b/src/test/regress/expected/sequence.out @@ -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 -- diff --git a/src/test/regress/input/constraints.source b/src/test/regress/input/constraints.source index f92f55af2bd7dbc0691af257589f7cfafafa27aa..350f29152a2ffc08f4125276ee1f4c2afd1e52ea 100644 --- a/src/test/regress/input/constraints.source +++ b/src/test/regress/input/constraints.source @@ -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); diff --git a/src/test/regress/output/constraints.source b/src/test/regress/output/constraints.source index 70ab60ac40013ffbaa28741807e64f85c76c1f05..5ba46c062fc77cdbb3c74cd70a8c29a3c5e73c44 100644 --- a/src/test/regress/output/constraints.source +++ b/src/test/regress/output/constraints.source @@ -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); diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql index 386adede1659943acd90f5edfebcc5070ab04329..c80b81262679125b49f37357c7a83bb99d232dd7 100644 --- a/src/test/regress/sql/domain.sql +++ b/src/test/regress/sql/domain.sql @@ -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 diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql index a8b73c02bf85587d552b7f0ac2359ed79906cfeb..806a71819269710d21152e2ce6f5faed70bc8676 100644 --- a/src/test/regress/sql/sequence.sql +++ b/src/test/regress/sql/sequence.sql @@ -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 --