CREATE FUNCTION "recordchange" () RETURNS trigger AS
-'$libdir/pending.so', 'recordchange' LANGUAGE 'C';
+'$libdir/pending', 'recordchange' LANGUAGE 'C';
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;
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)
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
/****************************************************************************
* 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
{
-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);
/*****************************************************************************
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");
}
-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" \
"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();
}
<!--
-$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">
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
<!--
-$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
-->
<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>
<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>
</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></>
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:
</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
</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>
<!--
-$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:
</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
* 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 $
*
*-------------------------------------------------------------------------
*/
}
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;
*
* 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 $
*/
/*
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
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
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
void
AlterSequence(AlterSeqStmt *stmt)
{
+ Oid relid;
SeqTable elm;
Relation seqrel;
Buffer buf;
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()))
}
+/*
+ * 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;
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 */
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;
}
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;
}
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;
result = last_used_seq->last;
relation_close(seqrel, NoLock);
+
PG_RETURN_INT64(result);
}
* sequence.
*/
static void
-do_setval(RangeVar *sequence, int64 next, bool iscalled)
+do_setval(Oid relid, int64 next, bool iscalled)
{
SeqTable elm;
Relation seqrel;
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);
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 */
* 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);
}
* 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);
}
}
/*
- * 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.
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)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
*/
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);
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
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
+/*
+ * 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.
*/
*
* 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"
/* 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)
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200509161
+#define CATALOG_VERSION_NO 200510011
#endif
*
* 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
* 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 ));
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
* 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
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_ ));
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)");
* 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 $
*
*-------------------------------------------------------------------------
*/
} 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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
-- 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
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;
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
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); );
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;
(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
--
--
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);
-- 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);
-- 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
select * from defaulttest;
-drop sequence ddef4_seq;
drop table defaulttest cascade;
-- Test ALTER DOMAIN .. NOT NULL
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
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;
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
--