Postgres 函数创建中 $$ double dollars 的语法错误

Syntax error on $$ double dollars in Postgres function creation

我试图在 postgres 实例启动期间创建一个简单的函数。我通过将一些 .sh 文件映射到 /docker-entrypoint-initdb.d 目录来做到这一点。

我一直在用这个简单的函数遇到问题。

#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
    CREATE OR REPLACE FUNCTION hi() RETURNS TEXT AS $$
    BEGIN
        RETURN 'hi'
    END;
    $$;
EOSQL
2020-01-29 05:12:30.817 UTC [62] ERROR:  syntax error at or near "1" at character 49
2020-01-29 05:12:30.817 UTC [62] STATEMENT:  CREATE OR REPLACE FUNCTION hi() RETURNS TEXT AS 1
        BEGIN
            RETURN 'hi'
        END;
ERROR:  syntax error at or near "1"
LINE 1: CREATE OR REPLACE FUNCTION hi() RETURNS TEXT AS 1

如果我把它改成有实际内容的东西:

#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
    CREATE OR REPLACE FUNCTION hi() RETURNS TEXT AS $func$
    BEGIN
        RETURN 'hi'
    END;
    $func$;
EOSQL

我在同一个地方遇到另一个错误:

2020-01-29 05:17:36.161 UTC [62] ERROR:  syntax error at or near "$" at character 49
2020-01-29 05:17:36.161 UTC [62] STATEMENT:  CREATE OR REPLACE FUNCTION hi() RETURNS TEXT AS $
        BEGIN
            RETURN 'hi'
        END;
ERROR:  syntax error at or near "$"
LINE 1: CREATE OR REPLACE FUNCTION hi() RETURNS TEXT AS $

运行最新postgres版本:12.1

这个函数定义到底有什么问题,为什么会出现这个错误?

脚本中从 <<-EOSQLEOSQL 的部分称为 "here document",该功能记录在 the Bash Reference Manual, §3.6.6 "Here Documents" 中。根据该部分:

If any part of word [in your case EOSQL] is quoted, […] the lines in the here-document are not expanded. If word is unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion, […]

换句话说——因为您没有引用 EOSQL 的任何部分,Bash 正在对 here-document 的内容执行参数扩展(和其他类似的替换),其中包括在 PostgreSQL 看到它们之前,将 $$ 替换为进程 ID,并将 $func 替换为空字符串。

如果您只是将 <<-EOSQL 更改为 <<-'EOSQL',它不会那样做。

$func$$bash中的变量。第一个是 shell 实例的进程 ID,它解释了错误输出中的数字;第二个只是一个普通的用户定义变量,大概是空的,所以 $test$ 变成 $ (因为 $test 被一个空字符串替换)。

您可以转义 bash 认为重要的美元符号,使用 $$$test$,或者您可以使用 <<-'EOSQL' 使用单引号(不变量替换)heredoc 上的语义。

None 这与 PostgreSQL 有关,它 bash 做它认为你想做的事。