Refactor init_params() in sequence.c to not use FormData_pg_sequence_data

init_params() sets up "last_value" and "is_called" for a sequence
relation holdind its metadata, based on the sequence properties in
pg_sequences.  "log_cnt" is the third property that can be updated in
this routine for FormData_pg_sequence_data, tracking when WAL records
should be generated for a sequence after nextval() iterations.  This
routine is called when creating or altering a sequence.

This commit refactors init_params() to not depend anymore on
FormData_pg_sequence_data, removing traces of it in sequence.c, making
easier the manipulation of metadata related to sequences.  The knowledge
about "log_cnt" is replaced with a more general "reset_state" flag, to
let the caller know if the sequence state should be reset.  In the case
of in-core sequences, this relates to WAL logging.  We still need to
depend on FormData_pg_sequence.

Author: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Reviewed-by: Tomas Vondra <tomas@vondra.me>
Discussion: https://postgr.es/m/ZWlohtKAs0uVVpZ3@paquier.xyz
pull/239/head
Michael Paquier 4 weeks ago
parent 97ca67377a
commit ba3d93b2e8
  1. 81
      src/backend/commands/sequence.c

@ -106,7 +106,9 @@ static Form_pg_sequence_data read_seq_tuple(Relation rel,
static void init_params(ParseState *pstate, List *options, bool for_identity, static void init_params(ParseState *pstate, List *options, bool for_identity,
bool isInit, bool isInit,
Form_pg_sequence seqform, Form_pg_sequence seqform,
Form_pg_sequence_data seqdataform, int64 *last_value,
bool *reset_state,
bool *is_called,
bool *need_seq_rewrite, bool *need_seq_rewrite,
List **owned_by); List **owned_by);
static void do_setval(Oid relid, int64 next, bool iscalled); static void do_setval(Oid relid, int64 next, bool iscalled);
@ -121,7 +123,9 @@ ObjectAddress
DefineSequence(ParseState *pstate, CreateSeqStmt *seq) DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
{ {
FormData_pg_sequence seqform; FormData_pg_sequence seqform;
FormData_pg_sequence_data seqdataform; int64 last_value;
bool reset_state;
bool is_called;
bool need_seq_rewrite; bool need_seq_rewrite;
List *owned_by; List *owned_by;
CreateStmt *stmt = makeNode(CreateStmt); CreateStmt *stmt = makeNode(CreateStmt);
@ -164,7 +168,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
/* Check and set all option values */ /* Check and set all option values */
init_params(pstate, seq->options, seq->for_identity, true, init_params(pstate, seq->options, seq->for_identity, true,
&seqform, &seqdataform, &seqform, &last_value, &reset_state, &is_called,
&need_seq_rewrite, &owned_by); &need_seq_rewrite, &owned_by);
/* /*
@ -179,7 +183,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
{ {
case SEQ_COL_LASTVAL: case SEQ_COL_LASTVAL:
coldef = makeColumnDef("last_value", INT8OID, -1, InvalidOid); coldef = makeColumnDef("last_value", INT8OID, -1, InvalidOid);
value[i - 1] = Int64GetDatumFast(seqdataform.last_value); value[i - 1] = Int64GetDatumFast(last_value);
break; break;
case SEQ_COL_LOG: case SEQ_COL_LOG:
coldef = makeColumnDef("log_cnt", INT8OID, -1, InvalidOid); coldef = makeColumnDef("log_cnt", INT8OID, -1, InvalidOid);
@ -448,6 +452,9 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
ObjectAddress address; ObjectAddress address;
Relation rel; Relation rel;
HeapTuple seqtuple; HeapTuple seqtuple;
bool reset_state = false;
bool is_called;
int64 last_value;
HeapTuple newdatatuple; HeapTuple newdatatuple;
/* Open and lock sequence, and check for ownership along the way. */ /* Open and lock sequence, and check for ownership along the way. */
@ -481,12 +488,14 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
/* copy the existing sequence data tuple, so it can be modified locally */ /* copy the existing sequence data tuple, so it can be modified locally */
newdatatuple = heap_copytuple(&datatuple); newdatatuple = heap_copytuple(&datatuple);
newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple); newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple);
last_value = newdataform->last_value;
is_called = newdataform->is_called;
UnlockReleaseBuffer(buf); UnlockReleaseBuffer(buf);
/* Check and set new values */ /* Check and set new values */
init_params(pstate, stmt->options, stmt->for_identity, false, init_params(pstate, stmt->options, stmt->for_identity, false,
seqform, newdataform, seqform, &last_value, &reset_state, &is_called,
&need_seq_rewrite, &owned_by); &need_seq_rewrite, &owned_by);
/* If needed, rewrite the sequence relation itself */ /* If needed, rewrite the sequence relation itself */
@ -513,6 +522,10 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
/* /*
* Insert the modified tuple into the new storage file. * Insert the modified tuple into the new storage file.
*/ */
newdataform->last_value = last_value;
newdataform->is_called = is_called;
if (reset_state)
newdataform->log_cnt = 0;
fill_seq_with_data(seqrel, newdatatuple); fill_seq_with_data(seqrel, newdatatuple);
} }
@ -1236,17 +1249,19 @@ read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
/* /*
* init_params: process the options list of CREATE or ALTER SEQUENCE, and * init_params: process the options list of CREATE or ALTER SEQUENCE, and
* store the values into appropriate fields of seqform, for changes that go * store the values into appropriate fields of seqform, for changes that go
* into the pg_sequence catalog, and fields of seqdataform for changes to the * into the pg_sequence catalog, and fields for changes to the sequence
* sequence relation itself. Set *need_seq_rewrite to true if we changed any * relation itself (*is_called, *last_value and *reset_state). Set
* parameters that require rewriting the sequence's relation (interesting for * *need_seq_rewrite to true if we changed any parameters that require
* ALTER SEQUENCE). Also set *owned_by to any OWNED BY option, or to NIL if * rewriting the sequence's relation (interesting for ALTER SEQUENCE). Also
* there is none. * set *owned_by to any OWNED BY option, or to NIL if there is none. Set
* *reset_state to true if the internal state of the sequence needs to be
* reset, affecting future nextval() calls, for example with WAL logging.
* *
* If isInit is true, fill any unspecified options with default values; * If isInit is true, fill any unspecified options with default values;
* otherwise, do not change existing options that aren't explicitly overridden. * otherwise, do not change existing options that aren't explicitly overridden.
* *
* Note: we force a sequence rewrite whenever we change parameters that affect * Note: we force a sequence rewrite whenever we change parameters that affect
* generation of future sequence values, even if the seqdataform per se is not * generation of future sequence values, even if the metadata per se is not
* changed. This allows ALTER SEQUENCE to behave transactionally. Currently, * changed. This allows ALTER SEQUENCE to behave transactionally. Currently,
* the only option that doesn't cause that is OWNED BY. It's *necessary* for * the only option that doesn't cause that is OWNED BY. It's *necessary* for
* ALTER SEQUENCE OWNED BY to not rewrite the sequence, because that would * ALTER SEQUENCE OWNED BY to not rewrite the sequence, because that would
@ -1257,7 +1272,9 @@ static void
init_params(ParseState *pstate, List *options, bool for_identity, init_params(ParseState *pstate, List *options, bool for_identity,
bool isInit, bool isInit,
Form_pg_sequence seqform, Form_pg_sequence seqform,
Form_pg_sequence_data seqdataform, int64 *last_value,
bool *reset_state,
bool *is_called,
bool *need_seq_rewrite, bool *need_seq_rewrite,
List **owned_by) List **owned_by)
{ {
@ -1363,11 +1380,11 @@ init_params(ParseState *pstate, List *options, bool for_identity,
} }
/* /*
* We must reset log_cnt when isInit or when changing any parameters that * We must reset the state of the sequence when isInit or when changing
* would affect future nextval allocations. * any parameters that would affect future nextval allocations.
*/ */
if (isInit) if (isInit)
seqdataform->log_cnt = 0; *reset_state = true;
/* AS type */ /* AS type */
if (as_type != NULL) if (as_type != NULL)
@ -1416,7 +1433,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("INCREMENT must not be zero"))); errmsg("INCREMENT must not be zero")));
seqdataform->log_cnt = 0; *reset_state = true;
} }
else if (isInit) else if (isInit)
{ {
@ -1428,7 +1445,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
{ {
seqform->seqcycle = boolVal(is_cycled->arg); seqform->seqcycle = boolVal(is_cycled->arg);
Assert(BoolIsValid(seqform->seqcycle)); Assert(BoolIsValid(seqform->seqcycle));
seqdataform->log_cnt = 0; *reset_state = true;
} }
else if (isInit) else if (isInit)
{ {
@ -1439,7 +1456,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
if (max_value != NULL && max_value->arg) if (max_value != NULL && max_value->arg)
{ {
seqform->seqmax = defGetInt64(max_value); seqform->seqmax = defGetInt64(max_value);
seqdataform->log_cnt = 0; *reset_state = true;
} }
else if (isInit || max_value != NULL || reset_max_value) else if (isInit || max_value != NULL || reset_max_value)
{ {
@ -1455,7 +1472,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
} }
else else
seqform->seqmax = -1; /* descending seq */ seqform->seqmax = -1; /* descending seq */
seqdataform->log_cnt = 0; *reset_state = true;
} }
/* Validate maximum value. No need to check INT8 as seqmax is an int64 */ /* Validate maximum value. No need to check INT8 as seqmax is an int64 */
@ -1471,7 +1488,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
if (min_value != NULL && min_value->arg) if (min_value != NULL && min_value->arg)
{ {
seqform->seqmin = defGetInt64(min_value); seqform->seqmin = defGetInt64(min_value);
seqdataform->log_cnt = 0; *reset_state = true;
} }
else if (isInit || min_value != NULL || reset_min_value) else if (isInit || min_value != NULL || reset_min_value)
{ {
@ -1487,7 +1504,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
} }
else else
seqform->seqmin = 1; /* ascending seq */ seqform->seqmin = 1; /* ascending seq */
seqdataform->log_cnt = 0; *reset_state = true;
} }
/* Validate minimum value. No need to check INT8 as seqmin is an int64 */ /* Validate minimum value. No need to check INT8 as seqmin is an int64 */
@ -1538,30 +1555,30 @@ init_params(ParseState *pstate, List *options, bool for_identity,
if (restart_value != NULL) if (restart_value != NULL)
{ {
if (restart_value->arg != NULL) if (restart_value->arg != NULL)
seqdataform->last_value = defGetInt64(restart_value); *last_value = defGetInt64(restart_value);
else else
seqdataform->last_value = seqform->seqstart; *last_value = seqform->seqstart;
seqdataform->is_called = false; *is_called = false;
seqdataform->log_cnt = 0; *reset_state = true;
} }
else if (isInit) else if (isInit)
{ {
seqdataform->last_value = seqform->seqstart; *last_value = seqform->seqstart;
seqdataform->is_called = false; *is_called = false;
} }
/* crosscheck RESTART (or current value, if changing MIN/MAX) */ /* crosscheck RESTART (or current value, if changing MIN/MAX) */
if (seqdataform->last_value < seqform->seqmin) if (*last_value < seqform->seqmin)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("RESTART value (%" PRId64 ") cannot be less than MINVALUE (%" PRId64 ")", errmsg("RESTART value (%" PRId64 ") cannot be less than MINVALUE (%" PRId64 ")",
seqdataform->last_value, *last_value,
seqform->seqmin))); seqform->seqmin)));
if (seqdataform->last_value > seqform->seqmax) if (*last_value > seqform->seqmax)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("RESTART value (%" PRId64 ") cannot be greater than MAXVALUE (%" PRId64 ")", errmsg("RESTART value (%" PRId64 ") cannot be greater than MAXVALUE (%" PRId64 ")",
seqdataform->last_value, *last_value,
seqform->seqmax))); seqform->seqmax)));
/* CACHE */ /* CACHE */
@ -1573,7 +1590,7 @@ init_params(ParseState *pstate, List *options, bool for_identity,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("CACHE (%" PRId64 ") must be greater than zero", errmsg("CACHE (%" PRId64 ") must be greater than zero",
seqform->seqcache))); seqform->seqcache)));
seqdataform->log_cnt = 0; *reset_state = true;
} }
else if (isInit) else if (isInit)
{ {

Loading…
Cancel
Save