处理postgresql

时间:2015-07-28 08:54:53

标签: json postgresql unicode

我有一些JSON数据存储在postgresql数据库(9.4.1)的JSON(不是JSONB)列中。其中一些JSON结构在其属性值中包含unicode序列。例如:

{"client_id": 1, "device_name": "FooBar\ufffd\u0000\ufffd\u000f\ufffd" }

当我尝试查询此JSON列时(即使我没有直接尝试访问device_name属性),我收到以下错误:

  

错误:不支持的Unicode转义序列
  细节:\u0000无法转换为文字。

您可以通过在postgresql服务器上执行以下命令来重新创建此错误:

select '{"client_id": 1, "device_name": "FooBar\ufffd\u0000\ufffd\u000f\ufffd" }'::json->>'client_id'

错误对我有意义 - 根本没有办法在文本结果中表示unicode序列NULL

有没有办法让我查询相同的JSON数据,而不必执行"卫生"关于传入的数据?这些JSON结构会定期更改,因此扫描特定属性(在这种情况下为device_name)将不是一个好的解决方案,因为可能很容易存在可能包含类似数据的其他属性。

经过一些调查后,似乎这种行为对于版本9.4.1来说是新的mentioned in the changelog

  

...因此,当需要转换为转义表单时,{j}值中的\u0000也会被拒绝。只要没有对值进行处理,此更改不会破坏将\u0000存储在json列中的能力...

这真的是意图吗?在这里降级到9.4.1之前是一个可行的选择吗?

<子> 作为旁注,此属性取自客户端移动设备的名称 - 它是将此文本输入设备的用户。用户如何插入NULLREPLACEMENT CHARACTER值?!

3 个答案:

答案 0 :(得分:23)

\u0000是一个在字符串中无效的Unicode代码点。除了消毒字符串之外别无他法。

由于json只是特定格式的字符串,因此您可以使用标准字符串函数,而无需担心JSON结构。删除代码点的单行清理程序将是:

SELECT (regexp_replace(the_string::text, '\\u0000', '', 'g'))::json;

但是你也可以插入你喜欢的任何字符,如果将零代码点用作某种形式的分隔符,这将非常有用。

还要注意数据库中存储的内容与呈现给用户的方式之间的细微差别。您可以将代码点存储在JSON字符串中,但在将值作为json数据类型处理之前,必须先将其预处理为其他字符。

答案 1 :(得分:0)

帕特里克的解决方案并没有为我开箱即用。无论总是抛出一个错误。然后我研究了一点,并且能够编写一个小的自定义函数来解决这个问题。

首先,我可以通过写下来重现错误:

select json '{ "a":  "null \u0000 escape" }' ->> 'a' as fails

然后我添加了一个我在查询中使用的自定义函数:

CREATE OR REPLACE FUNCTION null_if_invalid_string(json_input JSON, record_id UUID)
  RETURNS JSON AS $$
DECLARE json_value JSON DEFAULT NULL;
BEGIN
  BEGIN
    json_value := json_input ->> 'location';
    EXCEPTION WHEN OTHERS
    THEN
      RAISE NOTICE 'Invalid json value: "%".  Returning NULL.', record_id;
      RETURN NULL;
  END;
  RETURN json_input;
END;
$$ LANGUAGE plpgsql;

要调用该函数,请执行此操作。你不应该收到错误。

select null_if_invalid_string('{ "a":  "null \u0000 escape" }', id) from my_table

然而这应该按预期返回json:

select null_if_invalid_string('{ "a":  "null" }', id) from my_table

答案 2 :(得分:-1)

如果您不希望这些空字节结果,只需添加:

AND json NOT LIKE '%\u0000%'

在您的WHERE语句中