mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	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
This commit is contained in:
		| @@ -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, | ||||
| 						bool isInit, | ||||
| 						Form_pg_sequence seqform, | ||||
| 						Form_pg_sequence_data seqdataform, | ||||
| 						int64 *last_value, | ||||
| 						bool *reset_state, | ||||
| 						bool *is_called, | ||||
| 						bool *need_seq_rewrite, | ||||
| 						List **owned_by); | ||||
| static void do_setval(Oid relid, int64 next, bool iscalled); | ||||
| @@ -121,7 +123,9 @@ ObjectAddress | ||||
| DefineSequence(ParseState *pstate, CreateSeqStmt *seq) | ||||
| { | ||||
| 	FormData_pg_sequence seqform; | ||||
| 	FormData_pg_sequence_data seqdataform; | ||||
| 	int64		last_value; | ||||
| 	bool		reset_state; | ||||
| 	bool		is_called; | ||||
| 	bool		need_seq_rewrite; | ||||
| 	List	   *owned_by; | ||||
| 	CreateStmt *stmt = makeNode(CreateStmt); | ||||
| @@ -164,7 +168,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq) | ||||
|  | ||||
| 	/* Check and set all option values */ | ||||
| 	init_params(pstate, seq->options, seq->for_identity, true, | ||||
| 				&seqform, &seqdataform, | ||||
| 				&seqform, &last_value, &reset_state, &is_called, | ||||
| 				&need_seq_rewrite, &owned_by); | ||||
|  | ||||
| 	/* | ||||
| @@ -179,7 +183,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq) | ||||
| 		{ | ||||
| 			case SEQ_COL_LASTVAL: | ||||
| 				coldef = makeColumnDef("last_value", INT8OID, -1, InvalidOid); | ||||
| 				value[i - 1] = Int64GetDatumFast(seqdataform.last_value); | ||||
| 				value[i - 1] = Int64GetDatumFast(last_value); | ||||
| 				break; | ||||
| 			case SEQ_COL_LOG: | ||||
| 				coldef = makeColumnDef("log_cnt", INT8OID, -1, InvalidOid); | ||||
| @@ -448,6 +452,9 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) | ||||
| 	ObjectAddress address; | ||||
| 	Relation	rel; | ||||
| 	HeapTuple	seqtuple; | ||||
| 	bool		reset_state = false; | ||||
| 	bool		is_called; | ||||
| 	int64		last_value; | ||||
| 	HeapTuple	newdatatuple; | ||||
|  | ||||
| 	/* 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 */ | ||||
| 	newdatatuple = heap_copytuple(&datatuple); | ||||
| 	newdataform = (Form_pg_sequence_data) GETSTRUCT(newdatatuple); | ||||
| 	last_value = newdataform->last_value; | ||||
| 	is_called = newdataform->is_called; | ||||
|  | ||||
| 	UnlockReleaseBuffer(buf); | ||||
|  | ||||
| 	/* Check and set new values */ | ||||
| 	init_params(pstate, stmt->options, stmt->for_identity, false, | ||||
| 				seqform, newdataform, | ||||
| 				seqform, &last_value, &reset_state, &is_called, | ||||
| 				&need_seq_rewrite, &owned_by); | ||||
|  | ||||
| 	/* 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. | ||||
| 		 */ | ||||
| 		newdataform->last_value = last_value; | ||||
| 		newdataform->is_called = is_called; | ||||
| 		if (reset_state) | ||||
| 			newdataform->log_cnt = 0; | ||||
| 		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 | ||||
|  * 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 | ||||
|  * sequence relation itself.  Set *need_seq_rewrite to true if we changed any | ||||
|  * parameters that require rewriting the sequence's relation (interesting for | ||||
|  * ALTER SEQUENCE).  Also set *owned_by to any OWNED BY option, or to NIL if | ||||
|  * there is none. | ||||
|  * into the pg_sequence catalog, and fields for changes to the sequence | ||||
|  * relation itself (*is_called, *last_value and *reset_state).  Set | ||||
|  * *need_seq_rewrite to true if we changed any parameters that require | ||||
|  * rewriting the sequence's relation (interesting for ALTER SEQUENCE).  Also | ||||
|  * 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; | ||||
|  * otherwise, do not change existing options that aren't explicitly overridden. | ||||
|  * | ||||
|  * 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, | ||||
|  * 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 | ||||
| @@ -1257,7 +1272,9 @@ static void | ||||
| init_params(ParseState *pstate, List *options, bool for_identity, | ||||
| 			bool isInit, | ||||
| 			Form_pg_sequence seqform, | ||||
| 			Form_pg_sequence_data seqdataform, | ||||
| 			int64 *last_value, | ||||
| 			bool *reset_state, | ||||
| 			bool *is_called, | ||||
| 			bool *need_seq_rewrite, | ||||
| 			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 | ||||
| 	 * would affect future nextval allocations. | ||||
| 	 * We must reset the state of the sequence when isInit or when changing | ||||
| 	 * any parameters that would affect future nextval allocations. | ||||
| 	 */ | ||||
| 	if (isInit) | ||||
| 		seqdataform->log_cnt = 0; | ||||
| 		*reset_state = true; | ||||
|  | ||||
| 	/* AS type */ | ||||
| 	if (as_type != NULL) | ||||
| @@ -1416,7 +1433,7 @@ init_params(ParseState *pstate, List *options, bool for_identity, | ||||
| 			ereport(ERROR, | ||||
| 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||||
| 					 errmsg("INCREMENT must not be zero"))); | ||||
| 		seqdataform->log_cnt = 0; | ||||
| 		*reset_state = true; | ||||
| 	} | ||||
| 	else if (isInit) | ||||
| 	{ | ||||
| @@ -1428,7 +1445,7 @@ init_params(ParseState *pstate, List *options, bool for_identity, | ||||
| 	{ | ||||
| 		seqform->seqcycle = boolVal(is_cycled->arg); | ||||
| 		Assert(BoolIsValid(seqform->seqcycle)); | ||||
| 		seqdataform->log_cnt = 0; | ||||
| 		*reset_state = true; | ||||
| 	} | ||||
| 	else if (isInit) | ||||
| 	{ | ||||
| @@ -1439,7 +1456,7 @@ init_params(ParseState *pstate, List *options, bool for_identity, | ||||
| 	if (max_value != NULL && max_value->arg) | ||||
| 	{ | ||||
| 		seqform->seqmax = defGetInt64(max_value); | ||||
| 		seqdataform->log_cnt = 0; | ||||
| 		*reset_state = true; | ||||
| 	} | ||||
| 	else if (isInit || max_value != NULL || reset_max_value) | ||||
| 	{ | ||||
| @@ -1455,7 +1472,7 @@ init_params(ParseState *pstate, List *options, bool for_identity, | ||||
| 		} | ||||
| 		else | ||||
| 			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 */ | ||||
| @@ -1471,7 +1488,7 @@ init_params(ParseState *pstate, List *options, bool for_identity, | ||||
| 	if (min_value != NULL && min_value->arg) | ||||
| 	{ | ||||
| 		seqform->seqmin = defGetInt64(min_value); | ||||
| 		seqdataform->log_cnt = 0; | ||||
| 		*reset_state = true; | ||||
| 	} | ||||
| 	else if (isInit || min_value != NULL || reset_min_value) | ||||
| 	{ | ||||
| @@ -1487,7 +1504,7 @@ init_params(ParseState *pstate, List *options, bool for_identity, | ||||
| 		} | ||||
| 		else | ||||
| 			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 */ | ||||
| @@ -1538,30 +1555,30 @@ init_params(ParseState *pstate, List *options, bool for_identity, | ||||
| 	if (restart_value != NULL) | ||||
| 	{ | ||||
| 		if (restart_value->arg != NULL) | ||||
| 			seqdataform->last_value = defGetInt64(restart_value); | ||||
| 			*last_value = defGetInt64(restart_value); | ||||
| 		else | ||||
| 			seqdataform->last_value = seqform->seqstart; | ||||
| 		seqdataform->is_called = false; | ||||
| 		seqdataform->log_cnt = 0; | ||||
| 			*last_value = seqform->seqstart; | ||||
| 		*is_called = false; | ||||
| 		*reset_state = true; | ||||
| 	} | ||||
| 	else if (isInit) | ||||
| 	{ | ||||
| 		seqdataform->last_value = seqform->seqstart; | ||||
| 		seqdataform->is_called = false; | ||||
| 		*last_value = seqform->seqstart; | ||||
| 		*is_called = false; | ||||
| 	} | ||||
|  | ||||
| 	/* crosscheck RESTART (or current value, if changing MIN/MAX) */ | ||||
| 	if (seqdataform->last_value < seqform->seqmin) | ||||
| 	if (*last_value < seqform->seqmin) | ||||
| 		ereport(ERROR, | ||||
| 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||||
| 				 errmsg("RESTART value (%" PRId64 ") cannot be less than MINVALUE (%" PRId64 ")", | ||||
| 						seqdataform->last_value, | ||||
| 						*last_value, | ||||
| 						seqform->seqmin))); | ||||
| 	if (seqdataform->last_value > seqform->seqmax) | ||||
| 	if (*last_value > seqform->seqmax) | ||||
| 		ereport(ERROR, | ||||
| 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||||
| 				 errmsg("RESTART value (%" PRId64 ") cannot be greater than MAXVALUE (%" PRId64 ")", | ||||
| 						seqdataform->last_value, | ||||
| 						*last_value, | ||||
| 						seqform->seqmax))); | ||||
|  | ||||
| 	/* CACHE */ | ||||
| @@ -1573,7 +1590,7 @@ init_params(ParseState *pstate, List *options, bool for_identity, | ||||
| 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||||
| 					 errmsg("CACHE (%" PRId64 ") must be greater than zero", | ||||
| 							seqform->seqcache))); | ||||
| 		seqdataform->log_cnt = 0; | ||||
| 		*reset_state = true; | ||||
| 	} | ||||
| 	else if (isInit) | ||||
| 	{ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user