[PATCH v20220922 02/13] FIXUP 0001-catalog-support-for-session-variables
Julien Rouhaud <julien.rouhaud@free.fr>
From: Julien Rouhaud <julien.rouhaud@free.fr>
To:
Date: 2022-09-13T08:06:59Z
Lists: pgsql-hackers
---
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"