@@ -86,6 +86,8 @@ typedef struct SeqTableData
8686
8787typedef SeqTableData * SeqTable ;
8888
89+ seq_nextval_hook_t SeqNextvalHook ;
90+
8991static HTAB * seqhashtab = NULL ;/* hash table for SeqTable items */
9092
9193/*
@@ -628,6 +630,10 @@ nextval_internal(Oid relid, bool check_permissions)
628630elm -> last += elm -> increment ;
629631relation_close (seqrel ,NoLock );
630632last_used_seq = elm ;
633+
634+ if (SeqNextvalHook )
635+ SeqNextvalHook (relid ,elm -> last );
636+
631637return elm -> last ;
632638}
633639
@@ -823,6 +829,9 @@ nextval_internal(Oid relid, bool check_permissions)
823829
824830relation_close (seqrel ,NoLock );
825831
832+ if (SeqNextvalHook )
833+ SeqNextvalHook (relid ,result );
834+
826835return result ;
827836}
828837
@@ -892,6 +901,139 @@ lastval(PG_FUNCTION_ARGS)
892901PG_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 *