Wstaw tekst z pojedynczymi cudzysłowami w PostgreSQL

432

Mam tabeli test(id,name).

Muszę wstawić wartości jak: 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');

Otrzymuję błąd, jeśli uruchomię dowolną z powyższych instrukcji.

Jeśli istnieje jakakolwiek metoda, aby to zrobić poprawnie, udostępnij. Nie chcę żadnych przygotowanych oświadczeń.

Czy jest to możliwe przy użyciu mechanizmu ucieczki SQL?

MAHI
źródło
1
Użyj dowolnej wartości, która ucieka od biblioteki klienta. Aby uzyskać więcej informacji, musisz powiedzieć, w jaki sposób uzyskujesz dostęp do bazy danych.
Richard Huxton,
Dostęp do bazy danych @Richard Huxton uzyskuje java.
MAHI
2
Więc użyj standardowych symboli zastępczych jdbc. Lub wyjaśnij, dlaczego nie jest to najlepszy wybór.
Richard Huxton,
@Richard Huxton Nie mówię, że nie jest to najlepszy wybór, szukam, czy istnieje jakaś metoda ucieczki w SQL, aby to zrobić.
MAHI
Cóż, patrz odpowiedź @ Claudix poniżej, ale oczywiście literały wartości będą wymagały różnych
znaków zmiany

Odpowiedzi:

763

Literały łańcuchowe

Unikanie pojedynczych cytatów 'poprzez ich podwojenie -> ''jest standardowym sposobem i działa oczywiście:

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

W starych wersjach lub jeśli nadal działasz z standard_conforming_strings = offlub, generalnie, jeśli poprzedzasz swój ciąg znaków, Eaby zadeklarować składnię łańcucha ucieczki Posix , możesz również uciec za pomocą odwrotnego ukośnika \:

E'user\'s log'

Sam odwrotny ukośnik jest poprzedzany innym odwrotnym ukośnikiem. Ale generalnie nie jest to preferowane.
Jeśli masz do czynienia z wieloma pojedynczymi cudzysłowami lub wieloma warstwami ucieczki, możesz uniknąć cytowania piekła w PostgreSQL za pomocą ciągów cytowanych w dolarach :

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

Aby dodatkowo uniknąć pomyłek w notowaniach dolara, dodaj unikalny token do każdej pary:

$token$escape ' with ''$token$

Które mogą być zagnieżdżone na dowolnej liczbie poziomów:

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

Zwróć uwagę, jeśli $ postać powinna mieć specjalne znaczenie w oprogramowaniu klienckim. Dodatkowo może być konieczne ucieczka. Nie dotyczy to standardowych klientów PostgreSQL, takich jak psql lub pgAdmin.

Wszystko to jest bardzo przydatne do pisania funkcji plpgsql lub ad-hoc poleceń SQL. Nie może jednak zmniejszyć potrzeby użycia przygotowanych instrukcji lub innej metody w celu zabezpieczenia przed wstrzyknięciem SQL w aplikacji, gdy możliwe jest wprowadzanie danych przez użytkownika. Odpowiedź @ Craiga zawiera więcej informacji na ten temat. Więcej szczegółów:

Wartości w Postgres

Gdy mamy do czynienia z wartościami w bazie danych, istnieje kilka przydatnych funkcji do prawidłowego cytowania ciągów:

  • quote_literal()lubquote_nullable() - ta ostatnia wyprowadza ciąg znaków NULLdla wejścia zerowego. (Jest też quote_ident()do podwójnego cytując strun gdzie potrzebne do uzyskania prawidłowych SQL identyfikatory ).
  • format()ze specyfikatorem formatu %Lodpowiada quote_nullable().
    Lubić:format('%L', string_var)
  • concat()lubconcat_ws() zazwyczaj nie są dobre, ponieważ nie unikają zagnieżdżonych pojedynczych cudzysłowów i odwrotnych ukośników.
Erwin Brandstetter
źródło
1
Warto również zauważyć, że niektóre wersje PgJDBC mają problemy z kwotowaniem dolara - w szczególności może nie ignorować terminatorów instrukcji (;) w ciągach kwotowanych w dolarach.
Craig Ringer
1
Ta pokrewna odpowiedź zawiera szczegółowe informacje na temat problemu z JDBC.
Erwin Brandstetter,
1
A jeśli chcesz wstawić s'tring z kolumny tekstowej podczas wstawiania w przypadku języka proceduralnego itp., Możesz użyć funkcji łańcuchowej quote_literal (nazwa_kolumny).
alexglue,
1
$ token $ jest niesamowity. Dzięki.
mityczny
@ErwinBrandstetter, re „można zagnieżdżać dowolną liczbę poziomów”: ale SELECT $outer$OUT$inner$INNER$inner$ER$outer$;dowodzi, że zagnieżdżanie drugiego poziomu nie działa tutaj.
filiprem,
46

Jest tak wiele złych światów, ponieważ twoje pytanie sugeruje, że prawdopodobnie masz luki w aplikacjach SQL .

Powinieneś używać sparametryzowanych instrukcji. W przypadku języka Java należy używać PreparedStatementsymboli zastępczych . Mówisz, że nie chcesz używać sparametryzowanych instrukcji, ale nie wyjaśniasz dlaczego , i szczerze mówiąc, musi to być bardzo dobry powód, aby ich nie używać, ponieważ są one najprostszym i najbezpieczniejszym sposobem rozwiązania problemu, który próbujesz rozwiązać rozwiązać.

Zobacz Zapobieganie wstrzykiwaniu SQL w Javie . Nie bądź Bobby kolejną ofiarą .

W PgJDBC nie ma funkcji publicznej do cytowania ciągów i zmiany znaczenia. Po części dlatego, że może to wydawać się dobrym pomysłem.

Tam wbudowane w cytując funkcje quote_literali quote_identw PostgreSQL, ale są za PL/PgSQLjego pomocą funkcji EXECUTE. Te dni quote_literalsą w większości przestarzałe EXECUTE ... USING, ponieważ jest to sparametryzowana wersja , ponieważ jest bezpieczniejsza i łatwiejsza . Nie możesz ich użyć do celów, które tu wyjaśnisz, ponieważ są to funkcje po stronie serwera.


Wyobraź sobie, co się stanie, jeśli otrzymasz wartość ');DROP SCHEMA public;--od złośliwego użytkownika. Wyprodukowalibyście:

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

który dzieli się na dwie instrukcje i komentarz, który jest ignorowany:

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

Ups, tam idzie twoja baza danych.

Craig Ringer
źródło
Chciałbym się zgodzić z jednym wyjątkiem - klauzulami „gdzie” (chociaż mówi „wstaw”) z listą wartości jako części klauzuli „in” (lub wiązki „lub”). Podejrzewam, że można policzyć rozmiar listy i wygenerować tekst do przygotowanej instrukcji z klauzulą ​​„in”, ale w tym przypadku użycia jest to dziwne.
Roboprog
@Roboprog Z niektórymi sterownikami klienta możesz użyć = ANY(?)i parametr tablicy.
Craig Ringer
12
Często używałem takich dosłownych wstawek do ładowania danych, oprócz DDL. Spróbujmy po prostu odpowiedzieć na pytania niż odpowiedzi typu „robisz to źle”
ThatDataGuy
1
@ThatDataGuy uczciwy komentarz, ale w tym pytaniu OP dodał komentarz mówiący, database is accessed by javawięc to bezpośrednio odnosi się do pytania. Bardzo ważne jest również, aby ludzie przybywający tutaj byli świadomi potencjalnych zagrożeń, szczególnie biorąc pod uwagę, że SQL Injection jest najczęstszą przyczyną podatności oprogramowania. Po zapoznaniu się z problemem ludzie mogą podejmować świadome decyzje, kiedy nie ma to znaczenia, na przykład przypadek użycia ładowania początkowego.
Davos
Dokładnie. Ludzie również często kopiują i wklejają kod. Przestanę ostrzegać ludzi o tym w dniu, w którym przestanę widzieć luki w zabezpieczeniach związane z iniekcją SQL w kodzie produkcyjnym.
Craig Ringer
26

Zgodnie z dokumentacją PostgreSQL (4.1.2.1. Stałe łańcuchowe) :

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

Zobacz także parametr standard_conforming_strings , który kontroluje, czy działa ucieczka z ukośnikami odwrotnymi.

Claudix
źródło
dziękuję za odpowiedź, ale muszę ręcznie uciec każdego znaku za pomocą tego, jeśli istnieją jakieś wbudowane funkcje do tego?
MAHI
3
@MAHI Gdyby istniała taka funkcja, byłaby w PgJDBC, a nie w PostgreSQL, ponieważ ucieczka musi być wykonana po stronie klienta. Nie ma takiej udokumentowanej funkcji publicznej, ponieważ jest to okropny pomysł. Powinieneś używać sparametryzowanych instrukcji, abyś nie musiał wykonywać żadnych potencjalnie zawodnych ucieczek.
Craig Ringer
13

W postgresql, jeśli chcesz wstawić wartości z 'nim, to musisz podać dodatkowe'

 insert into test values (1,'user''s log');
 insert into test values (2,'''my users''');
 insert into test values (3,'customer''s');
Łowca
źródło
głosowanie za wyświetleniem potrójnych cytatów, jeśli masz cytowany ciąg
winkbrace
, ponieważ jest to proste rozwiązanie
ktaria
5

możesz użyć funkcji chr (int) postrgesql:

insert into test values (2,'|| chr(39)||'my users'||chr(39)||');
Slava Struminski
źródło
2

Jeśli musisz wykonać pracę w Pg:

to_json(value)

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

hatenina
źródło
Jak to pytanie ma związek z JSON?
Erwin Brandstetter,
1
@ErwinBrandstetter, przepraszam, mogę być wyłączony .. ale ucieka cytaty w ciągach
hatenine
1
To zupełnie inna sprawa. Można użyć format(), quote_literal()lub quote_nullable()do ucieczki cytaty. Zobacz: stackoverflow.com/a/25143945/939860
Erwin Brandstetter
0
select concat('''','abc','''')
Rushi The Sharma
źródło
Wymagałoby to zacytowania user's logzamiast abcprawidłowego podania . Catch 22.
Erwin Brandstetter