前言
在基于 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 Datum 或 Jsonb 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);

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



