Fügen Sie Text mit einfachen Anführungszeichen in PostgreSQL ein

432

Ich habe einen Tisch test(id,name).

Ich brauche einfügen Werte wie: 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');

Ich erhalte eine Fehlermeldung, wenn ich eine der oben genannten Anweisungen ausführe.

Wenn es eine Methode gibt, um dies richtig zu machen, teilen Sie diese bitte mit. Ich möchte keine vorbereiteten Aussagen.

Ist es möglich, einen SQL-Escape-Mechanismus zu verwenden?

MAHI
quelle
1
Verwenden Sie den Wert, den Ihre Clientbibliothek bietet. Für weitere Informationen müssen Sie angeben, wie Sie auf die Datenbank zugreifen.
Richard Huxton
Auf die @ Richard Huxton-Datenbank wird von Java zugegriffen.
MAHI
2
Verwenden Sie also die Standard-JDBC-Platzhalter. Oder erklären Sie, warum dies nicht die beste Wahl ist.
Richard Huxton
@ Richard Huxton Ich sage nicht, dass dies nicht die beste Wahl ist. Ich suche, ob es eine Fluchtmethode in SQL gibt, um dies zu tun.
MAHI
Nun, siehe @ Claudix 'Antwort unten, aber offensichtlich müssen Werteliterale
Richard Huxton

Antworten:

762

String-Literale

Einfache Anführungszeichen 'durch Verdoppeln zu umgehen -> ''ist die Standardmethode und funktioniert natürlich:

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

In alten Versionen oder wenn Sie immer noch mit standard_conforming_strings = offoder im Allgemeinen, wenn Sie Ihre Zeichenfolge voranstellen, Eum die Posix-Escape-String-Syntax zu deklarieren , können Sie auch mit dem Backslash maskieren \:

E'user\'s log'

Der Backslash selbst wird mit einem weiteren Backslash maskiert. Aber das ist im Allgemeinen nicht vorzuziehen.
Wenn Sie sich mit vielen einfachen Anführungszeichen oder mehreren Escape-Ebenen befassen müssen, können Sie vermeiden, die Hölle in PostgreSQL mit Zeichenfolgen in Dollar-Anführungszeichen zu zitieren :

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

Fügen Sie jedem Paar einen eindeutigen Token hinzu, um Verwechslungen zwischen Dollar-Anführungszeichen zu vermeiden:

$token$escape ' with ''$token$

Welche kann beliebig viele Ebenen verschachtelt werden:

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

Achten Sie darauf, ob der $Charakter in Ihrer Client-Software eine besondere Bedeutung haben soll. Möglicherweise müssen Sie zusätzlich entkommen. Dies ist bei Standard-PostgreSQL-Clients wie psql oder pgAdmin nicht der Fall.

Dies ist alles sehr nützlich, um plpgsql-Funktionen oder Ad-hoc-SQL-Befehle zu schreiben. Es kann jedoch nicht die Notwendigkeit verringern, vorbereitete Anweisungen oder eine andere Methode zum Schutz vor SQL-Injection in Ihrer Anwendung zu verwenden, wenn Benutzereingaben möglich sind. @ Craig's Antwort hat mehr dazu. Mehr Details:

Werte in Postgres

Beim Umgang mit Werten in der Datenbank gibt es einige nützliche Funktionen, um Zeichenfolgen richtig zu zitieren:

  • quote_literal()oderquote_nullable() - Letzteres gibt die Zeichenfolge NULLfür die Null-Eingabe aus. (Es gibt auch quote_ident()zu doppelte Anführungszeichen Strings , wo erforderlich , um gültige SQL zu erhalten Bezeichner .)
  • format()mit dem Formatbezeichner %List äquivalent zu quote_nullable().
    Mögen:format('%L', string_var)
  • concat()oderconcat_ws() sind normalerweise nicht gut, da diese nicht verschachtelten einfachen Anführungszeichen und Backslashes entgehen.
Erwin Brandstetter
quelle
1
Es ist auch erwähnenswert, dass einige PgJDBC-Versionen Probleme mit Dollar-Anführungszeichen haben - insbesondere kann es sein, dass Anweisungs-Terminatoren (;) in Dollar-Anführungszeichen nicht ignoriert werden.
Craig Ringer
1
Diese verwandte Antwort enthält Details zum Problem mit JDBC.
Erwin Brandstetter
1
Und wenn Sie beim Einfügen im Falle einer prozeduralen Sprache usw. aus dem Text aus der Textspalte entkommen möchten, können Sie die Zeichenfolgenfunktion quote_literal (column_name) verwenden.
Alexglue
1
$ token $ ist großartig. Vielen Dank.
Mythicalcoder
@ErwinBrandstetter, re "kann beliebig viele Ebenen verschachtelt werden": SELECT $outer$OUT$inner$INNER$inner$ER$outer$;beweist aber, dass die Verschachtelung der 2. Ebene hier nicht funktioniert.
Filiprem
46

Dies sind so viele schlechte Welten, weil Ihre Frage impliziert, dass Ihre Anwendung wahrscheinlich klaffende SQL-Injection- Lücken aufweist.

Sie sollten parametrisierte Anweisungen verwenden. Verwenden Sie für Java PreparedStatementPlatzhalter . Sie sagen, Sie möchten keine parametrisierten Anweisungen verwenden, aber Sie erklären nicht, warum , und ehrlich gesagt muss es ein sehr guter Grund sein, sie nicht zu verwenden, da sie der einfachste und sicherste Weg sind, das von Ihnen versuchte Problem zu beheben lösen.

Siehe Verhindern der SQL-Injektion in Java . Sei nicht Bobbys nächstes Opfer.

In PgJDBC gibt es keine öffentliche Funktion zum Zitieren und Escapezeichen von Zeichenfolgen. Das liegt zum Teil daran, dass es eine gute Idee sein könnte.

Es gibt integrierte Anführungszeichenfunktionen quote_literalund quote_identPostgreSQL, diese gelten jedoch für PL/PgSQLFunktionen, die verwendet werden EXECUTE. Diese Tage quote_literalwerden meistens von EXECUTE ... USINGder parametrisierten Version überholt , weil sie sicherer und einfacher ist . Sie können sie nicht für den hier erläuterten Zweck verwenden, da es sich um serverseitige Funktionen handelt.


Stellen Sie sich vor, was passiert, wenn Sie den Wert ');DROP SCHEMA public;--von einem böswilligen Benutzer erhalten. Sie würden produzieren:

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

Das besteht aus zwei Aussagen und einem Kommentar, der ignoriert wird:

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

Hoppla, da geht deine Datenbank.

Craig Ringer
quelle
Ich würde eher einer Ausnahme zustimmen - "where" -Klauseln (obwohl er "insert" sagt) mit einer Liste von Werten als Teil einer "in" -Klausel (oder einer Reihe von "oder" s). Ich nehme an, Sie könnten die Größe der Liste zählen und den Text für die vorbereitete Anweisung mit einer "in" -Klausel generieren, aber in diesem Anwendungsfall wird es seltsam.
Roboprog
@Roboprog Mit einigen Client-Treibern können Sie = ANY(?)einen Array-Parameter verwenden.
Craig Ringer
12
Ich habe neben DDL oft solche wörtlichen Einfügungen verwendet, um Daten zu booten. Versuchen wir einfach, Fragen zu beantworten als Antworten wie "Du machst es falsch"
ThatDataGuy
1
@ThatDataGuy fairer Kommentar, aber in dieser Frage fügte das OP einen Kommentar hinzu, der besagt, database is accessed by javadass dies die Frage direkt anspricht . Es ist auch sehr wichtig, dass die Leute, die hierher kommen, auf die potenziellen Gefahren aufmerksam gemacht werden, insbesondere angesichts der Tatsache, dass SQL Injection die häufigste Ursache für Software-Schwachstellen ist. Sobald Sie sich des Problems bewusst sind, können Sie fundierte Entscheidungen treffen, wann es keine Rolle spielt, wie z. B. Ihren Bootstrapping-Anwendungsfall.
Davos
Genau. Die Leute kopieren und fügen auch viel Code ein. Ich werde aufhören, die Leute darüber zu warnen, sobald ich nicht mehr täglich SQL-Injection-Schwachstellen im Produktionscode sehe.
Craig Ringer
26

Gemäß der PostgreSQL-Dokumentation (4.1.2.1. String-Konstanten) :

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

Siehe auch den Parameter standard_conforming_strings , der steuert, ob das Escapezeichen mit Backslashes funktioniert.

Claudix
quelle
danke für die antwort, aber ich muss jedes char manuell damit umgehen, wenn es irgendwelche eingebauten funktionen dafür gibt?
MAHI
3
@MAHI Wenn es eine solche Funktion gäbe, wäre sie in PgJDBC und nicht in PostgreSQL selbst, da das Escape auf der Clientseite erfolgen muss. Es gibt keine solche dokumentierte öffentliche Funktion, weil es eine schreckliche Idee ist. Sie sollten parametrisierte Anweisungen verwenden, damit Sie keine potenziell unzuverlässigen Escape-Aktionen ausführen müssen.
Craig Ringer
13

Wenn Sie in postgresql Werte einfügen möchten, 'müssen Sie dafür extra angeben'

 insert into test values (1,'user''s log');
 insert into test values (2,'''my users''');
 insert into test values (3,'customer''s');
Jäger
quelle
Upvote für das Anzeigen der dreifachen Anführungszeichen, wenn Sie eine Zeichenfolge in Anführungszeichen haben
winkbrace
up, da es eine einfache Lösung ist
ktaria
5

Sie können die Funktion postrgesql chr (int) verwenden:

insert into test values (2,'|| chr(39)||'my users'||chr(39)||');
Slava Struminski
quelle
2

Wenn Sie die Arbeit in Seite erledigen müssen:

to_json(value)

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

Hattenin
quelle
Wie hängt diese Frage mit JSON zusammen?
Erwin Brandstetter
1
@ErwinBrandstetter, sorry, ich könnte aus sein .. aber es entgeht Anführungszeichen in Strings
Hinenine
1
Das ist eine ganz andere Sache. Sie könnten verwenden format(), quote_literal()oder quote_nullable()Anführungszeichen zu entkommen. Siehe: stackoverflow.com/a/25143945/939860
Erwin Brandstetter
0
select concat('''','abc','''')
Rushi The Sharma
quelle
Dies würde erfordern, zunächst user's loganstelle von abcrichtig zu zitieren . Fang 22.
Erwin Brandstetter