Вставте текст з одинарними лапками в PostgreSQL


432

У мене стіл 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?


1
Використовуйте будь-яку цінність, що не відповідає вашій бібліотеці клієнтів. Для отримання додаткової інформації вам доведеться сказати, як ви отримуєте доступ до бази даних.
Річард Хакстон

@Richard Huxton має доступ до бази даних Java.
MAHI

2
Тому використовуйте стандартні заповнювачі jdbc. Або поясніть, чому це не найкращий вибір.
Річард Хакстон

@ Рікхард Хакстон Я не кажу, що це не найкращий вибір, я шукаю, чи існує у них будь-який метод виходу в sql, щоб зробити це.
MAHI

Ну, дивіться відповідь @ Клаудікса нижче, але очевидно, що значення літералам знадобляться по-різному, залежно від їх типу postgresql.org/docs/current/static/datatype.html
Річард Хакстон

Відповіді:


763

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

Уникнення одинарних лапок ', подвоєння їх -> ''- це стандартний спосіб і звичайно:

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

У старих версіях або, якщо ви все ще працюєте з, standard_conforming_strings = offабо, як правило, якщо ви додаєте рядок Eдо оголошення синтаксису рядового рядка 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
І якщо ви хочете уникнути s'tring з текстового стовпця при вставці у випадку процедурної мови і т. Д., Ви можете використовувати функцію string_literal (ім'я колонки).
alexglue

1
$ token $ є приголомшливим. Дякую.
mythicalcoder

@ErwinBrandstetter, повторно "можна вкласти будь-яку кількість рівнів": але SELECT $outer$OUT$inner$INNER$inner$ER$outer$;доводить, що вкладення 2-го рівня тут не працюють.?
filiprem

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;
--');

Ну, там іде ваша база даних.


Я схильний би погодитися з одним винятком - пункти "де" (хоча він каже "вставити") зі списком значень як частини пункту "в" (або купою "або" s). Я припускаю, що ви могли порахувати розмір списку та генерувати текст до підготовленого висловлювання за допомогою "in", але це стає дивним у такому випадку використання.
Робопрог

@Roboprog З деякими клієнтськими драйверами ви можете використовувати = ANY(?)параметр масиву.
Крейг Рінгер

12
Я часто використовував такі буквені вставки для завантаження даних поряд з DDL. Давайте просто спробуємо відповісти на запитання, ніж відповіді на кшталт "ти робиш це неправильно"
ThatDataGuy

1
@ThatDataGuy справедливий коментар, але до цього питання ОП додало коментар, сказавши, що database is accessed by javaце безпосередньо стосується питання. Також людям, які приїжджають сюди, дуже важливо ознайомитись з потенційними небезпеками, особливо, якщо SQL Injection є першою причиною вразливості програмного забезпечення. Ознайомившись з проблемою, люди можуть приймати обгрунтовані рішення щодо того, коли це не має значення, як-от ваш приклад завантаження.
Давос

Саме так. Люди також багато копіюють і вставляють код. Я перестану попереджати людей про це того дня, коли щодня перестаю бачити уразливі місця ін'єкцій SQL у виробничому коді.
Крейг Рінгер

26

Відповідно до документації 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 , який керує тим, чи працює втеча з косою косою рисою.


дякую за відповідь, але мені доведеться вручну вийти з кожного символу, використовуючи це, якщо в них є якісь вбудовані функції для цього?
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');

підняти показ потрійних лапок, якщо у вас є рядки з
цитатами

вгору, оскільки це просте рішення
ktaria


2

Якщо вам потрібно виконати роботу всередині Pg:

to_json(value)

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


Як це питання пов'язане з JSON?
Ервін Брандстеттер

1
@ErwinBrandstetter, вибачте, я можу бути відключений .. але це уникає цитат у рядках
hatenine

1
Це взагалі інша справа. Ви могли б використовувати format(), quote_literal()або quote_nullable()для екранування лапок. Дивіться: stackoverflow.com/a/25143945/939860
Erwin Brandstetter

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.