python добавляет E в строку

Эта строка:

"CREATE USER %s PASSWORD %s", (user, pw)

всегда расширяется до:

CREATE USER E'someuser' PASSWORD E'somepassword'

Кто-нибудь может сказать мне, почему?

Изменить: расширенная строка выше — это строка, которую моя база данных возвращает мне в сообщении об ошибке. Я использую psycopg2 для доступа к моей базе данных postgres. Реальный код выглядит так:

conn=psycopg2.connect(user=adminuser, password=adminpass, host=host)
cur = conn.cursor()

#user and pw are simple standard python strings the function gets as parameter
cur.execute("CREATE USER %s PASSWORD %s", (user, pw))
conn.commit()

person Kai    schedule 01.08.2010    source источник
comment
Можете ли вы дать полный код с объявлениями пользователя и pw?   -  person Tomasz Wysocki    schedule 01.08.2010
comment
Это должно быть вызвано поведением функции __str__ типа user и pw.   -  person Philipp    schedule 01.08.2010
comment
Это запятая после строкового литерала? Если это так, выражение является просто вложенным кортежем, и ничего не расширяется. Пожалуйста, покажите реальный код.   -  person Philipp    schedule 01.08.2010


Ответы (4)


Не только E, но и кавычки, по-видимому, исходят из любого типа, который есть у пользователя и pw. %s просто делает то, что делает str(), что может вернуться к repr(), оба из которых имеют соответствующие методы __str__ и __repr__. Кроме того, это не тот код, который генерирует ваш результат (я предполагал, что это %, но теперь вижу только запятую). Пожалуйста, дополните свой вопрос фактическим кодом, типами и значениями.

Приложение: учитывая, что это похоже на SQL, рискну предположить, что вы видите экранирующие строковые константы, вероятно, должным образом сгенерированные вашим интерфейсным модулем базы данных или библиотекой.

person Yann Vernier    schedule 01.08.2010
comment
Ты прав. Я использую Psycopg2, и это строка, которую моя база данных возвращает мне как ошибку. Я собираюсь поставить фактический код в вопрос сейчас. - person Kai; 01.08.2010
comment
Может показаться, что проблема в том, что %s используется для полей данных, а имя пользователя в CREATE USER выглядит как идентификатор, поэтому строковый литерал здесь не работает. Похоже, Psycopg2 не имеет функций проверки или цитирования таких идентификаторов. - person Yann Vernier; 01.08.2010
comment
comment
@Yann Это обсуждение переместилось на http://osdir.com/ml/python-db-psycopg-devel/2009-03/msg00011.html, так как ... - person ᴠɪɴᴄᴇɴᴛ; 02.09.2014

Для передачи идентификаторов в postgresql через psycopg используйте AsIs из модуля extensions

from psycopg2.extensions import AsIs
import psycopg2
connection = psycopg2.connect(database='db', user='user')
cur = connection.cursor()
cur.mogrify(
    'CREATE USER %s PASSWORD %s', (AsIs('someuser'), AsIs('somepassword'))
    )
'CREATE USER someuser PASSWORD somepassword'

Это также работает для передачи условий в такие предложения, как order by:

cur.mogrify(
    'select * from t order by %s', (AsIs('some_column, another column desc'),)
    )
'select * from t order by some_column, another column desc'
person Clodoaldo Neto    schedule 15.12.2012
comment
Жаль, что это противоречит точке параметризации запроса: >>> cursor.mogrify('CREATE USER %s PASSWORD %s', (AsIs('someuser'), AsIs('somepassword; drop table users;'))) 'CREATE USER someuser PASSWORD somepassword; drop table users;' Это должно быть подтверждено чем-то вроде: 'input_table'.replace('_', '').isalnum(). (Осторожно, не проверено.) - person Michał Pawłowski; 28.12.2015
comment
@MichałPawłowski: Да, AsIs не следует использовать для данных, вводимых пользователем. И использование любого непроверенного решения, такого как ваше, — это прямой путь к катастрофе. - person Clodoaldo Neto; 28.12.2015

Поскольку редактирование OP показывает, что он использует PostgreSQL, документы для него актуальны, и говорят:

Postgres Pro также поддерживает строковые константы escape, являющиеся расширением стандарта SQL. Константа управляющей строки указывается путем написания буквы E (верхний или нижний регистр) непосредственно перед открывающей одинарной кавычкой, например. Э'фу'.

Другими словами, psycopg правильно генерирует константы управляющих строк для ваших строк (так что, как говорится в документации:

В escape-строке символ обратной косой черты () начинает управляющую последовательность обратной косой черты в стиле C, в которой комбинация обратной косой черты и следующих за ней символов представляет собой специальное значение байта.

(которые, как это бывает, также являются соглашениями об уходе не-сырых строковых литералов Python).

Ошибка ОП явно не имеет к этому никакого отношения, и, помимо отличной идеи изучения отличной документации PostgreSQL, в данном случае ему не следует беспокоиться об этой форме E'...' ;-).

person Alex Martelli    schedule 01.08.2010
comment
Я только что прочитал это сам. Итак, строка верна, но почему мой сервер postgres возвращает ее мне с синтаксической ошибкой на букве E? - person Kai; 01.08.2010
comment
@ Кай, может быть, ты используешь устаревшую версию PgSQL? Или, возможно, комментарии @Yann к другому ответу верны, и вам нужен идентификатор, не вообще строка в кавычках, в CREATE USER (в этом случае вам придется вставить его с помощью строковых манипуляций перед execute, чтобы избежать экранирования -- не забудьте проверить это очень тщательно на предмет SQL-инъекций, конечно же!!!-). - person Alex Martelli; 01.08.2010
comment
Похоже, комментарий Янна правильный. Мне это не нравится, но на данный момент мне не нужно обрабатывать пользовательские значения в этих операторах. Поэтому я просто буду использовать стандартные манипуляции со строками Python. И все же мне это не нравится ;) - person Kai; 01.08.2010

Прежде чем пытаться что-то вроде:

statement = "CREATE USER %s PASSWORD %s" % (user, pw)

Обязательно прочтите: http://www.initd.org/psycopg/docs/usage.html

В основном проблема заключается в том, что если вы принимаете пользовательский ввод (я предполагаю, что кто-то вводит пользователя и pw), вы, вероятно, оставляете себя открытым для SQL-инъекций.

Как утверждает PsyCopg2:

Warning Never, never, NEVER use Python string concatenation (+) or string parameters interpolation (%) to pass variables to a SQL query string. Not even at gunpoint.

Как было установлено, Postgres (или Psycopg2), похоже, не дает хорошего ответа на экранирование идентификаторов. На мой взгляд, лучший способ решить эту проблему — предоставить метод фильтрации «белого списка».

т. е.: Определите, какие символы разрешены в «user» и «pw». (возможно, A-Za-z0-9_). Будьте осторожны, чтобы не включать escape-символы (' или ; и т. д.), или, если вы их включаете, избегайте этих значений.

person Richard G    schedule 01.06.2011
comment
Postgres имеет функцию quote_ident() для цитирования идентификаторов postgresql.org/docs/current/static/ - person raphael; 19.08.2016