Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit aa731ed

Browse files
committed
Change nextval and other sequence functions to specify their sequence
argument as a 'regclass' value instead of a text string. The frontend conversion of text string to pg_class OID is now encapsulated as an implicitly-invocable coercion from text to regclass. This provides backwards compatibility to the old behavior when the sequence argument is explicitly typed as 'text'. When the argument is just an unadorned literal string, it will be taken as 'regclass', which means that the stored representation will be an OID. This solves longstanding problems with renaming sequences that are referenced in default expressions, as well as new-in-8.1 problems with renaming such sequences' schemas or moving them to another schema. All per recent discussion. Along the way, fix some rather serious problems in dbmirror's support for mirroring sequence operations (int4 vs int8 confusion for instance).
1 parent 1b61ee3 commit aa731ed

File tree

25 files changed

+512
-339
lines changed

25 files changed

+512
-339
lines changed

contrib/dbmirror/MirrorSetup.sql

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ BEGIN;
22

33

44
CREATE FUNCTION "recordchange" () RETURNS trigger AS
5-
'$libdir/pending.so', 'recordchange' LANGUAGE 'C';
5+
'$libdir/pending', 'recordchange' LANGUAGE 'C';
66

77

88

@@ -48,15 +48,15 @@ CASCADE ON DELETE CASCADE
4848

4949
UPDATE pg_proc SET proname='nextval_pg' WHERE proname='nextval';
5050

51-
CREATE FUNCTION pg_catalog.nextval(text) RETURNS int8 AS
52-
'$libdir/pending.so', 'nextval' LANGUAGE 'C' STRICT;
51+
CREATE FUNCTION pg_catalog.nextval(regclass) RETURNS int8 AS
52+
'$libdir/pending', 'nextval_mirror' LANGUAGE 'C' STRICT;
5353

5454

5555
UPDATE pg_proc set proname='setval_pg' WHERE proname='setval';
5656

57-
CREATE FUNCTION pg_catalog.setval("unknown",integer,boolean) RETURNS int8 AS
58-
'$libdir/pending.so', 'setval' LANGUAGE 'C' STRICT;
59-
CREATE FUNCTION pg_catalog.setval("unknown",integer) RETURNS int8 AS
60-
'$libdir/pending.so', 'setval' LANGUAGE 'C' STRICT;
57+
CREATE FUNCTION pg_catalog.setval(regclass, int8, boolean) RETURNS int8 AS
58+
'$libdir/pending', 'setval3_mirror' LANGUAGE 'C' STRICT;
59+
CREATE FUNCTION pg_catalog.setval(regclass, int8) RETURNS int8 AS
60+
'$libdir/pending', 'setval_mirror' LANGUAGE 'C' STRICT;
6161

6262
COMMIT;

contrib/dbmirror/README.dbmirror

+5-5
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ Pending tables.
5656

5757
Requirements:
5858
---------------------------------
59-
-PostgreSQL-7.4 (Older versions are no longer supported)
59+
-PostgreSQL-8.1 (Older versions are no longer supported)
6060
-Perl 5.6 or 5.8 (Other versions might work)
6161
-PgPerl (http://gborg.postgresql.org/project/pgperl/projdisplay.php)
6262

@@ -177,15 +177,15 @@ If you are starting with an empty master database then the slave should
177177
be empty as well. Otherwise use pg_dump to ensure that the slave database
178178
tables are initially identical to the master.
179179

180-
6) Add entries in the MirrorHost table.
180+
6) Add entries in the dbmirror_MirrorHost table.
181181

182-
Each slave database must have an entry in the MirrorHost table.
182+
Each slave database must have an entry in the dbmirror_MirrorHost table.
183183

184-
The name of the host in the MirrorHost table must exactly match the
184+
The name of the host in the dbmirror_MirrorHost table must exactly match the
185185
slaveHost variable for that slave in the configuration file.
186186

187187
For example
188-
INSERT INTO "MirrorHost" ("SlaveName") VALUES ('backup_system');
188+
INSERT INTO dbmirror_MirrorHost (SlaveName) VALUES ('backup_system');
189189

190190

191191
6) Start DBMirror.pl

contrib/dbmirror/pending.c

+85-158
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/****************************************************************************
22
* pending.c
3-
* $Id: pending.c,v 1.21 2005/03/29 00:16:48 tgl Exp $
4-
* $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.21 2005/03/29 00:16:48 tgl Exp $
3+
* $Id: pending.c,v 1.22 2005/10/02 23:50:05 tgl Exp $
4+
* $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.22 2005/10/02 23:50:05 tgl Exp $
55
*
66
* This file contains a trigger for Postgresql-7.x to record changes to tables
77
* to a pending table for mirroring.
@@ -30,12 +30,13 @@
3030
*
3131
*
3232
***************************************************************************/
33-
#include <postgres.h>
33+
#include "postgres.h"
3434

35-
#include <executor/spi.h>
36-
#include <commands/trigger.h>
37-
#include <utils/lsyscache.h>
38-
#include <utils/array.h>
35+
#include "executor/spi.h"
36+
#include "commands/sequence.h"
37+
#include "commands/trigger.h"
38+
#include "utils/lsyscache.h"
39+
#include "utils/array.h"
3940

4041
enum FieldUsage
4142
{
@@ -81,11 +82,11 @@ PG_FUNCTION_INFO_V1(recordchange);
8182

8283

8384

84-
extern Datum nextval(PG_FUNCTION_ARGS);
85-
extern Datum setval(PG_FUNCTION_ARGS);
85+
extern Datum setval_mirror(PG_FUNCTION_ARGS);
86+
extern Datum setval3_mirror(PG_FUNCTION_ARGS);
87+
extern Datum nextval_mirror(PG_FUNCTION_ARGS);
8688

87-
int saveSequenceUpdate(const text *sequenceName,
88-
int nextSequenceValue);
89+
static void saveSequenceUpdate(Oid relid, int64 nextValue, bool iscalled);
8990

9091

9192
/*****************************************************************************
@@ -310,11 +311,9 @@ storeKeyInfo(char *cpTableName, HeapTuple tTupleData,
310311
SPI_pfree(cpKeyData);
311312

312313
if (iRetCode != SPI_OK_INSERT)
313-
{
314-
ereport(ERROR, (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION)
315-
,errmsg("error inserting row in pendingDelete")));
316-
return -1;
317-
}
314+
ereport(ERROR,
315+
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
316+
errmsg("error inserting row in pendingDelete")));
318317

319318
debug_msg("insert successful");
320319

@@ -583,161 +582,75 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc, Oid tableOid,
583582
}
584583

585584

586-
PG_FUNCTION_INFO_V1(setval);
585+
/*
586+
* Support for mirroring sequence objects.
587+
*/
588+
589+
PG_FUNCTION_INFO_V1(setval_mirror);
587590

588591
Datum
589-
setval(PG_FUNCTION_ARGS)
592+
setval_mirror(PG_FUNCTION_ARGS)
590593
{
594+
Oid relid = PG_GETARG_OID(0);
595+
int64 next = PG_GETARG_INT64(1);
596+
int64 result;
591597

598+
result = DatumGetInt64(DirectFunctionCall2(setval_oid,
599+
ObjectIdGetDatum(relid),
600+
Int64GetDatum(next)));
592601

593-
text *sequenceName;
594-
595-
Oid setvalArgTypes[3] = {TEXTOID, INT4OID,BOOLOID};
596-
int nextValue;
597-
void *setvalPlan = NULL;
598-
Datum setvalData[3];
599-
const char *setvalQuery = "SELECT setval_pg($1,$2,$3)";
600-
int ret;
601-
char is_called;
602-
603-
sequenceName = PG_GETARG_TEXT_P(0);
604-
nextValue = PG_GETARG_INT32(1);
605-
is_called = PG_GETARG_BOOL(2);
606-
607-
setvalData[0] = PointerGetDatum(sequenceName);
608-
setvalData[1] = Int32GetDatum(nextValue);
609-
if(PG_NARGS() > 2)
610-
{
611-
setvalData[2] = BoolGetDatum(is_called);
612-
}
613-
else
614-
{
615-
setvalData[2]=1;
616-
}
617-
618-
if (SPI_connect() < 0)
619-
{
620-
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
621-
errmsg("dbmirror:setval could not connect to SPI")));
622-
return -1;
623-
}
624-
625-
setvalPlan = SPI_prepare(setvalQuery, 3, setvalArgTypes);
626-
if (setvalPlan == NULL)
627-
{
628-
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
629-
errmsg("dbmirror:setval could not prepare plan")));
630-
return -1;
631-
}
632-
633-
ret = SPI_execp(setvalPlan, setvalData, NULL, 1);
634-
635-
if (ret != SPI_OK_SELECT || SPI_processed != 1)
636-
return -1;
637-
638-
debug_msg2("dbmirror:setval: setval_pg returned ok:%d", nextValue);
639-
640-
ret = saveSequenceUpdate(sequenceName, nextValue);
641-
642-
SPI_pfree(setvalPlan);
643-
644-
SPI_finish();
645-
debug_msg("dbmirror:setval about to return");
646-
return Int64GetDatum(nextValue);
602+
saveSequenceUpdate(relid, result, true);
647603

604+
PG_RETURN_INT64(result);
648605
}
649606

650-
651-
652-
PG_FUNCTION_INFO_V1(nextval);
607+
PG_FUNCTION_INFO_V1(setval3_mirror);
653608

654609
Datum
655-
nextval(PG_FUNCTION_ARGS)
610+
setval3_mirror(PG_FUNCTION_ARGS)
656611
{
657-
text *sequenceName;
658-
659-
const char *nextvalQuery = "SELECT nextval_pg($1)";
660-
Oid nextvalArgTypes[1] = {TEXTOID};
661-
void *nextvalPlan = NULL;
662-
Datum nextvalData[1];
663-
664-
665-
int ret;
666-
HeapTuple resTuple;
667-
char isNull;
668-
int nextSequenceValue;
669-
670-
671-
672-
debug_msg("dbmirror:nextval Starting pending.so:nextval");
673-
674-
675-
sequenceName = PG_GETARG_TEXT_P(0);
676-
677-
if (SPI_connect() < 0)
678-
{
679-
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
680-
errmsg("dbmirror:nextval could not connect to SPI")));
681-
return -1;
682-
}
683-
684-
nextvalPlan = SPI_prepare(nextvalQuery, 1, nextvalArgTypes);
685-
686-
687-
debug_msg("prepared plan to call nextval_pg");
688-
689-
690-
if (nextvalPlan == NULL)
691-
{
692-
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
693-
errmsg("dbmirror:nextval error creating plan")));
694-
return -1;
695-
}
696-
nextvalData[0] = PointerGetDatum(sequenceName);
697-
698-
ret = SPI_execp(nextvalPlan, nextvalData, NULL, 1);
699-
700-
debug_msg("dbmirror:Executed call to nextval_pg");
701-
702-
703-
if (ret != SPI_OK_SELECT || SPI_processed != 1)
704-
return -1;
705-
706-
resTuple = SPI_tuptable->vals[0];
612+
Oid relid = PG_GETARG_OID(0);
613+
int64 next = PG_GETARG_INT64(1);
614+
bool iscalled = PG_GETARG_BOOL(2);
615+
int64 result;
707616

708-
debug_msg("dbmirror:nextval Set resTuple");
709-
710-
nextSequenceValue = *(unsigned int *) (DatumGetPointer(SPI_getbinval(resTuple,
711-
SPI_tuptable->tupdesc,
712-
1, &isNull)));
617+
result = DatumGetInt64(DirectFunctionCall3(setval3_oid,
618+
ObjectIdGetDatum(relid),
619+
Int64GetDatum(next),
620+
BoolGetDatum(iscalled)));
713621

622+
saveSequenceUpdate(relid, result, iscalled);
714623

624+
PG_RETURN_INT64(result);
625+
}
715626

716-
debug_msg2("dbmirror:nextval Set SPI_getbinval:%d", nextSequenceValue);
627+
PG_FUNCTION_INFO_V1(nextval_mirror);
717628

629+
Datum
630+
nextval_mirror(PG_FUNCTION_ARGS)
631+
{
632+
Oid relid = PG_GETARG_OID(0);
633+
int64 result;
718634

719-
saveSequenceUpdate(sequenceName, nextSequenceValue);
720-
SPI_pfree(resTuple);
721-
SPI_pfree(nextvalPlan);
635+
result = DatumGetInt64(DirectFunctionCall1(nextval_oid,
636+
ObjectIdGetDatum(relid)));
722637

723-
SPI_finish();
638+
saveSequenceUpdate(relid, result, true);
724639

725-
return Int64GetDatum(nextSequenceValue);
640+
PG_RETURN_INT64(result);
726641
}
727642

728643

729-
int
730-
saveSequenceUpdate(const text *sequenceName,
731-
int nextSequenceVal)
644+
static void
645+
saveSequenceUpdate(Oid relid, int64 nextValue, bool iscalled)
732646
{
733-
734-
Oid insertArgTypes[2] = {TEXTOID, INT4OID};
647+
Oid insertArgTypes[2] = {NAMEOID, INT4OID};
735648
Oid insertDataArgTypes[1] = {NAMEOID};
736-
void *insertPlan = NULL;
737-
void *insertDataPlan = NULL;
649+
void *insertPlan;
650+
void *insertDataPlan;
738651
Datum insertDatum[2];
739652
Datum insertDataDatum[1];
740-
char nextSequenceText[32];
653+
char nextSequenceText[64];
741654

742655
const char *insertQuery =
743656
"INSERT INTO dbmirror_Pending (TableName,Op,XID) VALUES" \
@@ -746,36 +659,50 @@ saveSequenceUpdate(const text *sequenceName,
746659
"INSERT INTO dbmirror_PendingData(SeqId,IsKey,Data) VALUES " \
747660
"(currval('dbmirror_pending_seqid_seq'),'t',$1)";
748661

749-
int ret;
750-
662+
if (SPI_connect() < 0)
663+
ereport(ERROR,
664+
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
665+
errmsg("dbmirror:savesequenceupdate could not connect to SPI")));
751666

752667
insertPlan = SPI_prepare(insertQuery, 2, insertArgTypes);
753668
insertDataPlan = SPI_prepare(insertDataQuery, 1, insertDataArgTypes);
754669

755-
debug_msg("Prepared insert query");
756-
757-
758670
if (insertPlan == NULL || insertDataPlan == NULL)
759-
ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), errmsg("dbmirror:nextval error creating plan")));
671+
ereport(ERROR,
672+
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
673+
errmsg("dbmirror:savesequenceupdate error creating plan")));
760674

675+
insertDatum[0] = PointerGetDatum(get_rel_name(relid));
761676
insertDatum[1] = Int32GetDatum(GetCurrentTransactionId());
762-
insertDatum[0] = PointerGetDatum(sequenceName);
763677

764-
sprintf(nextSequenceText, "%d", nextSequenceVal);
678+
snprintf(nextSequenceText, sizeof(nextSequenceText),
679+
INT64_FORMAT ",'%c'",
680+
nextValue, iscalled ? 't' : 'f');
681+
682+
/*
683+
* note type cheat here: we prepare a C string and then claim it is a
684+
* NAME, which the system will coerce to varchar for us.
685+
*/
765686
insertDataDatum[0] = PointerGetDatum(nextSequenceText);
766-
debug_msg2("dbmirror:savesequenceupdate: Setting value %s",
687+
688+
debug_msg2("dbmirror:savesequenceupdate: Setting value as %s",
767689
nextSequenceText);
768690

769691
debug_msg("dbmirror:About to execute insert query");
770692

771-
ret = SPI_execp(insertPlan, insertDatum, NULL, 1);
693+
if (SPI_execp(insertPlan, insertDatum, NULL, 1) != SPI_OK_INSERT)
694+
ereport(ERROR,
695+
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
696+
errmsg("error inserting row in dbmirror_Pending")));
772697

773-
ret = SPI_execp(insertDataPlan, insertDataDatum, NULL, 1);
698+
if (SPI_execp(insertDataPlan, insertDataDatum, NULL, 1) != SPI_OK_INSERT)
699+
ereport(ERROR,
700+
(errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
701+
errmsg("error inserting row in dbmirror_PendingData")));
774702

775703
debug_msg("dbmirror:Insert query finished");
776704
SPI_pfree(insertPlan);
777705
SPI_pfree(insertDataPlan);
778706

779-
return ret;
780-
707+
SPI_finish();
781708
}

0 commit comments

Comments
 (0)