Inserisci testo con virgolette singole in PostgreSQL


433

Ho un tavolo test(id,name).

Ho bisogno di inserire i valori come: 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');

Ricevo un errore se eseguo una delle dichiarazioni sopra.

Se esiste un metodo per farlo correttamente, si prega di condividere. Non voglio dichiarazioni preparate.

È possibile utilizzare il meccanismo di escape sql?


1
Utilizzare qualsiasi valore fornito dalla libreria client. Per ulteriori informazioni dovrai dire come stai accedendo al database.
Richard Huxton,

Il database @Richard Huxton è accessibile da java.
MAHI,

2
Quindi usa i segnaposto jdbc standard. Oppure spiega perché non è la scelta migliore.
Richard Huxton,

@Richard Huxton non sto dicendo che non sia la scelta migliore, sto cercando se esiste un metodo di escape in sql per farlo.
MAHI,

Bene, vedi la risposta di @ Claudix di seguito, ma ovviamente i letterali di valore avranno bisogno di una fuga diversa a seconda del loro tipo postgresql.org/docs/current/static/datatype.html
Richard Huxton

Risposte:


764

Letterali a corda

Sfuggire alle virgolette singole 'raddoppiandole -> ''è il modo standard e funziona ovviamente:

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

Nelle versioni precedenti o se si esegue ancora con standard_conforming_strings = offo, in genere, se si antepone la stringa Eper dichiarare la sintassi della stringa di escape Posix , è possibile anche eseguire la escape con la barra rovesciata \:

E'user\'s log'

La stessa barra rovesciata viene salvata con un'altra barra rovesciata. Ma questo non è generalmente preferibile.
Se devi affrontare molte virgolette singole o più livelli di escape, puoi evitare di citare l'inferno in PostgreSQL con stringhe tra virgolette :

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

Per evitare ulteriore confusione tra le virgolette, aggiungi un token univoco a ciascuna coppia:

$token$escape ' with ''$token$

Che può essere nidificato in qualsiasi numero di livelli:

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

Fai attenzione se il $personaggio deve avere un significato speciale nel tuo software client. Potrebbe essere necessario scappare in aggiunta. Questo non è il caso dei client PostgreSQL standard come psql o pgAdmin.

Ciò è molto utile per scrivere funzioni plpgsql o comandi SQL ad hoc. Tuttavia, non può alleviare la necessità di utilizzare istruzioni preparate o altri metodi per salvaguardare dall'iniezione SQL nell'applicazione quando è possibile l'input dell'utente. La risposta di @ Craig ha di più su questo. Più dettagli:

Valori all'interno di Postgres

Quando si hanno a che fare con valori all'interno del database, ci sono un paio di utili funzioni per citare correttamente le stringhe:

  • quote_literal()oppurequote_nullable() - quest'ultimo genera la stringa NULLper input null. (È inoltre necessario quote_ident()fare una virgoletta doppia tra parentesi quando necessario per ottenere identificatori SQL validi .)
  • format()con l'identificatore di formato %Lequivale a quote_nullable().
    Piace:format('%L', string_var)
  • concat()o inconcat_ws() genere non vanno bene perché non sfuggono alle virgolette singole singole e alle barre rovesciate.

1
Vale anche la pena notare che alcune versioni di PgJDBC hanno problemi con le quotazioni in dollari - in particolare, potrebbe non ignorare i terminatori di istruzioni (;) all'interno di stringhe tra virgolette.
Craig Ringer,

1
Questa risposta correlata contiene dettagli per il problema con JDBC.
Erwin Brandstetter,

1
E se vuoi scappare s'tring dalla colonna di testo durante l'inserimento in caso di linguaggio procedurale ecc., Puoi usare la funzione stringa quote_literal (nome_colonna).
alexglue,

1
$ token $ è fantastico. Grazie.
miticalcoder

@ErwinBrandstetter, re "può essere nidificato qualsiasi numero di livelli": ma SELECT $outer$OUT$inner$INNER$inner$ER$outer$;dimostra che l'annidamento di 2 ° livello non funziona qui.
filiprem,

46

Si tratta di così tanti mondi negativi, perché la tua domanda implica che probabilmente hai buchi di iniezione SQL spalancati nella tua applicazione.

Dovresti usare istruzioni con parametri. Per Java, utilizzare PreparedStatementcon segnaposto . Dici di non voler usare le istruzioni parametrizzate, ma non spieghi il perché , e francamente deve essere un'ottima ragione per non usarle perché sono il modo più semplice e sicuro per risolvere il problema che stai provando risolvere.

Vedere Prevenzione dell'iniezione SQL in Java . Non essere la prossima vittima di Bobby .

Non esiste alcuna funzione pubblica in PgJDBC per la quotazione e l'escape di stringhe. Questo in parte perché potrebbe far sembrare una buona idea.

Ci sono funzioni di quotazione integrate quote_literale quote_identin PostgreSQL, ma sono per le PL/PgSQLfunzioni che usano EXECUTE. In questi giorni quote_literalè per lo più obsoleto EXECUTE ... USING, che è la versione con parametri , perché è più sicuro e più facile . Non puoi usarli per lo scopo che spieghi qui, perché sono funzioni lato server.


Immagina cosa succede se ottieni il valore ');DROP SCHEMA public;--da un utente malintenzionato. Produresti:

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

che si suddivide in due affermazioni e un commento che viene ignorato:

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

Spiacenti, ecco il tuo database.


Tenderei a concordare con un'eccezione: le clausole "where" (anche se dice "inserire") con un elenco di valori come parte di una clausola "in" (o un insieme di "o" s). Suppongo che potresti contare le dimensioni dell'elenco e generare il testo nell'istruzione preparata con una clausola "in", ma diventa strano in quel caso d'uso.
Roboprog,

@Roboprog Con alcuni driver client è possibile utilizzare = ANY(?)e un parametro array.
Craig Ringer,

12
Ho spesso usato inserti letterali come questo per avviare i dati, insieme a DDL. Proviamo a rispondere a domande piuttosto che a risposte come "stai sbagliando"
ThatDataGuy,

1
@ThatDataGuy bel commento, ma in questa domanda l'OP ha aggiunto un commento dicendo che database is accessed by javaquesto affronta direttamente la domanda. È anche molto importante che le persone che vengono qui vengano informate dei potenziali pericoli, soprattutto se SQL Injection è la prima causa di vulnerabilità del software. Una volta a conoscenza del problema, le persone possono prendere decisioni informate su quando non ha importanza, come il caso d'uso del bootstrap.
Davos,

Esattamente. Le persone copiano e incollano molto anche il codice. Smetterò di avvertire la gente di questo il giorno in cui smetterò di vedere quotidianamente le vulnerabilità dell'iniezione SQL nel codice di produzione.
Craig Ringer,

26

Secondo la documentazione PostgreSQL (4.1.2.1. Costanti di stringa) :

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

Vedi anche il parametro standard_conforming_strings , che controlla se funziona l'escaping con barre rovesciate.


grazie per la risposta, ma devo scappare manualmente da ogni carattere usando questo, se esiste una funzione integrata per farlo?
MAHI,

3
@MAHI Se ci fosse una tale funzione, sarebbe in PgJDBC, non in PostgreSQL, perché la fuga deve essere eseguita sul lato client. Non esiste una funzione pubblica documentata perché è un'idea terribile . Dovresti usare istruzioni con parametri in modo da non dover fare alcun tipo di escape potenzialmente inaffidabile.
Craig Ringer,

13

In postgresql se vuoi inserire valori con 'esso allora devi dare un extra'

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

voto positivo per mostrare le virgolette triple se hai una stringa tra virgolette
winkbrace il

su, in quanto è una soluzione semplice
ktaria il

5

puoi usare la funzione postrgesql chr (int):

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

2

Se hai bisogno di fare il lavoro all'interno di Pg:

to_json(value)

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


In che modo questa domanda è correlata a JSON?
Erwin Brandstetter,

1
@ErwinBrandstetter, mi dispiace, potrei essere fuori .. ma sfugge alle virgolette nelle stringhe
hatenine,

1
Questa è un'altra faccenda. È possibile utilizzare format(), quote_literal()o quote_nullable()per fuggire citazioni. Vedi: stackoverflow.com/a/25143945/939860
Erwin Brandstetter

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.