尝试在Python上编写注入安全的PostgreSQL查询时出现“ Psycopg2.error列不存在”错误

时间:2019-08-22 07:41:07

标签: python postgresql psycopg2

我正在编写一个使用psycopg2库为PostgreSQL数据库动态创建插入/更新/选择查询的功能。

我一直在尝试根据psycopg2 documentation提供的建议编写安全注入函数-使用sql.Sql方法正确地组成查询。所有参数(表名,要插入的列,值)都动态传递给函数:

def insert(table, columns: list, values: list):

    query = sql.SQL('INSERT INTO {} ({}) VALUES ({});').format(
                    sql.Identifier(table),
                    sql.SQL(', ').join(map(sql.Identifier, columns)),
                    sql.SQL(', ').join(map(sql.Identifier, values))
                   )
    cursor = foo_connection.cursor()
    cursor.execute(query)

当我尝试测试该功能时:

insert('test_table', ['col1', 'col2', 'col3'], ['1', '2', '3'])

我收到以下错误:

psycopg2.errors.UndefinedColumn: column "1" does not exist
LINE 1: ...e" ("col1", "col2", "col3") VALUES ("1", "2", ...

我不会取消错误,因为从技术上讲它甚至都不是列,而是要插入的值。

我认为查询的构成不正确,但是print(query.as_string(foo_connection))的结果表明它似乎是正确的:

INSERT INTO "test_table" ("col1", "col2", "col3") VALUES ("1", "2", "3");

官方文档没有涵盖这种情况。谷歌搜索也没有给我答案。

所以,问题是:

  1. 我在这里做什么错了?
  2. 如何使此代码起作用?

3 个答案:

答案 0 :(得分:2)

如Laurenz所说,在psycopg2文档中,它写为:

  

标识符通常代表数据库对象的名称,例如表或字段。

我还看到了Literals对象:

  

表示要包含在查询中的SQL值。

在格式化查询时,也许可以尝试用文字替换标识符:

query = sql.SQL('INSERT INTO {} ({}) VALUES ({});').format(
                sql.Identifier(table),
                sql.SQL(', ').join(map(sql.Identifier, columns)),
                sql.SQL(', ').join(map(sql.Literals, values))
               )

答案 1 :(得分:0)

我认为这是您对查询的引用。也许尝试在外面使用双打:

def insert(table, columns: list, values: list):

    query = sql.SQL("INSERT INTO {} ({}) VALUES ({});").format(
                    sql.Identifier(table),
                    sql.SQL(', ').join(map(sql.Identifier, columns)),
                    sql.SQL(', ').join(map(sql.Literlas, values))
                   )
    cursor = foo_connection.cursor()
    cursor.execute(query)

答案 2 :(得分:0)

问题是您将值常量的格式设置为sql.Identifier

这导致它们用双引号而不是单引号引起来,因此PostgreSQL认为它们是表列。因此出现错误消息。

最好的做法是对文字使用%s占位符,并将它们作为第二个参数传递给execute()