Правильное использование модуля Psycopg2 SQL

Отредактировал вопрос из-за синтаксической ошибки, о которой мне сообщил Морис Мейер.

Мне нужно защитить приложение от SQL-инъекции, поэтому используйте модуль sql от Psycopg2. Это генерирует рабочий запрос:

conn = get_db()
cur = conn.cursor()
with open(fp, 'r') as f:
    query = sql.SQL("COPY parts ({fields}) FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)").format(
        fields = sql.SQL(',').join(sql.Identifier(col) for col in cols))
    cur.copy_expert(query, f)

Однако мне интересно, правильное ли это решение. Как сгенерированный запрос:

print(query.as_string(conn))
>>> COPY parts ("asin","name","t_id","supp_pid","acq_price","deposit","ean","m_pid") FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)

Но в соответствии с документами Postgresql идентификаторы не должны заключаться в кавычки. Почему до сих пор работает?

2 ответа

Решение

Скобки закрыты неправильно. Ты используешьformat в строке вместо объекта SQL:

with open(fp, 'r') as f:
    _sql = "COPY parts ({}) FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)"
    query = sql.SQL(_sql).format(
        sql.SQL(',').join(sql.Identifier(col) for col in cols)
    )
    print(query.as_string(conn))
    cur.copy_expert(query, f)

Выход:

COPY parts ("firstname","lastname") FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)
Traceback (most recent call last):
  File "pg2.py", line 14, in <module>
    cur.copy_expert(query, f)
psycopg2.errors.UndefinedTable: relation "parts" does not exist

Примечание относительно цитируемых идентификаторов:

Представьте, что у вас есть имя столбца, содержащее пробелы, а затем вам нужно заключить их в кавычки, чтобы их можно было использовать. Таким образом, можно использовать двойные кавычки, то же самое относится и к консоли postgres.

>>> cur.execute("""select firstname, "desc ription" from users2 where lastname = 'bar'""")
>>> print(cur.fetchone())
RealDictRow([('firstname', 'fo'), ('desc ription', 'baz')])

У вас опечатка:

sql.SQL("xxx".format(...))

вместо того:

sql.SQL("xxx").format(...)
             ^ this (

так:

query = sql.SQL("COPY parts ({fields}) FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)").format(
        fields = sql.SQL(',').join(sql.Identifier(col) for col in cols))
Другие вопросы по тегам