Thread

  1. [PATCH v20220922 02/13] FIXUP 0001-catalog-support-for-session-variables

    Julien Rouhaud <julien.rouhaud@free.fr> — 2022-09-13T08:06:59Z

    ---
     src/backend/catalog/dependency.c        |   2 +-
     src/backend/catalog/pg_variable.c       | 250 +++++++++++++++++-------
     src/backend/commands/session_variable.c | 120 ++----------
     src/backend/tcop/utility.c              |   2 +-
     src/include/catalog/pg_variable.h       |  20 +-
     src/include/commands/session_variable.h |   4 +-
     6 files changed, 207 insertions(+), 191 deletions(-)
    
    diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
    index 6255c2c72f..d8d512973d 100644
    --- a/src/backend/catalog/dependency.c
    +++ b/src/backend/catalog/dependency.c
    @@ -1513,7 +1513,7 @@ doDeletion(const ObjectAddress *object, int flags)
     			break;
     
     		case OCLASS_VARIABLE:
    -			RemoveSessionVariable(object->objectId);
    +			DropVariable(object->objectId);
     			break;
     
     			/*
    diff --git a/src/backend/catalog/pg_variable.c b/src/backend/catalog/pg_variable.c
    index a844e5c217..f4a06c47a3 100644
    --- a/src/backend/catalog/pg_variable.c
    +++ b/src/backend/catalog/pg_variable.c
    @@ -16,7 +16,6 @@
     
     #include "access/heapam.h"
     #include "access/htup_details.h"
    -
     #include "catalog/catalog.h"
     #include "catalog/dependency.h"
     #include "catalog/indexing.h"
    @@ -26,82 +25,47 @@
     #include "catalog/pg_namespace.h"
     #include "catalog/pg_type.h"
     #include "catalog/pg_variable.h"
    +#include "commands/session_variable.h"
    +#include "miscadmin.h"
    +#include "parser/parse_coerce.h"
    +#include "parser/parse_collate.h"
    +#include "parser/parse_expr.h"
    +#include "parser/parse_type.h"
     #include "storage/lmgr.h"
     #include "utils/builtins.h"
     #include "utils/lsyscache.h"
     #include "utils/pg_lsn.h"
     #include "utils/syscache.h"
     
    -/*
    - * Fetch attributes (without acl) of session variable from the syscache.
    - * We don't work with acl directly, so we don't need to read it here.
    - * Skip deserialization of defexpr when fast_only is true.
    - */
    -void
    -initVariable(Variable *var, Oid varid, bool fast_only)
    -{
    -	HeapTuple	tup;
    -	Form_pg_variable varform;
    -	Datum		defexpr_datum;
    -	bool		defexpr_isnull;
    -
    -	tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varid));
     
    -	if (!HeapTupleIsValid(tup))
    -		elog(ERROR, "cache lookup failed for session variable %u", varid);
    +static ObjectAddress create_variable(const char *varName,
    +									 Oid varNamespace,
    +									 Oid varType,
    +									 int32 varTypmod,
    +									 Oid varOwner,
    +									 Oid varCollation,
    +									 Node *varDefexpr,
    +									 VariableEOXAction eoxaction,
    +									 bool is_not_null,
    +									 bool if_not_exists,
    +									 bool is_immutable);
     
    -	varform = (Form_pg_variable) GETSTRUCT(tup);
    -
    -	var->oid = varid;
    -	var->create_lsn = varform->create_lsn;
    -	var->name = pstrdup(NameStr(varform->varname));
    -	var->namespaceid = varform->varnamespace;
    -	var->typid = varform->vartype;
    -	var->typmod = varform->vartypmod;
    -	var->owner = varform->varowner;
    -	var->collation = varform->varcollation;
    -	var->is_immutable = varform->varisimmutable;
    -	var->is_not_null = varform->varisnotnull;
    -	var->eoxaction = varform->vareoxaction;
    -
    -	/* Get defexpr */
    -	defexpr_datum = SysCacheGetAttr(VARIABLEOID,
    -									tup,
    -									Anum_pg_variable_vardefexpr,
    -									&defexpr_isnull);
    -
    -	var->has_defexpr = !defexpr_isnull;
    -
    -	/*
    -	 * Deserialize defexpr only when it is requested. We need to deserialize
    -	 * Node with default expression, only when we read from session variable,
    -	 * and this session variable has not assigned value, and this session
    -	 * variable has default expression. For other cases, we skip skip this
    -	 * operation.
    -	 */
    -	if (!fast_only && !defexpr_isnull)
    -		var->defexpr = stringToNode(TextDatumGetCString(defexpr_datum));
    -	else
    -		var->defexpr = NULL;
    -
    -	ReleaseSysCache(tup);
    -}
     
     /*
    - * Create entry in pg_variable table
    + * Creates entry in pg_variable table
      */
    -ObjectAddress
    -VariableCreate(const char *varName,
    -			   Oid varNamespace,
    -			   Oid varType,
    -			   int32 varTypmod,
    -			   Oid varOwner,
    -			   Oid varCollation,
    -			   Node *varDefexpr,
    -			   VariableEOXAction eoxaction,
    -			   bool is_not_null,
    -			   bool if_not_exists,
    -			   bool is_immutable)
    +static ObjectAddress
    +create_variable(const char *varName,
    +				Oid varNamespace,
    +				Oid varType,
    +				int32 varTypmod,
    +				Oid varOwner,
    +				Oid varCollation,
    +				Node *varDefexpr,
    +				VariableEOXAction eoxaction,
    +				bool is_not_null,
    +				bool if_not_exists,
    +				bool is_immutable)
     {
     	Acl		   *varacl;
     	NameData	varname;
    @@ -235,10 +199,102 @@ VariableCreate(const char *varName,
     }
     
     /*
    - * Remove variable specified by id from pg_variable
    + * Creates a new variable
    + *
    + * Used by CREATE VARIABLE command
    + */
    +ObjectAddress
    +CreateVariable(ParseState *pstate, CreateSessionVarStmt *stmt)
    +{
    +	Oid			namespaceid;
    +	AclResult	aclresult;
    +	Oid			typid;
    +	int32		typmod;
    +	Oid			varowner = GetUserId();
    +	Oid			collation;
    +	Oid			typcollation;
    +	ObjectAddress variable;
    +
    +	Node	   *cooked_default = NULL;
    +
    +	/*
    +	 * Check consistency of arguments
    +	 */
    +	if (stmt->eoxaction == VARIABLE_EOX_DROP
    +		&& stmt->variable->relpersistence != RELPERSISTENCE_TEMP)
    +		ereport(ERROR,
    +				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    +				 errmsg("ON COMMIT DROP can only be used on temporary variables")));
    +
    +	if (stmt->is_not_null && stmt->is_immutable && !stmt->defexpr)
    +		ereport(ERROR,
    +				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    +				 errmsg("IMMUTABLE NOT NULL variable requires default expression")));
    +
    +	namespaceid =
    +		RangeVarGetAndCheckCreationNamespace(stmt->variable, NoLock, NULL);
    +
    +	typenameTypeIdAndMod(pstate, stmt->typeName, &typid, &typmod);
    +	typcollation = get_typcollation(typid);
    +
    +	aclresult = pg_type_aclcheck(typid, GetUserId(), ACL_USAGE);
    +	if (aclresult != ACLCHECK_OK)
    +		aclcheck_error_type(aclresult, typid);
    +
    +	if (stmt->collClause)
    +		collation = LookupCollation(pstate,
    +									stmt->collClause->collname,
    +									stmt->collClause->location);
    +	else
    +		collation = typcollation;;
    +
    +	/* Complain if COLLATE is applied to an uncollatable type */
    +	if (OidIsValid(collation) && !OidIsValid(typcollation))
    +		ereport(ERROR,
    +				(errcode(ERRCODE_DATATYPE_MISMATCH),
    +				 errmsg("collations are not supported by type %s",
    +						format_type_be(typid)),
    +				 parser_errposition(pstate, stmt->collClause->location)));
    +
    +	if (stmt->defexpr)
    +	{
    +		cooked_default = transformExpr(pstate, stmt->defexpr,
    +									   EXPR_KIND_VARIABLE_DEFAULT);
    +
    +		cooked_default = coerce_to_specific_type(pstate,
    +												 cooked_default, typid, "DEFAULT");
    +		assign_expr_collations(pstate, cooked_default);
    +	}
    +
    +	variable = create_variable(stmt->variable->relname,
    +							   namespaceid,
    +							   typid,
    +							   typmod,
    +							   varowner,
    +							   collation,
    +							   cooked_default,
    +							   stmt->eoxaction,
    +							   stmt->is_not_null,
    +							   stmt->if_not_exists,
    +							   stmt->is_immutable);
    +
    +	elog(DEBUG1, "record for session variable \"%s\" (oid:%d) was created in pg_variable",
    +		 stmt->variable->relname, variable.objectId);
    +
    +	/* We want SessionVariableCreatePostprocess to see the catalog changes. */
    +	CommandCounterIncrement();
    +
    +	SessionVariableCreatePostprocess(variable.objectId, stmt->eoxaction);
    +
    +	return variable;
    +}
    +
    +/*
    + * Drop variable by OID, and register the needed session variable
    + * cleanup.
      */
     void
    -VariableDrop(Oid varid)
    +DropVariable(Oid varid)
     {
     	Relation	rel;
     	HeapTuple	tup;
    @@ -255,4 +311,62 @@ VariableDrop(Oid varid)
     	ReleaseSysCache(tup);
     
     	table_close(rel, RowExclusiveLock);
    +
    +	/* Do the necessary cleanup if needed in local memory */
    +	SessionVariableDropPostprocess(varid);
    +}
    +
    +/*
    + * Fetch attributes (without acl) of session variable from the syscache.
    + * We don't work with acl directly, so we don't need to read it here.
    + * Skip deserialization of defexpr when fast_only is true.
    + */
    +void
    +InitVariable(Variable *var, Oid varid, bool fast_only)
    +{
    +	HeapTuple	tup;
    +	Form_pg_variable varform;
    +	Datum		defexpr_datum;
    +	bool		defexpr_isnull;
    +
    +	tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varid));
    +
    +	if (!HeapTupleIsValid(tup))
    +		elog(ERROR, "cache lookup failed for session variable %u", varid);
    +
    +	varform = (Form_pg_variable) GETSTRUCT(tup);
    +
    +	var->oid = varid;
    +	var->create_lsn = varform->create_lsn;
    +	var->name = pstrdup(NameStr(varform->varname));
    +	var->namespaceid = varform->varnamespace;
    +	var->typid = varform->vartype;
    +	var->typmod = varform->vartypmod;
    +	var->owner = varform->varowner;
    +	var->collation = varform->varcollation;
    +	var->is_immutable = varform->varisimmutable;
    +	var->is_not_null = varform->varisnotnull;
    +	var->eoxaction = varform->vareoxaction;
    +
    +	/* Get defexpr */
    +	defexpr_datum = SysCacheGetAttr(VARIABLEOID,
    +									tup,
    +									Anum_pg_variable_vardefexpr,
    +									&defexpr_isnull);
    +
    +	var->has_defexpr = !defexpr_isnull;
    +
    +	/*
    +	 * Deserialize defexpr only when it is requested. We need to deserialize
    +	 * Node with default expression, only when we read from session variable,
    +	 * and this session variable has not assigned value, and this session
    +	 * variable has default expression. For other cases, we skip skip this
    +	 * operation.
    +	 */
    +	if (!fast_only && !defexpr_isnull)
    +		var->defexpr = stringToNode(TextDatumGetCString(defexpr_datum));
    +	else
    +		var->defexpr = NULL;
    +
    +	ReleaseSysCache(tup);
     }
    diff --git a/src/backend/commands/session_variable.c b/src/backend/commands/session_variable.c
    index 4ac6ecf730..3eafc05f89 100644
    --- a/src/backend/commands/session_variable.c
    +++ b/src/backend/commands/session_variable.c
    @@ -13,7 +13,7 @@
      *-------------------------------------------------------------------------
      */
     #include "postgres.h"
    -#include "miscadmin.h"
    +
     #include "access/heapam.h"
     #include "catalog/dependency.h"
     #include "catalog/indexing.h"
    @@ -21,10 +21,7 @@
     #include "catalog/pg_variable.h"
     #include "commands/session_variable.h"
     #include "funcapi.h"
    -#include "parser/parse_coerce.h"
    -#include "parser/parse_collate.h"
    -#include "parser/parse_expr.h"
    -#include "parser/parse_type.h"
    +#include "miscadmin.h"
     #include "utils/builtins.h"
     #include "utils/lsyscache.h"
     #include "utils/memutils.h"
    @@ -58,123 +55,40 @@ static List *xact_drop_actions = NIL;
     static void register_session_variable_xact_action(Oid varid, SVariableXActAction action);
     static void unregister_session_variable_xact_action(Oid varid, SVariableXActAction action);
     
    -/*
    - * Routines used for manipulation with session variables from
    - * SQL level
    - */
     
     /*
    - * Creates new variable - entry in pg_catalog.pg_variable table
    + * Do the necessary work to setup local memory management of a new
    + * variable.
      *
    - * Used by CREATE VARIABLE command
    + * Caller should already have created the necessary entry in catalog
    + * and made them visible.
      */
    -ObjectAddress
    -DefineSessionVariable(ParseState *pstate, CreateSessionVarStmt *stmt)
    +void
    +SessionVariableCreatePostprocess(Oid varid, char eoxaction)
     {
    -	Oid			namespaceid;
    -	AclResult	aclresult;
    -	Oid			typid;
    -	int32		typmod;
    -	Oid			varowner = GetUserId();
    -	Oid			collation;
    -	Oid			typcollation;
    -	ObjectAddress variable;
    -
    -	Node	   *cooked_default = NULL;
    -
    -	/*
    -	 * Check consistency of arguments
    -	 */
    -	if (stmt->eoxaction == VARIABLE_EOX_DROP
    -		&& stmt->variable->relpersistence != RELPERSISTENCE_TEMP)
    -		ereport(ERROR,
    -				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    -				 errmsg("ON COMMIT DROP can only be used on temporary variables")));
    -
    -	if (stmt->is_not_null && stmt->is_immutable && !stmt->defexpr)
    -		ereport(ERROR,
    -				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    -				 errmsg("IMMUTABLE NOT NULL variable requires default expression")));
    -
    -	namespaceid =
    -		RangeVarGetAndCheckCreationNamespace(stmt->variable, NoLock, NULL);
    -
    -	typenameTypeIdAndMod(pstate, stmt->typeName, &typid, &typmod);
    -	typcollation = get_typcollation(typid);
    -
    -	aclresult = pg_type_aclcheck(typid, GetUserId(), ACL_USAGE);
    -	if (aclresult != ACLCHECK_OK)
    -		aclcheck_error_type(aclresult, typid);
    -
    -	if (stmt->collClause)
    -		collation = LookupCollation(pstate,
    -									stmt->collClause->collname,
    -									stmt->collClause->location);
    -	else
    -		collation = typcollation;;
    -
    -	/* Complain if COLLATE is applied to an uncollatable type */
    -	if (OidIsValid(collation) && !OidIsValid(typcollation))
    -		ereport(ERROR,
    -				(errcode(ERRCODE_DATATYPE_MISMATCH),
    -				 errmsg("collations are not supported by type %s",
    -						format_type_be(typid)),
    -				 parser_errposition(pstate, stmt->collClause->location)));
    -
    -	if (stmt->defexpr)
    -	{
    -		cooked_default = transformExpr(pstate, stmt->defexpr,
    -									   EXPR_KIND_VARIABLE_DEFAULT);
    -
    -		cooked_default = coerce_to_specific_type(pstate,
    -												 cooked_default, typid, "DEFAULT");
    -		assign_expr_collations(pstate, cooked_default);
    -	}
    -
    -	variable = VariableCreate(stmt->variable->relname,
    -							  namespaceid,
    -							  typid,
    -							  typmod,
    -							  varowner,
    -							  collation,
    -							  cooked_default,
    -							  stmt->eoxaction,
    -							  stmt->is_not_null,
    -							  stmt->if_not_exists,
    -							  stmt->is_immutable);
    -
    -	elog(DEBUG1, "record for session variable \"%s\" (oid:%d) was created in pg_variable",
    -		 stmt->variable->relname, variable.objectId);
    -
     	/*
     	 * For temporary variables, we need to create a new end of xact action to
     	 * ensure deletion from catalog.
     	 */
    -	if (stmt->eoxaction == VARIABLE_EOX_DROP)
    +	if (eoxaction == VARIABLE_EOX_DROP)
     	{
    -		Assert(isTempNamespace(namespaceid));
    +		Assert(isTempNamespace(get_session_variable_namespace(varid)));
     
    -		register_session_variable_xact_action(variable.objectId,
    -											  SVAR_ON_COMMIT_DROP);
    +		register_session_variable_xact_action(varid, SVAR_ON_COMMIT_DROP);
     	}
    -
    -	return variable;
     }
     
     /*
    - * Drop variable by OID. This routine doesn't try to remove
    - * the value of session variable immediately. It will be
    - * removed on transaction end in sync_sessionvars_xact_callback
    - * routine. This routine manipulate just with system catalog.
    + * Handle the local memory cleanup for a DROP VARIABLE command.
    + *
    + * Caller should take care of removing the pg_variable entry first.
      */
     void
    -RemoveSessionVariable(Oid varid)
    +SessionVariableDropPostprocess(Oid varid)
     {
    -	VariableDrop(varid);
    -
     	/*
    -	 * We removed entry from catalog already, we must not do it again at end
    -	 * of xact time
    +	 * The entry was removed from catalog already, we must not do it
    +	 * again at end of xact time.
     	 */
     	unregister_session_variable_xact_action(varid, SVAR_ON_COMMIT_DROP);
     }
    diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
    index 58f5c2b69c..0bba0ed480 100644
    --- a/src/backend/tcop/utility.c
    +++ b/src/backend/tcop/utility.c
    @@ -1396,7 +1396,7 @@ ProcessUtilitySlow(ParseState *pstate,
     				break;
     
     			case T_CreateSessionVarStmt:
    -				address = DefineSessionVariable(pstate, (CreateSessionVarStmt *) parsetree);
    +				address = CreateVariable(pstate, (CreateSessionVarStmt *) parsetree);
     				break;
     
     				/*
    diff --git a/src/include/catalog/pg_variable.h b/src/include/catalog/pg_variable.h
    index e75222f90c..cde36b0cea 100644
    --- a/src/include/catalog/pg_variable.h
    +++ b/src/include/catalog/pg_variable.h
    @@ -112,21 +112,9 @@ typedef struct Variable
     	Node	   *defexpr;
     } Variable;
     
    -extern void initVariable(Variable *var,
    -						 Oid varid,
    -						 bool fast_only);
    -extern ObjectAddress VariableCreate(const char *varName,
    -									Oid varNamespace,
    -									Oid varType,
    -									int32 varTypmod,
    -									Oid varOwner,
    -									Oid varCollation,
    -									Node *varDefexpr,
    -									VariableEOXAction eoxaction,
    -									bool is_not_null,
    -									bool if_not_exists,
    -									bool is_immutable);
    -
    -extern void VariableDrop(Oid varid);
    +extern ObjectAddress CreateVariable(ParseState *pstate,
    +									CreateSessionVarStmt *stmt);
    +extern void DropVariable(Oid varid);
    +extern void InitVariable(Variable *var, Oid varid, bool fast_only);
     
     #endif							/* PG_VARIABLE_H */
    diff --git a/src/include/commands/session_variable.h b/src/include/commands/session_variable.h
    index 0daf6f41ec..51934e8d1a 100644
    --- a/src/include/commands/session_variable.h
    +++ b/src/include/commands/session_variable.h
    @@ -24,8 +24,8 @@
     #include "utils/queryenvironment.h"
     
     extern void ResetSessionVariables(void);
    -extern void RemoveSessionVariable(Oid varid);
    -extern ObjectAddress DefineSessionVariable(ParseState *pstate, CreateSessionVarStmt *stmt);
    +extern void SessionVariableCreatePostprocess(Oid varid, char eoxaction);
    +extern void SessionVariableDropPostprocess(Oid varid);
     
     extern Datum CopySessionVariable(Oid varid, bool *isNull, Oid *typid);
     extern Datum CopySessionVariableWithTypeCheck(Oid varid, bool *isNull, Oid expected_typid);
    -- 
    2.37.0
    
    
    --z3ntqfnlkpftg4xg
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: attachment;
    	filename="v20220922-0003-session-variables.patch"