【问题标题】:Insert text with single quotes in PostgreSQL在 PostgreSQL 中插入带单引号的文本
【发布时间】:2012-09-01 06:27:48
【问题描述】:

我有一张桌子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转义机制?

【问题讨论】:

  • 使用转义客户端库提供的任何值。要了解更多信息,您必须说明您是如何访问数据库的。
  • @Richard Huxton 数据库被 java 访问。
  • 所以使用标准的 jdbc 占位符。或者解释一下为什么这不是最佳选择。
  • @Richard Huxton 我并不是说这不是最佳选择,我正在搜索他们是否存在 sql 中的任何转义方法。
  • 好吧,请参阅下面@Claudix 的回复,但显然值文字将需要不同的转义,具体取决于它们的类型postgresql.org/docs/current/static/datatype.html

标签: sql postgresql quotes string-literals


【解决方案1】:

字符串字面量

通过将单引号 ' 加倍来转义它们 -> '' 是标准方式,当然也可以:

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

请注意,纯单引号(ASCII / UTF-8 代码 39),而不是反引号 `,它在 Postgres 中没有特殊用途(与某些其他 RDBMS 不同),而不是双引号 ",用于标识符.

在旧版本中,或者如果您仍然使用 standard_conforming_strings = off 运行,或者通常,如果您在字符串前面加上 E 来声明 Posix 转义字符串语法,您也可以使用反斜杠 @ 进行转义987654337@:

E'user\'s log'

反斜杠本身用另一个反斜杠转义。但这通常不是可取的。
如果你必须处理很多单引号或多层转义,你可以避免在PostgreSQL中用dollar-quoted strings引用地狱:

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

为进一步避免美元报价之间的混淆,请为每一对添加一个唯一标记:

$token$escape ' with ''$token$

可以嵌套任意层数:

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

注意$ 字符在您的客户端软件中是否应该具有特殊含义。此外,您可能还必须逃避它。对于像 psql 或 pgAdmin 这样的标准 PostgreSQL 客户端,情况并非如此。

这对于编写 plpgsql 函数或 ad-hoc SQL 命令非常有用。但是,当用户可以输入时,它不能减轻使用准备好的语句或其他方法来防止应用程序中的 SQL 注入的需要。 @Craig's answer 对此有更多了解。更多详情:

Postgres 中的值

在处理数据库中的值时,有几个有用的函数可以正确引用字符串:

【讨论】:

  • 另外值得注意的是,一些 PgJDBC 版本存在美元引用问题 - 特别是,它可能无法忽略美元引用字符串中的语句终止符 (;)。
  • This related answer 有 JDBC 问题的详细信息。
  • 如果你想在插入时从文本列中转义字符串,以防过程语言等,那么你可以使用 quote_literal(column_name) 字符串函数。
  • $token$ 很棒。谢谢。
  • 我们注意到尝试将字符串文字插入 Redshift(实际上是旧的 Postgres 8.x)与您在此处所说的旧版本相符。在该平台中,如果字符串文字的反斜杠与以下字符的有效转义序列不结合,则该反斜杠在插入时会消失,因此在这种情况下加倍反斜杠也有效。加载 xml/html 文字值时,您很容易被刺痛。 Literal 曾经表示(在 Redshift 中仍然如此)文字 带有转义。很高兴您现在必须使用 E 明确请求该行为。
【解决方案2】:

这是一个糟糕的世界,因为您的问题暗示您的应用程序中可能存在 SQL injection 漏洞。

您应该使用参数化语句。对于 Java,请使用 PreparedStatement with placeholders。你说你不想使用参数化语句,但你没有解释为什么,坦率地说,不使用它们必须是一个很好的理由,因为它们是最简单、最安全的方法解决您要解决的问题。

Preventing SQL Injection in Java。不要成为Bobby 的下一个受害者。

PgJDBC 中没有用于字符串引用和转义的公共函数。这部分是因为它可能使它看起来像是一个好主意。

在 PostgreSQL 中内置引用函数 quote_literalquote_ident,但它们适用于使用 EXECUTEPL/PgSQL 函数。现在quote_literal 大多被EXECUTE ... USING 淘汰,这是参数化版本,因为它更安全 并且更容易。您不能将它们用于您在此处解释的目的,因为它们是服务器端函数。


想象一下,如果您从恶意用户那里获得值 ');DROP SCHEMA public;-- 会发生什么。你会产生:

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

分解为两条语句和一条被忽略的注释:

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

哎呀,你的数据库好了。

【讨论】:

  • 我经常使用像这样的文字插入来引导数据,以及 DDL。让我们试着回答问题,而不是像“你做错了”这样的回答
  • @ThatDataGuy 公平评论,但在这个问题中,OP 添加了一条评论说 database is accessed by java 所以这确实直接解决了这个问题。让来到这里的人意识到潜在的危险也非常重要,特别是考虑到 SQL 注入是软件漏洞的第一大原因。一旦意识到这个问题,人们就可以做出明智的决定,何时无关紧要,例如您的引导用例。
  • 没错。人们还经常复制和粘贴代码。在我不再每天在生产代码中看到 SQL 注入漏洞的那一天,我将停止警告人们。
  • 这个问题和答案应该是任何即将到来的软件开发人员考试的一部分。 OP 操作“可能安全”,但即使是最有经验的人也能不断提醒危险。
  • @Davos 同意,应该警告人们,但我认为不应该有一个独立的警告答案。最好通过以下过程警告人们: i) 在每个答案上写下评论,要求作者在他们的答案前加上警告; ii) 如果作者在 7 天内没有更新,那么你就去那里编辑带有序言的答案。
【解决方案3】:

根据PostgreSQL documentation (4.1.2.1. String Constants)

要在字符串常量中包含单引号字符,请编写 两个相邻的单引号,例如'黛安'的马'。

另请参阅standard_conforming_strings 参数,该参数控制是否使用反斜杠进行转义。

【讨论】:

  • 感谢您的回复,但如果它们存在任何用于执行此操作的内置函数,我必须使用它手动转义每个字符?
  • @MAHI 如果有这样的功能,它会在 PgJDBC 中,而不是在 PostgreSQL 中,因为转义必须在客户端完成。没有这样的记录在案的公共功能,因为这是一个可怕的想法。您应该使用参数化语句,因此您不需要进行任何可能不可靠的转义。
【解决方案4】:

如果你想在 postgresql 中插入带有' 的值,那么为此你必须提供额外的'

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

【讨论】:

  • 如果您有带引号的字符串,请支持显示三引号
  • up ,因为它是一个简单的解决方案
【解决方案5】:

你可以使用 postrgesql chr(int) 函数:

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

【讨论】:

    【解决方案6】:

    如果你需要在 Pg 中完成工作:

    to_json(value)

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

    【讨论】:

    • 这个问题和 JSON 有什么关系?
    • @ErwinBrandstetter ,对不起,我可能会离开.. 但它会转义字符串中的引号
    • 那完全是另一回事。您可以使用format()quote_literal()quote_nullable() 来转义引号。见:stackoverflow.com/a/25143945/939860
    【解决方案7】:

    当我使用Python向PostgreSQL中插入值时,我也遇到了一个问题:列“xxx”不存在。

    我在wiki.postgresql找到原因:

    PostgreSQL 对此仅使用单引号(即WHERE name = 'John')。双引号用于引用系统标识符;字段名、表名等(即WHERE "last name" = 'Smith')。
    MySQL 使用`(重音符号或反引号)来引用系统标识符,这显然是非标准的。

    这意味着PostgreSQL只能对字段名、表名等使用单引号,所以不能在值中使用单引号。

    我的情况是:我想在 PostgreSQL 中插入值“it's adj for sb and it's adj of sb”。

    我是如何解决这个问题的:

    我将'替换为,并将"替换为'因为PostgreSQL值不支持双引号。

    所以我认为您可以使用以下代码插入值:

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

    【讨论】:

    • "表示PostgreSQL只能对字段名、表名使用单引号" 不,你可以使用单引号'列名或表名。在 Postgres 和标准 SQL 中都没有。您可以轻松地将单引号嵌入到字符串常量 user''s log' 中,这就是 SQL 标准中的定义。
    • @a_horse_with_no_name 感谢您的解决方案。经过测试,我发现它可以工作。
    猜你喜欢
    • 2012-08-05
    • 1970-01-01
    • 2019-02-15
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 2014-11-09
    • 2015-01-31
    相关资源
    最近更新 更多