使用 pgx 在 postgres 中创建用户 (SQLSTATE 42601)
我正在尝试在 postgres 中创建一个用户。目前正在尝试使用 https://github.com/jackc/pgx 作为连接到的驱动程序数据库。我有以下内容
package main
import (
"context"
"fmt"
"os"
"github.com/jackc/pgx/v4"
)
func main() {
ctx := context.Background()
conn, err := pgx.Connect(ctx, "host=localhost port=5432 user=postgres password=postgres dbname=postgres")
if err != nil {
panic(err)
}
defer conn.Close(ctx)
// create user
_, err = conn.Exec(ctx, "CREATE USER $1 WITH PASSWORD $2", "moulick", "testpass")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
但我收到此错误:“$1”处或附近的语法错误(SQLSTATE 42601)
我不明白这里有什么问题?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Postgres 准备好的语句(带有
$1
、$2
等的语句)仅支持 SELECT、INSERT、UPDATE、DELETE、MERGE 或 VALUES 语句(请参阅 PREPARE 文档)。由于问题是关于 CREATE USER 的,我们需要自己构建 SQL 语句,正确地转义不同的部分。用户名是一个标识符(使用
Identifier.Sanitize( )
),密码是一个字符串(使用PgConn.EscapeString()
)。以下程序正确转义这两个部分以创建sql
字符串,然后将其按原样传递给Exec()
。Postgres prepared statements (those with
$1
,$2
, etc.) are supported only for SELECT, INSERT, UPDATE, DELETE, MERGE, or VALUES statements (see documentation of PREPARE).Since the question is about
CREATE USER
, we need to build the SQL statement ourselves, properly escaping the different parts. The username is an identifier (useIdentifier.Sanitize()
), and the password is a string (usePgConn.EscapeString()
). The following program escapes both parts correctly to create thesql
string, which is then passed as-is toExec()
.“我不明白这里有什么问题?” -- 问题是 位置参数只能用于值,不能用于标识符。
您无法在
CREATE USER
中使用位置参数,就像无法在SELECT t. 中使用位置参数一样。 FROM <表名> AS t 。
如果
user_name
不是硬编码的,而是来自未知的用户输入,您需要自己验证它以避免SQL注入的可能性。这不是一项艰巨的任务,因为词汇结构标识符仅限于一小组规则,如果您愿意,您可以进一步将其减少到更小的子集(例如,不允许变音符号和非拉丁字母):"I don't get what's the problem here ?" -- The problem is that positional parameters can be used only for values, and not for identifiers.
You cannot use positional parameters in
CREATE USER <user_name>
the same way you cannot use them inSELECT t.<column_name> FROM <table_name> AS t
.If the
user_name
is not hardcoded, but instead comes from an unknown user input, you need to validate it yourself to avoid the possibility of SQL injections. This is not a difficult task since the lexical structure of identifiers is limited to a small set of rules, which you can further reduce to an even smaller subset if you like (e.g. disallowing diacritical marks and non-Latin letters):