PostgreSQL的学习心得和知识总结(一百三十九)|深入理解PostgreSQL数据库GUC参数 allow_alter_system 的使用和原理

本文主要是介绍PostgreSQL的学习心得和知识总结(一百三十九)|深入理解PostgreSQL数据库GUC参数 allow_alter_system 的使用和原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下:

1、参考书籍:《PostgreSQL数据库内核分析》
2、参考书籍:《数据库事务处理的艺术:事务管理与并发控制》
3、PostgreSQL数据库仓库链接,点击前往
4、日本著名PostgreSQL数据库专家 铃木启修 网站主页,点击前往
5、参考书籍:《PostgreSQL中文手册》
6、参考书籍:《PostgreSQL指南:内幕探索》,点击前往
7、参考书籍:《事务处理 概念与技术》
8、PgSQL · 性能优化 · PostgreSQL TPC-C极限优化玩法,点击前往


1、本文内容全部来源于开源社区 GitHub和以上博主的贡献,本文也免费开源(可能会存在问题,评论区等待大佬们的指正)
2、本文目的:开源共享 抛砖引玉 一起学习
3、本文不提供任何资源 不存在任何交易 与任何组织和机构无关
4、大家可以根据需要自行 复制粘贴以及作为其他个人用途,但是不允许转载 不允许商用 (写作不易,还请见谅 💖)
5、本文内容基于PostgreSQL master源码开发而成


深入理解PostgreSQL数据库GUC参数 allow_alter_system 的使用和原理

  • 文章快速说明索引
  • 参数使用背景说明
    • 背景
    • 使用
  • 参数实现源码解析



文章快速说明索引

学习目标:

做数据库内核开发久了就会有一种 少年得志,年少轻狂 的错觉,然鹅细细一品觉得自己其实不算特别优秀 远远没有达到自己想要的。也许光鲜的表面掩盖了空洞的内在,每每想到于此,皆有夜半临渊如履薄冰之感。为了睡上几个踏实觉,即日起 暂缓其他基于PostgreSQL数据库的兼容功能开发,近段时间 将着重于学习分享Postgres的基础知识和实践内幕。


学习内容:(详见目录)

1、深入理解PostgreSQL数据库GUC参数 allow_alter_system 的使用和原理


学习时间:

2024年04月21日 14:44:16


学习产出:

1、PostgreSQL数据库基础知识回顾 1个
2、CSDN 技术博客 1篇
3、PostgreSQL数据库内核深入学习


注:下面我们所有的学习环境是Centos8+PostgreSQL master +Oracle19C+MySQL8.0

postgres=# select version();version                                                   
------------------------------------------------------------------------------------------------------------PostgreSQL 17devel on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-21), 64-bit
(1 row)postgres=##-----------------------------------------------------------------------------#SQL> select * from v$version;          BANNER        Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production	
BANNER_FULL	  Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production Version 19.17.0.0.0	
BANNER_LEGACY Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production	
CON_ID 0#-----------------------------------------------------------------------------#mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.27    |
+-----------+
1 row in set (0.06 sec)mysql>

参数使用背景说明

背景

2024/03/29日,PostgreSQL新增一个GUC参数,如下:

  • Discussion: Possibility to disable ALTER SYSTEM,点击前往

添加allow_alter_system GUC


这个被标记为PGC_SIGHUP,所以只能在配置文件中设置,不能在其他地方设置;并且它还被标记为GUC_DISALLOW_IN_AUTO_FILE,因此不能使用ALTER SYSTEM进行设置。当设置为 false 时,不允许使用 ALTER SYSTEM 命令


人们非常担心这会被误解为安全功能,但事实并非如此,因为坚定的超级用户可以通过多种方式绕过它。因此,我们在文档的措辞上做了很多工作,希望避免任何此类混乱


官方文档的解释,如下:

当allow_alter_system设置为off时,执行ALTER SYSTEM命令会返回错误。该参数只能在 postgresql.conf 文件或服务器命令行中设置。默认值是打开的

请注意,此设置不得视为安全功能。它仅禁用 ALTER SYSTEM 命令。它不会阻止超级用户使用其他 SQL 命令更改配置。超级用户有多种在操作系统级别执行 shell 命令的方法,因此可以修改 postgresql.auto.conf,无论此设置的值如何

关闭此设置适用于 PostgreSQL 配置由某些外部工具管理的环境。在这种环境中,善意的超级用户可能会错误地使用 ALTER SYSTEM 来更改配置,而不是使用外部工具。这可能会导致意外行为,例如外部工具在稍后更新配置时覆盖更改。将此参数设置为关闭可以帮助避免此类错误

该参数仅控制 ALTER SYSTEM 的使用。即使allow_alter_system设置为off,存储在postgresql.auto.conf中的设置也会生效


使用

接下来看一个简单的使用,示例1如下:

[postgres@localhost:~/test/bin]$ ./psql 
psql (17devel)
Type "help" for help.postgres=# show timezone;TimeZone       
---------------------America/Los_Angeles
(1 row)postgres=# set timezone = 'PRC';
SET
postgres=# show timezone;TimeZone 
----------PRC
(1 row)postgres=# select now();now              
-------------------------------2024-04-18 15:35:49.411729+08
(1 row)postgres=# reset timezone;
RESET
postgres=# show timezone;TimeZone       
---------------------America/Los_Angeles
(1 row)postgres=# select now();now              
-------------------------------2024-04-18 00:36:06.505543-07
(1 row)postgres=# alter system set timezone = 'PRC';
2024-04-18 00:36:23.026 PDT [30697] ERROR:  ALTER SYSTEM is not allowed in this environment
2024-04-18 00:36:23.026 PDT [30697] STATEMENT:  alter system set timezone = 'PRC';
ERROR:  ALTER SYSTEM is not allowed in this environment
postgres=# 
postgres=# show timezone;TimeZone       
---------------------America/Los_Angeles
(1 row)postgres=# show allow_alter_system;allow_alter_system 
--------------------off
(1 row)postgres=# alter system set allow_alter_system = on;
2024-04-18 00:40:03.694 PDT [30697] ERROR:  ALTER SYSTEM is not allowed in this environment
2024-04-18 00:40:03.694 PDT [30697] STATEMENT:  alter system set allow_alter_system = on;
ERROR:  ALTER SYSTEM is not allowed in this environment
postgres=#
[postgres@localhost:~/test/bin]$ cat test/postgresql.conf | grep allow_alter_system
allow_alter_system = off
[postgres@localhost:~/test/bin]$

示例2,如下:

[postgres@localhost:~/test/bin]$ cat test/postgresql.conf | grep allow_alter_system
allow_alter_system = off
[postgres@localhost:~/test/bin]$ 
[postgres@localhost:~/test/bin]$ vim test/postgresql.auto.conf 
[postgres@localhost:~/test/bin]$ 
[postgres@localhost:~/test/bin]$ cat test/postgresql.auto.conf 
# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
allow_alter_system = on
[postgres@localhost:~/test/bin]$ 
[postgres@localhost:~/test/bin]$ ./pg_ctl restart -D test/
waiting for server to shut down....2024-04-24 23:05:34.217 PDT [30683] LOG:  received fast shutdown request
2024-04-24 23:05:34.219 PDT [30683] LOG:  aborting any active transactions
2024-04-24 23:05:34.220 PDT [30683] LOG:  background worker "logical replication launcher" (PID 30689) exited with exit code 1
2024-04-24 23:05:34.221 PDT [30684] LOG:  shutting down
2024-04-24 23:05:34.240 PDT [30683] LOG:  database system is shut downdone
server stopped
waiting for server to start....2024-04-24 23:05:34.361 PDT [50234] LOG:  starting PostgreSQL 17devel on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-21), 64-bit
2024-04-24 23:05:34.361 PDT [50234] LOG:  listening on IPv6 address "::1", port 5432
2024-04-24 23:05:34.361 PDT [50234] LOG:  listening on IPv4 address "127.0.0.1", port 5432
2024-04-24 23:05:34.363 PDT [50234] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5432"
2024-04-24 23:05:34.366 PDT [50237] LOG:  database system was shut down at 2024-04-24 23:05:34 PDT
2024-04-24 23:05:34.370 PDT [50234] LOG:  database system is ready to accept connectionsdone
server started
[postgres@localhost:~/test/bin]$ ./psql 
psql (17devel)
Type "help" for help.postgres=# show allow_alter_system;allow_alter_system 
--------------------on
(1 row)postgres=# show timezone;TimeZone       
---------------------America/Los_Angeles
(1 row)postgres=# alter system set timezone = 'PRC';
ALTER SYSTEM
postgres=# alter system set allow_alter_system = off;
2024-04-24 23:06:26.063 PDT [50248] ERROR:  parameter "allow_alter_system" cannot be changed
2024-04-24 23:06:26.063 PDT [50248] STATEMENT:  alter system set allow_alter_system = off;
ERROR:  parameter "allow_alter_system" cannot be changed
postgres=#

参数实现源码解析

guc定义,如下:

// src\backend\utils\misc\guc_tables.c{/** This setting itself cannot be set by ALTER SYSTEM to avoid an* operator turning this setting off by using ALTER SYSTEM, without a* way to turn it back on.*  * 此设置本身无法通过 ALTER SYSTEM 设置,以避免操作员使用 ALTER SYSTEM 关闭此设置* 而无法将其重新打开*/{"allow_alter_system", PGC_SIGHUP, COMPAT_OPTIONS_OTHER,gettext_noop("Allows running the ALTER SYSTEM command."),gettext_noop("Can be set to off for environments where global configuration ""changes should be made using a different method."),GUC_DISALLOW_IN_AUTO_FILE},&AllowAlterSystem,true,NULL, NULL, NULL},

该参数真实使用的逻辑,如下:

// src\backend\utils\misc\guc.c/** Execute ALTER SYSTEM statement.** Read the old PG_AUTOCONF_FILENAME file, merge in the new variable value,* and write out an updated file.  If the command is ALTER SYSTEM RESET ALL,* we can skip reading the old file and just write an empty file.* 读取旧的 PG_AUTOCONF_FILENAME 文件,合并新的变量值,并写出更新的文件* 如果命令是 ALTER SYSTEM RESET ALL,我们可以跳过读取旧文件,只写入一个空文件** An LWLock is used to serialize updates of the configuration file.* LWLock 用于序列化配置文件的更新** In case of an error, we leave the original automatic* configuration file (PG_AUTOCONF_FILENAME) intact.* 如果出现错误,我们会保留原始自动配置文件(PG_AUTOCONF_FILENAME)不变*/
void
AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
{char	   *name;char	   *value;bool		resetall = false;ConfigVariable *head = NULL;ConfigVariable *tail = NULL;volatile int Tmpfd;char		AutoConfFileName[MAXPGPATH];char		AutoConfTmpFileName[MAXPGPATH];/** Extract statement arguments*/name = altersysstmt->setstmt->name;if (!AllowAlterSystem)ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),errmsg("ALTER SYSTEM is not allowed in this environment")));switch (altersysstmt->setstmt->kind){case VAR_SET_VALUE:value = ExtractSetVariableArgs(altersysstmt->setstmt);break;case VAR_SET_DEFAULT:case VAR_RESET:value = NULL;break;case VAR_RESET_ALL:value = NULL;resetall = true;break;default:elog(ERROR, "unrecognized alter system stmt type: %d",altersysstmt->setstmt->kind);break;}/** Check permission to run ALTER SYSTEM on the target variable*/if (!superuser()){if (resetall)ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),errmsg("permission denied to perform ALTER SYSTEM RESET ALL")));else{AclResult	aclresult;aclresult = pg_parameter_aclcheck(name, GetUserId(),ACL_ALTER_SYSTEM);if (aclresult != ACLCHECK_OK)ereport(ERROR,(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),errmsg("permission denied to set parameter \"%s\"",name)));}}/** Unless it's RESET_ALL, validate the target variable and value*/if (!resetall){struct config_generic *record;/* We don't want to create a placeholder if there's not one already */record = find_option(name, false, true, DEBUG5);if (record != NULL){/** Don't allow parameters that can't be set in configuration files* to be set in PG_AUTOCONF_FILENAME file.*/if ((record->context == PGC_INTERNAL) ||(record->flags & GUC_DISALLOW_IN_FILE) ||(record->flags & GUC_DISALLOW_IN_AUTO_FILE))ereport(ERROR,(errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM),errmsg("parameter \"%s\" cannot be changed",name)));/** If a value is specified, verify that it's sane.*/if (value){union config_var_val newval;void	   *newextra = NULL;if (!parse_and_validate_value(record, name, value,PGC_S_FILE, ERROR,&newval, &newextra))ereport(ERROR,(errcode(ERRCODE_INVALID_PARAMETER_VALUE),errmsg("invalid value for parameter \"%s\": \"%s\"",name, value)));if (record->vartype == PGC_STRING && newval.stringval != NULL)guc_free(newval.stringval);guc_free(newextra);}}else{/** Variable not known; check we'd be allowed to create it.  (We* cannot validate the value, but that's fine.  A non-core GUC in* the config file cannot cause postmaster start to fail, so we* don't have to be too tense about possibly installing a bad* value.)*/(void) assignable_custom_variable_name(name, false, ERROR);}/** We must also reject values containing newlines, because the grammar* for config files doesn't support embedded newlines in string* literals.*/if (value && strchr(value, '\n'))ereport(ERROR,(errcode(ERRCODE_INVALID_PARAMETER_VALUE),errmsg("parameter value for ALTER SYSTEM must not contain a newline")));}/** PG_AUTOCONF_FILENAME and its corresponding temporary file are always in* the data directory, so we can reference them by simple relative paths.*/snprintf(AutoConfFileName, sizeof(AutoConfFileName), "%s",PG_AUTOCONF_FILENAME);snprintf(AutoConfTmpFileName, sizeof(AutoConfTmpFileName), "%s.%s",AutoConfFileName,"tmp");/** Only one backend is allowed to operate on PG_AUTOCONF_FILENAME at a* time.  Use AutoFileLock to ensure that.  We must hold the lock while* reading the old file contents.*/LWLockAcquire(AutoFileLock, LW_EXCLUSIVE);/** If we're going to reset everything, then no need to open or parse the* old file.  We'll just write out an empty list.*/if (!resetall){struct stat st;if (stat(AutoConfFileName, &st) == 0){/* open old file PG_AUTOCONF_FILENAME */FILE	   *infile;infile = AllocateFile(AutoConfFileName, "r");if (infile == NULL)ereport(ERROR,(errcode_for_file_access(),errmsg("could not open file \"%s\": %m",AutoConfFileName)));/* parse it */if (!ParseConfigFp(infile, AutoConfFileName, CONF_FILE_START_DEPTH,LOG, &head, &tail))ereport(ERROR,(errcode(ERRCODE_CONFIG_FILE_ERROR),errmsg("could not parse contents of file \"%s\"",AutoConfFileName)));FreeFile(infile);}/** Now, replace any existing entry with the new value, or add it if* not present.*/replace_auto_config_value(&head, &tail, name, value);}/** Invoke the post-alter hook for setting this GUC variable.  GUCs* typically do not have corresponding entries in pg_parameter_acl, so we* call the hook using the name rather than a potentially-non-existent* OID.  Nonetheless, we pass ParameterAclRelationId so that this call* context can be distinguished from others.  (Note that "name" will be* NULL in the RESET ALL case.)** We do this here rather than at the end, because ALTER SYSTEM is not* transactional.  If the hook aborts our transaction, it will be cleaner* to do so before we touch any files.*/InvokeObjectPostAlterHookArgStr(ParameterAclRelationId, name,ACL_ALTER_SYSTEM,altersysstmt->setstmt->kind,false);/** To ensure crash safety, first write the new file data to a temp file,* then atomically rename it into place.** If there is a temp file left over due to a previous crash, it's okay to* truncate and reuse it.*/Tmpfd = BasicOpenFile(AutoConfTmpFileName,O_CREAT | O_RDWR | O_TRUNC);if (Tmpfd < 0)ereport(ERROR,(errcode_for_file_access(),errmsg("could not open file \"%s\": %m",AutoConfTmpFileName)));/** Use a TRY block to clean up the file if we fail.  Since we need a TRY* block anyway, OK to use BasicOpenFile rather than OpenTransientFile.*/PG_TRY();{/* Write and sync the new contents to the temporary file */write_auto_conf_file(Tmpfd, AutoConfTmpFileName, head);/* Close before renaming; may be required on some platforms */close(Tmpfd);Tmpfd = -1;/** As the rename is atomic operation, if any problem occurs after this* at worst it can lose the parameters set by last ALTER SYSTEM* command.*/durable_rename(AutoConfTmpFileName, AutoConfFileName, ERROR);}PG_CATCH();{/* Close file first, else unlink might fail on some platforms */if (Tmpfd >= 0)close(Tmpfd);/* Unlink, but ignore any error */(void) unlink(AutoConfTmpFileName);PG_RE_THROW();}PG_END_TRY();FreeConfigVariables(head);LWLockRelease(AutoFileLock);
}

这篇关于PostgreSQL的学习心得和知识总结(一百三十九)|深入理解PostgreSQL数据库GUC参数 allow_alter_system 的使用和原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/936082

相关文章

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

数据库oracle用户密码过期查询及解决方案

《数据库oracle用户密码过期查询及解决方案》:本文主要介绍如何处理ORACLE数据库用户密码过期和修改密码期限的问题,包括创建用户、赋予权限、修改密码、解锁用户和设置密码期限,文中通过代码介绍... 目录前言一、创建用户、赋予权限、修改密码、解锁用户和设置期限二、查询用户密码期限和过期后的修改1.查询用

python管理工具之conda安装部署及使用详解

《python管理工具之conda安装部署及使用详解》这篇文章详细介绍了如何安装和使用conda来管理Python环境,它涵盖了从安装部署、镜像源配置到具体的conda使用方法,包括创建、激活、安装包... 目录pytpshheraerUhon管理工具:conda部署+使用一、安装部署1、 下载2、 安装3

Mysql虚拟列的使用场景

《Mysql虚拟列的使用场景》MySQL虚拟列是一种在查询时动态生成的特殊列,它不占用存储空间,可以提高查询效率和数据处理便利性,本文给大家介绍Mysql虚拟列的相关知识,感兴趣的朋友一起看看吧... 目录1. 介绍mysql虚拟列1.1 定义和作用1.2 虚拟列与普通列的区别2. MySQL虚拟列的类型2

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

关于@MapperScan和@ComponentScan的使用问题

《关于@MapperScan和@ComponentScan的使用问题》文章介绍了在使用`@MapperScan`和`@ComponentScan`时可能会遇到的包扫描冲突问题,并提供了解决方法,同时,... 目录@MapperScan和@ComponentScan的使用问题报错如下原因解决办法课外拓展总结@

mysql数据库分区的使用

《mysql数据库分区的使用》MySQL分区技术通过将大表分割成多个较小片段,提高查询性能、管理效率和数据存储效率,本文就来介绍一下mysql数据库分区的使用,感兴趣的可以了解一下... 目录【一】分区的基本概念【1】物理存储与逻辑分割【2】查询性能提升【3】数据管理与维护【4】扩展性与并行处理【二】分区的

使用Python实现在Word中添加或删除超链接

《使用Python实现在Word中添加或删除超链接》在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能,本文将为大家介绍一下Python如何实现在Word中添加或... 在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超

Linux使用fdisk进行磁盘的相关操作

《Linux使用fdisk进行磁盘的相关操作》fdisk命令是Linux中用于管理磁盘分区的强大文本实用程序,这篇文章主要为大家详细介绍了如何使用fdisk进行磁盘的相关操作,需要的可以了解下... 目录简介基本语法示例用法列出所有分区查看指定磁盘的区分管理指定的磁盘进入交互式模式创建一个新的分区删除一个存

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,