我有一个相当复杂的查询,在这里我试图使用准备好的语句来保护数据库免受SQL注入。实际上,我已将多个查询链接在单个begin-end块下。
此复合查询首先检查是否存在用户会话,然后检查用户是否被禁止,然后用户输入的标签是否有效,最后将帖子插入数据库。
以下是查询:
query = "DO
$$
BEGIN
IF
(select exists(select user_id from sessions where unqid = $1 and user_id = $2))
THEN
IF
(select banned_till from users where unqid = $2) > now()
THEN
RAISE EXCEPTION 'User has been banned!';
ELSE
IF (
Select ( SELECT array_agg(DISTINCT name) FROM allowed_tags) @> $3)
THEN
insert into posts (unqid, title, link, content, user_id, user_nick, user_flair,
tags, tags_details, likes, likes_details)
SELECT $4, $5, $6, $7,
$2, user_nick, user_flair,
$8, $9, 1, $10
from users where unqid = $2;
ELSE
RAISE EXCEPTION 'Fake tags detected!';
END IF;
END IF;
ELSE
RAISE EXCEPTION 'User is not logged in';
END IF;
END
$$;"
DB.exec query,
session_id, session_user, tags_list, unqid, title, link, content,
tags_obj.to_json, tags_details_obj.to_json, likes_obj.to_json
当我使用字符串插值时,此查询工作正常。但是当我尝试使用准备好的语句时,我开始明白了。
bind message supplies 10 parameters, but prepared statement "" requires 0
如何在查询中使用准备好的语句?
答案 0 :(得分:0)
您不能将DO
语句用作准备语句。
我建议您使用两个语句:
一个可以获取确定是否存在错误情况所需的三个结果
运行INSERT
语句的一个
其中第二个是常规的准备好的语句。
在我看来,您正在混淆PL / pgSQL中的事务和BEGIN ... END
块。