如何利用 PostgreSQL 的 JSONB API 作为扩展的轻量级 JSON 解析器

前言

在基于 C 语言的 PostgreSQL 扩展开发中,您可能会遇到需要处理 JSON 等结构化数据的情况。通常,您可能会在扩展中引入第三方 JSON 解析库,例如 cJSON 或 libjansson。这些库功能强大、易于使用且提供了丰富的特性,但如果我们并未充分利用这些库的高级功能,引入它们则会显得多余。很多时候,我们只是希望从 JSON 中读取某个特定值或简单地遍历它。PostgreSQL 本身已经具备了处理 JSON 数据的足够能力,尽管这些功能可能不如第三方库那样直观。如果您能够充分掌握 PostgreSQL 已有的功能,或许可以避免引入第三方 JSON 库的成本。

在本文中,将向您展示如何使用 PostgreSQL 的 JSONB API 来解析、提取和遍历 JSON 结构。

解析和获取

要使用 PostgreSQL 的 JSONB API,您需要在 C 扩展中包含其头文件:

#include "utils/jsonb.h"

现在,我们可以开始使用 JSONB 了。假设我们有一个 char * 指针,指向一个完整的 JSON 结构内容。我们需要将其转换为 Jsonb *,然后才能对其进行操作。

/* myjson points to a complete JSON content */
void jsonb_example(const char * myjson)
{
   
   
    Datum jsonb_datum;
    Jsonb * jb;

    /* we first convert char * to datum representation */
    jsonb_datum = DirectFunctionCall1(jsonb_in, CStringGetDatum(myjson));

    /* then, we convert it to Jsonb * */
    jb = DatumGetJsonbP(jsonb_datum);
}

假设我们的 JSON 如下所示:

{
   
   
  "version": "1.0",
  "payload": {
   
   
    "name": "exampleapp",
    "ts_ms": 1720811216000,
    "db": "postgresql",
    "table": "mytable",
    "schema": "myschema"
  },
  "queries": [
    {
   
   
      "query": "select * from mytable"
    },
    {
   
   
      "query": "update mytable set a = 1"
    }
  ]
}

为了获取 payload 组下 db 的值,我们可以使用 JSONB 的 jsonb_get_element() 函数,函数原型如下:

Datum jsonb_get_element(Jsonb *jb, Datum *path, int npath,
 bool *isnull, bool as_text);

该函数接受一个 JSONB 指针(即我们之前创建的表示整个 JSON 消息的指针),以及一个Datum 数组和 npath,用于表示 JSON 元素的路径。请注意,此路径不必一直指向标量值,它可以停在另一个内部组或数组,具体取决于您的用例。它还接受一个 isnull 布尔指针,如果找不到元素,函数会将其设置为 false。最后,as_text 布尔值指示函数是否将结果作为 Text DatumJsonb Datum 返回。我倾向于将其设置为 false,以便返回 JSONB Datum,从而可以进一步操作。将其转换为字符串表示也很简单(通过 stringinfo 结构)。请参见以下示例。

/* myjson points to a complete JSON content */
void jsonb_example(const char * myjson)
{
   
   
    Datum jsonb_datum;
    Jsonb * jb;

    /* variables needed for fetching element */
    Datum datum_elems[2];
    Datum res;
    int numpath = 2;
    bool isnull;
    StringInfoData strinfo;

    /* we first convert char * to datum representation */
    jsonb_datum = DirectFunctionCall1(jsonb_in, CStringGetDatum(myjson));

    /* then, we convert it to Jsonb * */
    jb = DatumGetJsonbP(jsonb_datum);

    /* prepare element paths to fetch, from outer to inner */
    initStringInfo(&strinfo);
    datum_elems[0] = CStringGetTextDatum("payload");
    datum_elems[1] = CStringGetTextDatum("db");

    /* fetch it */
    res = jsonb_get_element(jb, datum_elems, numPaths, &isnull, false);
    if (isnull)
    {
   
   
        /* write NULL if element does not exist */
        resetStringInfo(&strinfoo);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值