Вставить текст с одинарными кавычками в PostgreSQL

433

У меня есть стол test(id,name).

Мне нужно вставить значения , как: user's log, 'my user', customer's.

 insert into test values (1,'user's log');
 insert into test values (2,''my users'');
 insert into test values (3,'customer's');

Я получаю сообщение об ошибке, если я запускаю любое из приведенных выше утверждений.

Если есть какой-либо способ сделать это правильно, пожалуйста, поделитесь. Я не хочу никаких готовых заявлений.

Возможно ли использовать sql escape-механизм?

MAHI
источник
1
Используйте любое значение, выходящее за пределы вашей клиентской библиотеки. Для получения дополнительной информации вам нужно будет указать способ доступа к базе данных.
Ричард Хэкстон,
Доступ к базе данных @Richard Huxton осуществляется через Java.
MAHI
2
Поэтому используйте стандартные заполнители jdbc. Или объясните, почему это не лучший выбор.
Ричард Хэкстон,
@Richard Huxton Я не говорю, что это не лучший выбор, я ищу, существует ли для этого какой-либо способ экранирования в SQL.
MAHI
Хорошо, см. Ответ @ Claudix ниже, но очевидно, что литералам-значениям нужно будет экранировать по-разному в зависимости от их типа postgresql.org/docs/current/static/datatype.html
Ричард Хакстон,

Ответы:

765

Строковые литералы

Избавление от одинарных кавычек 'путем их удвоения -> ''это стандартный способ, который работает, конечно:

'user's log'     -- incorrect syntax (unbalanced quote)
'user''s log'

В старых версиях или если вы все еще работаете с standard_conforming_strings = offили, как правило, если вы добавляете строку Eк объявлению синтаксиса escape-строки Posix , вы также можете использовать обратную косую черту \:

E'user\'s log'

Сама обратная косая черта экранируется другой обратной косой чертой. Но это вообще не желательно.
Если вам приходится иметь дело со множеством одинарных кавычек или несколькими уровнями экранирования, вы можете избежать использования кавычек в PostgreSQL с помощью строк в кавычках :

'escape '' with '''''
$$escape ' with ''$$

Чтобы избежать путаницы в кавычках, добавьте уникальный токен к каждой паре:

$token$escape ' with ''$token$

Который может быть вложен в любое количество уровней:

$token2$Inner string: $token1$escape ' with ''$token1$ is nested$token2$

Обратите внимание, должен ли $персонаж иметь особое значение в вашей клиентской программе. Возможно, вам придется избежать этого в дополнение. Это не относится к стандартным клиентам PostgreSQL, таким как psql или pgAdmin.

Это все очень полезно для написания функций plpgsql или специальных команд SQL. Тем не менее, это не может облегчить необходимость использования подготовленных операторов или какого-либо другого метода для защиты от внедрения SQL в ваше приложение, когда возможен ввод данных пользователем. Ответ @ Крейга имеет больше об этом. Больше деталей:

Значения внутри Postgres

При работе со значениями в базе данных есть пара полезных функций для правильного цитирования строк:

  • quote_literal()илиquote_nullable() - последний выводит строку NULLдля нулевого ввода. (Также есть quote_ident()возможность заключить строки в двойные кавычки, где необходимо получить действительные идентификаторы SQL .)
  • format()с указателем формата %Lэквивалентно quote_nullable().
    Подобно:format('%L', string_var)
  • concat()или,concat_ws() как правило, бесполезны, так как те не избегают вложенных одинарных кавычек и обратной косой черты.
Эрвин Брандштеттер
источник
1
Стоит также отметить, что в некоторых версиях PgJDBC есть проблемы с кавычками в долларах - в частности, он может не игнорировать оператор-терминатор (;) внутри строк в кавычках.
Крейг Рингер
1
Этот связанный ответ содержит детали для проблемы с JDBC.
Эрвин Брандштеттер
1
И если вы хотите убрать строку из текстового столбца при вставке в случае процедурного языка и т. Д., То вы можете использовать строковую функцию quote_literal (column_name).
alexglue
1
$ token $ - это круто. Спасибо.
Мифический
@ErwinBrandstetter, re «может быть вложен в любое количество уровней»: но SELECT $outer$OUT$inner$INNER$inner$ER$outer$;доказывает, что вложение 2-го уровня здесь не работает.
филипрем
46

Это очень много плохих миров, потому что ваш вопрос подразумевает, что у вас, вероятно, есть пробелы в SQL-инъекциях в вашем приложении.

Вы должны использовать параметризованные операторы. Для Java используйте PreparedStatementс заполнителями . Вы говорите, что не хотите использовать параметризованные операторы, но не объясняете почему , и, честно говоря, это должно быть очень веской причиной, чтобы не использовать их, потому что это самый простой и безопасный способ решения проблемы, которую вы пытаетесь решить. решать.

См. Предотвращение внедрения SQL в Java . Не будь следующей жертвой Бобби .

В PgJDBC нет публичной функции для цитирования строк и экранирования. Это отчасти потому, что это может показаться хорошей идеей.

Есть и встроенные функции цитирования quote_literalи quote_identв PostgreSQL, но они предназначены для PL/PgSQLфункций, которые используют EXECUTE. Эти дни quote_literalв основном устарели EXECUTE ... USING, что является параметризованной версией , потому что это безопаснее и проще . Вы не можете использовать их для целей, которые вы здесь объясняете, потому что они являются функциями на стороне сервера.


Представьте, что произойдет, если вы получите значение ');DROP SCHEMA public;--от злонамеренного пользователя. Вы бы произвели:

insert into test values (1,'');DROP SCHEMA public;--');

который разбивается на два утверждения и комментарий, который игнорируется:

insert into test values (1,'');
DROP SCHEMA public;
--');

Упс, там идет ваша база данных.

Крейг Рингер
источник
Я бы предпочел согласиться с одним исключением - предложения «где» (хотя он говорит «вставить») со списком значений как часть предложения «в» (или группы «или»). Я полагаю, что вы можете посчитать размер списка и сгенерировать текст для подготовленного оператора с предложением «in», но в этом случае это становится странным.
Roboprog
@Roboprog С некоторыми клиентскими драйверами вы можете использовать = ANY(?)и параметр массива.
Крейг Рингер,
12
Я часто использовал такие буквенные вставки для загрузки данных вместе с DDL. Давайте просто попробуем ответить на вопросы, а не на такие, как «ты делаешь это неправильно»
ThatDataGuy
1
@ThatDataGuy честный комментарий, но в этом вопросе ОП добавил комментарий, сказав, database is accessed by javaчто это напрямую решает вопрос. Для людей, приезжающих сюда, также очень важно знать о потенциальных опасностях, особенно учитывая, что SQL-инъекция является # 1 причиной уязвимости программного обеспечения. Узнав о проблеме, люди могут принимать обоснованные решения относительно того, когда это не имеет значения, например, ваш вариант начальной загрузки.
Давос,
Точно. Люди также много копируют и вставляют код. Я перестану предупреждать людей об этом в тот день, когда перестану ежедневно видеть уязвимости SQL-инъекций в производственном коде.
Крейг Рингер
27

Согласно документации PostgreSQL (4.1.2.1. Строковые константы) :

 To include a single-quote character within a string constant, write two 
 adjacent single quotes, e.g. 'Dianne''s horse'.

См. Также параметр standard_conforming_strings , который определяет, работает ли экранирование с обратной косой чертой.

Claudix
источник
спасибо за ответ, но я должен вручную экранировать каждый символ с помощью этого, если они существуют какие-либо встроенные функции для этого?
MAHI
3
@MAHI Если бы была такая функция, она была бы в PgJDBC, а не в самом PostgreSQL, потому что экранирование должно выполняться на стороне клиента. Нет такой документированной публичной функции, потому что это ужасная идея. Вы должны использовать параметризованные операторы, поэтому вам не нужно делать какие-либо потенциально ненадежные экранированные символы.
Крейг Рингер,
13

В postgresql, если вы хотите вставить 'в него значения, то для этого вы должны дать дополнительные'

 insert into test values (1,'user''s log');
 insert into test values (2,'''my users''');
 insert into test values (3,'customer''s');
охотник
источник
upvote для показа тройных кавычек, если у вас есть строка в кавычках
winkbrace
вверх, как это простое решение
ktaria
5

Вы можете использовать функцию postrgesql chr (int):

insert into test values (2,'|| chr(39)||'my users'||chr(39)||');
Слава Струмински
источник
2

Если вам нужно выполнить работу внутри Pg:

to_json(value)

https://www.postgresql.org/docs/9.3/static/functions-json.html#FUNCTIONS-JSON-TABLE

hatenine
источник
Как этот вопрос связан с JSON?
Эрвин Брандштеттер
1
@ErwinBrandstetter, извините, я могу быть выключен ... но он избегает кавычек в строках
hatenine
1
Это совсем другое дело. Вы могли бы использовать format(), quote_literal()или quote_nullable()для экранирования кавычек. См .: stackoverflow.com/a/25143945/939860
Эрвин Брандштеттер
0
select concat('''','abc','''')
Руши Шарма
источник
Это потребует, чтобы процитировать user's logвместо abcправильно для начала. Поймай 22
Эрвин Брандстеттер