Skip to content

Commit 737b025

Browse files
kelvicharssher
authored andcommitted
[PGPRO-4074] Sequence hooks for mm
(cherry picked from commit 259711d6d874cf13fceb566f07128f21b5a4e9dc) tags: multimaster (cherry picked from commit 5b18256fd471a9e40d11ed516531e1c5a3269939)
1 parent c9bcd7f commit 737b025

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

src/backend/commands/sequence.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ typedef struct SeqTableData
8686

8787
typedef SeqTableData *SeqTable;
8888

89+
seq_nextval_hook_t SeqNextvalHook;
90+
8991
static HTAB *seqhashtab = NULL; /* hash table for SeqTable items */
9092

9193
/*
@@ -628,6 +630,10 @@ nextval_internal(Oid relid, bool check_permissions)
628630
elm->last += elm->increment;
629631
relation_close(seqrel, NoLock);
630632
last_used_seq = elm;
633+
634+
if (SeqNextvalHook)
635+
SeqNextvalHook(relid, elm->last);
636+
631637
return elm->last;
632638
}
633639

@@ -823,6 +829,9 @@ nextval_internal(Oid relid, bool check_permissions)
823829

824830
relation_close(seqrel, NoLock);
825831

832+
if (SeqNextvalHook)
833+
SeqNextvalHook(relid, result);
834+
826835
return result;
827836
}
828837

@@ -892,6 +901,139 @@ lastval(PG_FUNCTION_ARGS)
892901
PG_RETURN_INT64(result);
893902
}
894903

904+
/*
905+
* Bump last value to next iff next > value.
906+
* Support routine for multimaster's monotonic sequences.
907+
*/
908+
void
909+
AdjustSequence(Oid relid, int64 next)
910+
{
911+
SeqTable elm;
912+
Relation seqrel;
913+
Buffer buf;
914+
HeapTupleData seqdatatuple;
915+
Form_pg_sequence_data seq;
916+
HeapTuple pgstuple;
917+
Form_pg_sequence pgsform;
918+
int64 maxv,
919+
minv,
920+
incby,
921+
cache;
922+
int64 last;
923+
924+
/* open and lock sequence */
925+
init_sequence(relid, &elm, &seqrel);
926+
927+
if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
928+
ereport(ERROR,
929+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
930+
errmsg("permission denied for sequence %s",
931+
RelationGetRelationName(seqrel))));
932+
933+
pgstuple = SearchSysCache1(SEQRELID, ObjectIdGetDatum(relid));
934+
if (!HeapTupleIsValid(pgstuple))
935+
elog(ERROR, "cache lookup failed for sequence %u", relid);
936+
pgsform = (Form_pg_sequence) GETSTRUCT(pgstuple);
937+
maxv = pgsform->seqmax;
938+
minv = pgsform->seqmin;
939+
incby = pgsform->seqincrement;
940+
cache = pgsform->seqcache;
941+
ReleaseSysCache(pgstuple);
942+
943+
/* cached number is greater than received */
944+
if (elm->last != cache && elm->last + incby > next)
945+
{
946+
relation_close(seqrel, NoLock);
947+
return;
948+
}
949+
950+
/* read-only transactions may only modify temp sequences */
951+
if (!seqrel->rd_islocaltemp)
952+
PreventCommandIfReadOnly("setval()");
953+
954+
/*
955+
* Forbid this during parallel operation because, to make it work, the
956+
* cooperating backends would need to share the backend-local cached
957+
* sequence information. Currently, we don't support that.
958+
*/
959+
PreventCommandIfParallelMode("setval()");
960+
961+
/* lock page' buffer and read tuple */
962+
seq = read_seq_tuple(seqrel, &buf, &seqdatatuple);
963+
964+
if ((next < minv) || (next > maxv))
965+
{
966+
char bufv[100],
967+
bufm[100],
968+
bufx[100];
969+
970+
snprintf(bufv, sizeof(bufv), INT64_FORMAT, next);
971+
snprintf(bufm, sizeof(bufm), INT64_FORMAT, minv);
972+
snprintf(bufx, sizeof(bufx), INT64_FORMAT, maxv);
973+
ereport(ERROR,
974+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
975+
errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)",
976+
bufv, RelationGetRelationName(seqrel),
977+
bufm, bufx)));
978+
}
979+
980+
last = seq->last_value;
981+
if (seq->is_called)
982+
{
983+
last += incby;
984+
}
985+
if (last <= next)
986+
{
987+
next = last + incby*((next - last + incby)/incby);
988+
989+
/* Set the currval() state only if iscalled = true */
990+
if (seq->is_called)
991+
{
992+
elm->last = next; /* last returned number */
993+
elm->last_valid = true;
994+
}
995+
996+
/* In any case, forget any future cached numbers */
997+
elm->cached = elm->last;
998+
999+
/* check the comment above nextval_internal()'s equivalent call. */
1000+
if (RelationNeedsWAL(seqrel))
1001+
GetTopTransactionId();
1002+
1003+
START_CRIT_SECTION();
1004+
1005+
seq->last_value = next; /* last fetched number */
1006+
seq->log_cnt = 0;
1007+
1008+
MarkBufferDirty(buf);
1009+
1010+
/* XLOG stuff */
1011+
if (RelationNeedsWAL(seqrel))
1012+
{
1013+
xl_seq_rec xlrec;
1014+
XLogRecPtr recptr;
1015+
Page page = BufferGetPage(buf);
1016+
1017+
XLogBeginInsert();
1018+
XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
1019+
1020+
xlrec.node = seqrel->rd_node;
1021+
XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
1022+
XLogRegisterData((char *) seqdatatuple.t_data, seqdatatuple.t_len);
1023+
1024+
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
1025+
1026+
PageSetLSN(page, recptr);
1027+
}
1028+
1029+
END_CRIT_SECTION();
1030+
}
1031+
1032+
UnlockReleaseBuffer(buf);
1033+
1034+
relation_close(seqrel, NoLock);
1035+
}
1036+
8951037
/*
8961038
* Main internal procedure that handles 2 & 3 arg forms of SETVAL.
8971039
*

src/include/commands/sequence.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,9 @@ extern void seq_desc(StringInfo buf, XLogReaderState *rptr);
6666
extern const char *seq_identify(uint8 info);
6767
extern void seq_mask(char *pagedata, BlockNumber blkno);
6868

69+
typedef void (*seq_nextval_hook_t)(Oid seq_relid, int64 next);
70+
extern seq_nextval_hook_t SeqNextvalHook;
71+
72+
extern void AdjustSequence(Oid relid, int64 next);
73+
6974
#endif /* SEQUENCE_H */

0 commit comments

Comments
 (0)