From a7513b34828091b6608b3abf93c15efaea9a800d Mon Sep 17 00:00:00 2001 From: "okbob@github.com" Date: Wed, 28 May 2025 08:30:25 +0200 Subject: [PATCH 01/15] introduce new class (catalog) pg_variable This table holds metadata about session variables created by command CREATE VARIABLE, and dropped by command DROP VARIABLE. --- doc/src/sgml/catalogs.sgml | 133 ++++++++++++++++++++ src/backend/catalog/Makefile | 1 + src/backend/catalog/meson.build | 1 + src/backend/catalog/pg_variable.c | 168 +++++++++++++++++++++++++ src/include/catalog/Makefile | 3 +- src/include/catalog/meson.build | 1 + src/include/catalog/pg_variable.h | 96 ++++++++++++++ src/test/regress/expected/oidjoins.out | 4 + src/tools/pgindent/typedefs.list | 2 + 9 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 src/backend/catalog/pg_variable.c create mode 100644 src/include/catalog/pg_variable.h diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 6c8a0f173c9..7c79ddc9c09 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -369,6 +369,11 @@ pg_user_mapping mappings of users to foreign servers + + + pg_variable + session variables + @@ -9834,4 +9839,132 @@ SCRAM-SHA-256$<iteration count>:&l + + <structname>pg_variable</structname> + + + pg_variable + + + + The catalog pg_variable stores information about + session variables. + + + + <structname>pg_variable</structname> Columns + + + + + Column Type + + + Description + + + + + + + + oid oid + + + Row identifier + + + + + + vartype oid + (references pg_type.oid) + + + The OID of the variable's data type + + + + + + varcreate_lsn pg_lsn + + + LSN of the transaction where the variable was created. + varcreate_lsn and + oid together form the all-time unique + identifier (oid alone is not enough, since + object identifiers can get reused). + + + + + + varname name + + + Name of the session variable + + + + + + varnamespace oid + (references pg_namespace.oid) + + + The OID of the namespace that contains this variable + + + + + + varowner oid + (references pg_authid.oid) + + + Owner of the variable + + + + + + vartypmod int4 + + + vartypmod records type-specific data + supplied at variable creation time (for example, the maximum + length of a varchar column). It is passed to + type-specific input functions and length coercion functions. + The value will generally be -1 for types that do not need vartypmod. + + + + + + varcollation oid + (references pg_collation.oid) + + + The defined collation of the variable, or zero if the variable is + not of a collatable data type. + + + + + + varacl aclitem[] + + + Access privileges; see + and + + for details + + + + + +
+
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index c090094ed08..2c20d60db19 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -45,6 +45,7 @@ OBJS = \ pg_shdepend.o \ pg_subscription.o \ pg_type.o \ + pg_variable.o \ storage.o \ toasting.o diff --git a/src/backend/catalog/meson.build b/src/backend/catalog/meson.build index 1958ea9238a..ed44c877fca 100644 --- a/src/backend/catalog/meson.build +++ b/src/backend/catalog/meson.build @@ -32,6 +32,7 @@ backend_sources += files( 'pg_shdepend.c', 'pg_subscription.c', 'pg_type.c', + 'pg_variable.c', 'storage.c', 'toasting.c', ) diff --git a/src/backend/catalog/pg_variable.c b/src/backend/catalog/pg_variable.c new file mode 100644 index 00000000000..bd6a29a79e5 --- /dev/null +++ b/src/backend/catalog/pg_variable.c @@ -0,0 +1,168 @@ +/*------------------------------------------------------------------------- + * + * pg_variable.c + * session variables + * + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/catalog/pg_variable.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/heapam.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/namespace.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_namespace.h" +#include "catalog/pg_variable.h" +#include "utils/builtins.h" +#include "utils/pg_lsn.h" +#include "utils/syscache.h" + +/* + * Creates entry in pg_variable table + */ +ObjectAddress +create_variable(const char *varName, + Oid varNamespace, + Oid varType, + int32 varTypmod, + Oid varOwner, + Oid varCollation, + bool if_not_exists) +{ + NameData varname; + bool nulls[Natts_pg_variable]; + Datum values[Natts_pg_variable]; + Relation rel; + HeapTuple tup; + TupleDesc tupdesc; + ObjectAddress myself, + referenced; + ObjectAddresses *addrs; + Oid varid; + + Assert(varName); + Assert(OidIsValid(varNamespace)); + Assert(OidIsValid(varType)); + Assert(OidIsValid(varOwner)); + + rel = table_open(VariableRelationId, RowExclusiveLock); + + /* + * Check for duplicates. Note that this does not really prevent + * duplicates, it's here just to provide nicer error message in common + * case. The real protection is the unique key on the catalog. + */ + if (SearchSysCacheExists2(VARIABLENAMENSP, + PointerGetDatum(varName), + ObjectIdGetDatum(varNamespace))) + { + if (if_not_exists) + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("session variable \"%s\" already exists, skipping", + varName))); + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("session variable \"%s\" already exists", + varName))); + + table_close(rel, RowExclusiveLock); + + return InvalidObjectAddress; + } + + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + namestrcpy(&varname, varName); + + varid = GetNewOidWithIndex(rel, VariableOidIndexId, Anum_pg_variable_oid); + + values[Anum_pg_variable_oid - 1] = ObjectIdGetDatum(varid); + values[Anum_pg_variable_varcreate_lsn - 1] = LSNGetDatum(GetXLogInsertRecPtr()); + values[Anum_pg_variable_varname - 1] = NameGetDatum(&varname); + values[Anum_pg_variable_varnamespace - 1] = ObjectIdGetDatum(varNamespace); + values[Anum_pg_variable_vartype - 1] = ObjectIdGetDatum(varType); + values[Anum_pg_variable_vartypmod - 1] = Int32GetDatum(varTypmod); + values[Anum_pg_variable_varowner - 1] = ObjectIdGetDatum(varOwner); + values[Anum_pg_variable_varcollation - 1] = ObjectIdGetDatum(varCollation); + + nulls[Anum_pg_variable_varacl - 1] = true; + + tupdesc = RelationGetDescr(rel); + + tup = heap_form_tuple(tupdesc, values, nulls); + CatalogTupleInsert(rel, tup); + Assert(OidIsValid(varid)); + + addrs = new_object_addresses(); + + ObjectAddressSet(myself, VariableRelationId, varid); + + /* dependency on namespace */ + ObjectAddressSet(referenced, NamespaceRelationId, varNamespace); + add_exact_object_address(&referenced, addrs); + + /* dependency on used type */ + ObjectAddressSet(referenced, TypeRelationId, varType); + add_exact_object_address(&referenced, addrs); + + /* dependency on collation */ + if (OidIsValid(varCollation) && + varCollation != DEFAULT_COLLATION_OID) + { + ObjectAddressSet(referenced, CollationRelationId, varCollation); + add_exact_object_address(&referenced, addrs); + } + + record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); + free_object_addresses(addrs); + + /* dependency on owner */ + recordDependencyOnOwner(VariableRelationId, varid, varOwner); + + /* dependency on extension */ + recordDependencyOnCurrentExtension(&myself, false); + + heap_freetuple(tup); + + /* post creation hook for new function */ + InvokeObjectPostCreateHook(VariableRelationId, varid, 0); + + table_close(rel, RowExclusiveLock); + + return myself; +} + +/* + * Drop variable by OID + */ +void +DropVariableById(Oid varid) +{ + Relation rel; + HeapTuple tup; + + rel = table_open(VariableRelationId, RowExclusiveLock); + + tup = SearchSysCache1(VARIABLEOID, ObjectIdGetDatum(varid)); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for variable %u", varid); + + CatalogTupleDelete(rel, &tup->t_self); + + ReleaseSysCache(tup); + + table_close(rel, RowExclusiveLock); +} diff --git a/src/include/catalog/Makefile b/src/include/catalog/Makefile index 2bbc7805fe3..f98760de635 100644 --- a/src/include/catalog/Makefile +++ b/src/include/catalog/Makefile @@ -81,7 +81,8 @@ CATALOG_HEADERS := \ pg_publication_namespace.h \ pg_publication_rel.h \ pg_subscription.h \ - pg_subscription_rel.h + pg_subscription_rel.h \ + pg_variable.h GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) diff --git a/src/include/catalog/meson.build b/src/include/catalog/meson.build index ec1cf467f6f..81398efa7c9 100644 --- a/src/include/catalog/meson.build +++ b/src/include/catalog/meson.build @@ -69,6 +69,7 @@ catalog_headers = [ 'pg_publication_rel.h', 'pg_subscription.h', 'pg_subscription_rel.h', + 'pg_variable.h', ] # The .dat files we need can just be listed alphabetically. diff --git a/src/include/catalog/pg_variable.h b/src/include/catalog/pg_variable.h new file mode 100644 index 00000000000..15f530894c5 --- /dev/null +++ b/src/include/catalog/pg_variable.h @@ -0,0 +1,96 @@ +/*------------------------------------------------------------------------- + * + * pg_variable.h + * definition of session variables system catalog (pg_variables) + * + * + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_variable.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_VARIABLE_H +#define PG_VARIABLE_H + +#include "access/xlogdefs.h" +#include "catalog/genbki.h" +#include "catalog/objectaddress.h" +#include "catalog/pg_variable_d.h" +#include "utils/acl.h" + +/* ---------------- + * pg_variable definition. cpp turns this into + * typedef struct FormData_pg_variable + * ---------------- + */ +CATALOG(pg_variable,9222,VariableRelationId) +{ + Oid oid; /* oid */ + + /* OID of entry in pg_type for variable's type */ + Oid vartype BKI_LOOKUP(pg_type); + + /* + * Used for identity check [oid, create_lsn]. + * + * This column of the 8-byte XlogRecPtr type should be at an address that + * is divisible by 8, but before any column of type NameData. + */ + XLogRecPtr varcreate_lsn; + + /* variable name */ + NameData varname; + + /* OID of namespace containing variable class */ + Oid varnamespace BKI_LOOKUP(pg_namespace); + + /* variable owner */ + Oid varowner BKI_LOOKUP(pg_authid); + + /* typmod for variable's type */ + int32 vartypmod BKI_DEFAULT(-1); + + /* variable collation */ + Oid varcollation BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_collation); + + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + + /* access permissions */ + aclitem varacl[1] BKI_DEFAULT(_null_); + +#endif +} FormData_pg_variable; + +/* ---------------- + * Form_pg_variable corresponds to a pointer to a tuple with + * the format of the pg_variable relation. + * ---------------- + */ +typedef FormData_pg_variable *Form_pg_variable; + +DECLARE_TOAST(pg_variable, 9223, 9224); + +DECLARE_UNIQUE_INDEX_PKEY(pg_variable_oid_index, 9225, VariableOidIndexId, pg_variable, btree(oid oid_ops)); +DECLARE_UNIQUE_INDEX(pg_variable_varname_nsp_index, 9226, VariableNameNspIndexId, pg_variable, btree(varname name_ops, varnamespace oid_ops)); + +MAKE_SYSCACHE(VARIABLENAMENSP, pg_variable_varname_nsp_index, 8); +MAKE_SYSCACHE(VARIABLEOID, pg_variable_oid_index, 8); + +extern ObjectAddress create_variable(const char *varName, + Oid varNamespace, + Oid varType, + int32 varTypmod, + Oid varOwner, + Oid varCollation, + bool if_not_exists); + +extern void DropVariableById(Oid varid); + +#endif /* PG_VARIABLE_H */ diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index 215eb899be3..d9953321402 100644 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -266,3 +266,7 @@ NOTICE: checking pg_subscription {subdbid} => pg_database {oid} NOTICE: checking pg_subscription {subowner} => pg_authid {oid} NOTICE: checking pg_subscription_rel {srsubid} => pg_subscription {oid} NOTICE: checking pg_subscription_rel {srrelid} => pg_class {oid} +NOTICE: checking pg_variable {vartype} => pg_type {oid} +NOTICE: checking pg_variable {varnamespace} => pg_namespace {oid} +NOTICE: checking pg_variable {varowner} => pg_authid {oid} +NOTICE: checking pg_variable {varcollation} => pg_collation {oid} diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 432509277c9..cf5c87c03a2 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -911,6 +911,7 @@ FormData_pg_ts_parser FormData_pg_ts_template FormData_pg_type FormData_pg_user_mapping +FormData_pg_variable FormExtraData_pg_attribute Form_pg_aggregate Form_pg_am @@ -970,6 +971,7 @@ Form_pg_ts_parser Form_pg_ts_template Form_pg_type Form_pg_user_mapping +Form_pg_variable FormatNode FreeBlockNumberArray FreeListData -- 2.51.1