@@ -86,6 +86,8 @@ typedef struct SeqTableData
86
86
87
87
typedef SeqTableData * SeqTable ;
88
88
89
+ seq_nextval_hook_t SeqNextvalHook ;
90
+
89
91
static HTAB * seqhashtab = NULL ;/* hash table for SeqTable items */
90
92
91
93
/*
@@ -628,6 +630,10 @@ nextval_internal(Oid relid, bool check_permissions)
628
630
elm -> last += elm -> increment ;
629
631
relation_close (seqrel ,NoLock );
630
632
last_used_seq = elm ;
633
+
634
+ if (SeqNextvalHook )
635
+ SeqNextvalHook (relid ,elm -> last );
636
+
631
637
return elm -> last ;
632
638
}
633
639
@@ -823,6 +829,9 @@ nextval_internal(Oid relid, bool check_permissions)
823
829
824
830
relation_close (seqrel ,NoLock );
825
831
832
+ if (SeqNextvalHook )
833
+ SeqNextvalHook (relid ,result );
834
+
826
835
return result ;
827
836
}
828
837
@@ -892,6 +901,139 @@ lastval(PG_FUNCTION_ARGS)
892
901
PG_RETURN_INT64 (result );
893
902
}
894
903
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
+
895
1037
/*
896
1038
* Main internal procedure that handles 2 & 3 arg forms of SETVAL.
897
1039
*