Chèn văn bản với dấu ngoặc đơn trong PostgreSQL


432

Tôi có một cái bàn test(id,name).

Tôi cần phải chèn giá trị như: 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');

Tôi gặp lỗi nếu tôi chạy bất kỳ câu lệnh nào ở trên.

Nếu có bất kỳ phương pháp để làm điều này một cách chính xác xin vui lòng chia sẻ. Tôi không muốn bất kỳ tuyên bố chuẩn bị.

Có thể sử dụng cơ chế thoát sql?


1
Sử dụng bất cứ giá trị nào thoát khỏi thư viện khách hàng của bạn cung cấp. Để biết thêm thông tin, bạn sẽ phải nói cách bạn truy cập cơ sở dữ liệu.
Richard Huxton

Cơ sở dữ liệu @Richard Huxton được truy cập bởi java.
MAHI

2
Vì vậy, sử dụng các giữ chỗ jdbc tiêu chuẩn. Hoặc giải thích tại sao đó không phải là sự lựa chọn tốt nhất.
Richard Huxton

@Richard Huxton Tôi không nói rằng đó không phải là sự lựa chọn tốt nhất, tôi đang tìm kiếm nếu họ tồn tại bất kỳ phương pháp thoát nào trong sql để làm như vậy.
MAHI

Chà, hãy xem câu trả lời của @ Claudix bên dưới, nhưng rõ ràng giá trị chữ sẽ cần thoát khác nhau tùy thuộc vào loại postgresql.org/docs/civerse/static/datatype.html
Richard Huxton

Câu trả lời:


763

Chuỗi ký tự

Thoát các trích dẫn đơn 'bằng cách nhân đôi chúng lên -> ''là cách tiêu chuẩn và hoạt động tất nhiên:

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

Trong các phiên bản cũ hoặc nếu bạn vẫn chạy với standard_conforming_strings = offhoặc, nói chung, nếu bạn thêm chuỗi của bạn Eđể khai báo cú pháp chuỗi thoát Posix , bạn cũng có thể thoát bằng dấu gạch chéo ngược \:

E'user\'s log'

Backslash chính nó được thoát với một dấu gạch chéo ngược khác. Nhưng điều đó thường không thích hợp hơn.
Nếu bạn phải xử lý nhiều trích dẫn đơn hoặc nhiều lớp thoát, bạn có thể tránh trích dẫn địa ngục trong PostgreQuery bằng các chuỗi được trích dẫn bằng đô la :

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

Để tránh nhầm lẫn hơn giữa các trích dẫn đô la, hãy thêm một mã thông báo duy nhất cho mỗi cặp:

$token$escape ' with ''$token$

Mà có thể được lồng bất kỳ số cấp:

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

Hãy chú ý nếu $nhân vật nên có ý nghĩa đặc biệt trong phần mềm máy khách của bạn. Bạn có thể phải thoát nó ngoài. Đây không phải là trường hợp với các máy khách PostgreSQL tiêu chuẩn như psql hoặc pgAdmin.

Đó là tất cả rất hữu ích để viết các hàm plpgsql hoặc các lệnh SQL ad-hoc. Tuy nhiên, điều đó không thể làm giảm nhu cầu sử dụng các câu lệnh đã chuẩn bị hoặc một số phương pháp khác để bảo vệ chống lại việc tiêm SQL trong ứng dụng của bạn khi có thể nhập dữ liệu của người dùng. @ Câu trả lời của Craig có nhiều hơn về điều đó. Thêm chi tiết:

Giá trị bên trong Postgres

Khi xử lý các giá trị bên trong cơ sở dữ liệu, có một vài hàm hữu ích để trích dẫn đúng chuỗi:

  • quote_literal()hoặcquote_nullable() - cái sau xuất chuỗi NULLcho đầu vào null. (Ngoài ra còn có quote_ident()tới hai quote chuỗi nơi cần thiết để có được SQL hợp lệ định .)
  • format()với định dạng định dạng %Ltương đương với quote_nullable().
    Giống:format('%L', string_var)
  • concat()hoặcconcat_ws() thường không tốt vì chúng không thoát khỏi dấu ngoặc đơn và dấu gạch chéo ngược.

1
Cũng đáng lưu ý rằng một số phiên bản PGJDBC có vấn đề với việc trích dẫn đô la - đặc biệt, có thể không bỏ qua các công cụ chấm dứt câu lệnh (;) trong các chuỗi trích dẫn bằng đô la.
Craig Ringer

1
Câu trả lời liên quan này có chi tiết cho vấn đề với JDBC.
Erwin Brandstetter

1
Và nếu bạn muốn thoát s'tring khỏi cột văn bản khi chèn trong trường hợp ngôn ngữ thủ tục, v.v., thì bạn có thể sử dụng hàm chuỗi quote_literal (cột_name).
alexglue

1
$ token $ là tuyệt vời. Cảm ơn.
huyền thoại mã hóa

@ErwinBrandstetter, lại "có thể được lồng bất kỳ số cấp nào": nhưng SELECT $outer$OUT$inner$INNER$inner$ER$outer$;chứng minh rằng lồng cấp 2 không hoạt động ở đây.?
filiprem

46

Điều này là rất nhiều thế giới xấu, bởi vì câu hỏi của bạn ngụ ý rằng bạn có thể có lỗ hổng SQL tiêm trong ứng dụng của bạn.

Bạn nên sử dụng các câu lệnh tham số. Đối với Java, sử dụng PreparedStatementvới trình giữ chỗ . Bạn nói rằng bạn không muốn sử dụng các câu lệnh được tham số hóa, nhưng bạn không giải thích tại sao , và thật lòng mà nói, đó là một lý do rất tốt để không sử dụng chúng vì chúng là cách đơn giản nhất, an toàn nhất để khắc phục sự cố bạn đang cố gắng để giải quyết.

Xem phần Ngăn chặn SQL SQL trong Java . Đừng là nạn nhân tiếp theo của Bobby .

Không có chức năng công khai trong PGJDBC để trích dẫn và thoát chuỗi. Đó là một phần bởi vì nó có thể làm cho nó có vẻ như là một ý tưởng tốt.

được xây dựng trong trích dẫn các chức năng quote_literalquote_identtrong PostgreSQL, nhưng họ là dành cho PL/PgSQLchức năng sử dụng EXECUTE. Ngày nay, quote_literalhầu hết đã bị lỗi thời EXECUTE ... USING, đó là phiên bản được tham số hóa , bởi vì nó an toàndễ dàng hơn . Bạn không thể sử dụng chúng cho mục đích bạn giải thích ở đây, vì chúng là các chức năng phía máy chủ.


Hãy tưởng tượng điều gì xảy ra nếu bạn nhận được giá trị ');DROP SCHEMA public;--từ một người dùng độc hại. Bạn sẽ sản xuất:

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

trong đó chia thành hai tuyên bố và một nhận xét bị bỏ qua:

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

Rất tiếc, có cơ sở dữ liệu của bạn.


Tôi có xu hướng đồng ý với một ngoại lệ - mệnh đề "trong đó" (mặc dù anh ta nói "insert") với danh sách các giá trị như một phần của mệnh đề "in" (hoặc một bó "hoặc" s). Tôi cho rằng bạn có thể đếm kích thước của danh sách và tạo văn bản cho câu lệnh đã chuẩn bị với mệnh đề "in", nhưng nó trở nên kỳ lạ trong trường hợp sử dụng đó.
Roboprog

@Roboprog Với một số trình điều khiển máy khách, bạn có thể sử dụng = ANY(?)và tham số mảng.
Craig Ringer

12
Tôi thường sử dụng các phần chèn theo nghĩa đen như thế này để khởi động dữ liệu, cùng với DDL. Hãy cố gắng trả lời các câu hỏi hơn là trả lời như 'bạn đang làm sai'
ThatDataGuy

1
@ThatDataGuy bình luận công bằng, nhưng trong câu hỏi này, OP đã thêm một bình luận nói rằng database is accessed by javađiều này trực tiếp giải quyết câu hỏi. Điều cũng rất quan trọng đối với những người đến đây để nhận thức được các mối nguy hiểm tiềm ẩn, đặc biệt là SQL Injection là nguyên nhân số 1 của lỗ hổng phần mềm. Khi nhận thức được vấn đề, mọi người có thể đưa ra quyết định sáng suốt khi vấn đề không xảy ra, như trường hợp sử dụng bootstrapping của bạn.
Davos

Chính xác. Mọi người cũng sao chép và dán mã rất nhiều. Tôi sẽ ngừng cảnh báo mọi người về điều này vào ngày tôi ngừng nhìn thấy các lỗ hổng SQL tiêm hàng ngày trong mã sản xuất.
Craig Ringer

26

Theo tài liệu PostgreSQL (4.1.2.1. Hằng chuỗi) :

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

Xem thêm tham số standard_conforming_strings , điều khiển xem việc thoát với dấu gạch chéo ngược có hoạt động hay không.


cảm ơn vì đã trả lời, nhưng tôi phải thoát thủ công từng char bằng cách sử dụng cái này, nếu chúng tồn tại bất kỳ hàm dựng sẵn nào để làm việc này?
MAHI

3
@MAHI Nếu có một chức năng như vậy, thì đó sẽ là trong PGJDBC, chứ không phải trong PostgreQuery, vì việc thoát phải được thực hiện ở phía máy khách. Không có chức năng công khai tài liệu như vậy bởi vì đó là một ý tưởng khủng khiếp . Bạn nên sử dụng các câu lệnh được tham số hóa để bạn không cần phải thực hiện bất kỳ loại thoát nào không đáng tin cậy.
Craig Ringer

13

Trong postgresql nếu bạn muốn chèn các giá trị 'trong đó thì bạn phải cung cấp thêm'

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

upvote để hiển thị các trích dẫn ba nếu bạn có một chuỗi trích dẫn
winkbrace

vì đây là một giải pháp đơn giản
ktaria

5

bạn có thể sử dụng hàm postrgesql chr (int):

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

2

Nếu bạn cần hoàn thành công việc bên trong PG:

to_json(value)

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


Câu hỏi này liên quan đến JSON như thế nào?
Erwin Brandstetter

1
@ErwinBrandstetter, xin lỗi, tôi có thể tắt .. nhưng nó thoát khỏi dấu ngoặc kép
hatenine

1
Đó là một vấn đề khác hoàn toàn. Bạn có thể sử dụng format(), quote_literal()hoặc quote_nullable()để thoát dấu ngoặc kép. Xem: stackoverflow.com/a/25143945/939860
Erwin Brandstetter

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.