空运行 psql 脚本

空运行 psql 脚本

sql脚本文件可能(通常)包含sql-特定指令,包括在客户端解析的变量替换。我正在寻找一种获取 SQL 命令序列的通用方法,因为它们将通过以下方式发送到 PostgreSQL 服务器:sql,在所有客户端处理完成后。此外,这应该可以离线使用。因此,涉及套接字嗅探实时运行或使用回滚事务的解决方案被排除在外。有人知道可以实现这一目标的方法吗?

编辑:因为sql条件元命令 ( \if, ...) 可以依赖于先前 SQL 语句的评估结果,我知道不可能在所有情况下都有完整的解析(这可能就是为什么sql不提供试运行选项)。这个问题的有效解决方案仍然可以简单地忽略sql不过,是有条件的。

答案1

此 Bash 脚本扩展sql\包括\我) 和\include_relative\ir)元命令就地并输出单个已解析流标准输出。当我发布它时,我发现了一些可以改进的地方(主要是合并两个read -r line指令),但该脚本仍然可以正常工作(据我测试):

#!/bin/bash

incl='*([[:space:]])\\@(include?(_relative)|i?(r))+([[:space:]])*'

# Recursively process single \include (\i) or \include_relative (\ir) meta-command
process() {
    # If current line is an '\include' ('\i') or '\include_relative' ('\ir') meta-command, substitute with file contents
    if [[ "$1" == $incl ]]; then
        # Read included file's name
        filename="$(echo "$1" | awk '{print $2}')"
        # Read included file's contents and process each line recursively
        while IFS= read -r line; do
            process "$line"
        done < "$filename"
    # Else, echo the line
    else
        echo "$1"
    fi
}

# Output usage information with '--help' or '-h' switch
if [[ ' --help -h ' =~ " $1 " ]]; then
    echo "USAGE: pg_psqlexpand [workdir] [-h|--help]"
    echo
    echo "Expands in place `\include' (`\i') and `\include_relative' (`\ir') meta-commands in psql scripts."
    echo
    echo "Connect pipe or use redirection for I/O."
    echo "Paths are resolved relative to `workdir' (defaults to current working directory)."
    exit 0
else
    # If working directory is specified, cd into it (defaults to '.')
    cd "${1:-.}"
    while read -r line; do
        process "$line"
    done
fi

这允许将复杂的多文件脚本合并到单个文件中以供检查。它还允许将此类脚本就地传送到sql运行为postgres来自以下位置的超级用户postgres无权访问(通常是调用者主目录中的位置):

## Merge into single file
$ pg_psqlexpand < entry_point.psql > merged.psql

## Pipe to psql running as postgres
$ pg_psqlexpand < entry_point.psql | sudo -iu postgres psql

到目前为止,我已经使用上面的脚本近一周了,并且运行良好。我遇到的唯一缺点是有关文件名和行号的调试信息在此过程中丢失。作为解决方法,我将这些元命令添加到我的sql入口点,为我提供了足够的信息来进行调试,没有太大困难:

-- Error handling
\set VERBOSITY verbose
\set SHOW_CONTEXT errors
\set ON_ERROR_STOP on

应该注意的是,该脚本不支持语法,因此将替换任何可能出现在字符串或双引号文字标识符内的类似包含的子字符串。

相关内容