search_path 如何影响标识符解析和“当前模式”

Posted

技术标签:

【中文标题】search_path 如何影响标识符解析和“当前模式”【英文标题】:How does the search_path influence identifier resolution and the "current schema" 【发布时间】:2012-02-22 10:50:16 【问题描述】:

是否可以定义默认在哪个模式中创建新表? (由“不合格的表名”引用。)

我已经看到了有关在 Postgres 中使用“搜索路径”的一些细节,但我认为它只在检索数据时有效,而不是在创建时有效。

我有一堆 SQL 脚本,它们创建了许多表。我不想修改脚本,而是在默认情况下将数据库创建表设置为特定模式 - 当它们具有非限定名称时。

这可能吗?

【问题讨论】:

【参考方案1】:

什么是架构搜索路径search_path

The manual:

[...] 表通常由非限定名称引用,这些名称包括 只是表名。系统确定哪个表是指 遵循搜索路径,这是要查看的架构列表

我的大胆强调。这解释了标识符解析

“当前架构”(或“默认架构”)是 per documentation:

在搜索路径中命名的第一个架构称为当前 架构。除了是第一个搜索到的模式之外,它也是 如果CREATE TABLE 命令将在其中创建新表的架构 未指定架构名称。

我的大胆强调。系统架构 pg_temp(当前会话的临时对象的架构)和 pg_catalog 自动成为搜索路径的一部分并被搜索首先,按此顺序。 The manual:

pg_catalog 始终是搜索路径的有效部分。如果不是 在路径中显式命名,然后在 之前 隐式搜索 搜索路径的模式。这确保了内置名称将 总是可以找到的。但是,您可以将pg_catalog 显式放置在 如果您希望使用用户定义的名称,则搜索路径的结尾 覆盖内置名称。

按照原文的粗体强调。而pg_temp 在此之前出现,除非它被放到不同的位置。

如何设置?

有多种方法可以设置运行时变量search_path

    postgresql.conf 中的所有数据库中的所有角色设置集群 范围的默认值(并重新加载)。小心点!

    search_path = 'blarg,public'
    

    shipped default for this setting 是:

    search_path = "$user",public
    

    第一个元素指定与 当前用户将被搜索。如果不存在这样的架构,则忽略该条目。

    将其设置为一个数据库的默认值:

    ALTER DATABASE test SET search_path = blarg,public;
    

    将其设置为您连接的角色的默认值(在集群范围内有效):

    ALTER ROLE foo SET search_path = blarg,public;
    

    甚至(通常是最好的!)作为数据库中的角色的默认设置:

    ALTER ROLE foo IN DATABASE test SET search_path = blarg,public;
    

    在脚本顶部编写命令。或者在您的数据库会话中执行它:

    SET search_path = blarg,public;
    

    函数范围设置一个特定的search_path(以防止具有足够权限的恶意用户)。阅读手册中的Writing SECURITY DEFINER Functions Safely。

CREATE FUNCTION foo() RETURNS void AS
$func$
BEGIN
   -- do stuff
END
$func$ LANGUAGE plpgsql SECURITY DEFINER
       SET search_path=blarg,public,pg_temp;

我列表中较高的数字胜过较低的数字。manual has even more ways,比如设置环境变量或者使用命令行选项。

查看当前设置:

SHOW search_path;

致reset它:

RESET search_path;

The manual:

默认值被定义为参数将 如果在当前会话中没有为它发出过SET,那么已经有过。

【讨论】:

我在上面的 cmets 上说的是这个 :) 感谢您向我展示这些选项 ;) +1 用于 ALTER DATABASE,不知道,非常有用:) 谢谢@Erwin。阅读您的回答后,我发现RESET search_path; 为我解决了问题。 (#6?) @BKSpureon:blarg 只是 foo 和 bar 的丑兄弟。一个随机的名字。 请记住,在会话期间设置搜索路径可能与最理想的 pgBouncer 策略不兼容【参考方案2】:

搜索路径确实是你想要的:

% create schema blarg;
% set search_path to blarg;
% create table foo (id int);
% \d
       List of relations
 Schema | Name | Type  | Owner 
--------+------+-------+-------
 blarg  | foo  | table | pgsql

【讨论】:

是的,你是对的......但你已经知道了:)。但我认为它不起作用,因为我以前尝试过,但在不同的会话中:在一个我做了 set search_path,在另一个我创建了表。我认为“set search_path”会适用于给定的数据库。我可以让它粘住吗? 顺便说一句,为了再次测试,我只是将“set search_path”放在了 sql 脚本的顶部,而不是分别做这两件事......谢谢! 您应该能够在配置文件中设置 search_path 参数,或者通过以下方式将其永久设置为用户: ALTER USER SET search_path = whatever; 您也可以将其设为数据库的默认值:ALTER DATABASE db SET search_path = ...,甚至对于特定的用户/数据库组合(在 9.1 上):ALTER ROLE user IN DATABASE db SET search_path = ...,但如果您过多地使用这些设置,它们可以造成混乱,并注意它们何时被丢弃尚不清楚。

以上是关于search_path 如何影响标识符解析和“当前模式”的主要内容,如果未能解决你的问题,请参考以下文章

PGSQL search_path

PGSQL search_path

PostgreSQL:如何在用户级别设置 search_path? [复制]

postgresql中的search_path

postgresql中的search_path

用JavaScript带你体验V8引擎解析标识符过程