如何在DO语句中使用准备好的语句?

时间:2018-11-22 20:13:47

标签: postgresql transactions prepared-statement

我有一个相当复杂的查询,在这里我试图使用准备好的语句来保护数据库免受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

如何在查询中使用准备好的语句?

1 个答案:

答案 0 :(得分:0)

您不能将DO语句用作准备语句。

我建议您使用两个语句:

  • 一个可以获取确定是否存在错误情况所需的三个结果

  • 运行INSERT语句的一个

其中第二个是常规的准备好的语句。

在我看来,您正在混淆PL / pgSQL中的事务和BEGIN ... END块。