pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: David Steele <david@pgmasters.net>
To: Tom Lane <tgl@sss.pgh.pa.us>
Cc: Stephen Frost <sfrost@snowman.net>
Cc: David Fetter <david@fetter.org>
Cc: Robert Haas <robertmhaas@gmail.com>
Cc: Tels <nospam-pg-abuse@bloodgate.com>
Cc: Suraj Kharage <suraj.kharage@enterprisedb.com>
Cc: Rushabh Lathia <rushabh.lathia@gmail.com>
Cc: Andrew Dunstan <andrew.dunstan@2ndquadrant.com>
Cc: PostgreSQL Hackers <pgsql-hackers@postgresql.org>
Cc: Jeevan Chalke <jeevan.chalke@enterprisedb.com>
Cc: vignesh C <vignesh21@gmail.com>
Subject: Re: backup manifests
Date: Tue, 14 Jan 2020 22:21:00 -0700
Message-ID: <aa9fbed1-247a-3565-3c55-22b1cfb694fb@pgmasters.net> (raw)
In-Reply-To: <6524.1579063633@sss.pgh.pa.us>
References: <CA+TgmoY_icSH_uoBUQH2NnJBucShKsfONCXxdhuLh4m4aAh5Sg@mail.gmail.com>
	<20200103170123.GX3195@tamriel.snowman.net>
	<CA+TgmobjkosrwPaEA6nxhC-JoZ4JGXSiQ+27Zkm3iMY0VnMwvQ@mail.gmail.com>
	<20200103193559.GY3195@tamriel.snowman.net>
	<CA+TgmoY1EpREir7QvAHBzyj370-+bmfFV2F_X3ZDytpxf=iezw@mail.gmail.com>
	<20200108013348.GF3195@tamriel.snowman.net>
	<00b28009-3781-4c4a-174b-be2c1bc52f27@pgmasters.net>
	<CA+TgmoYdEEtO9HEPdDjV8DUT+=haZf_3bsMEuVgkOWTjt+PSKA@mail.gmail.com>
	<12445.1579024384@sss.pgh.pa.us>
	<20200114183312.GF32763@fetter.org>
	<20200114203540.GC3195@tamriel.snowman.net>
	<1115c3d4-2d80-8388-4fd4-5fdb3ee9b429@pgmasters.net>
	<6524.1579063633@sss.pgh.pa.us>

Hi Tom,

On 1/14/20 9:47 PM, Tom Lane wrote:
> David Steele <david@pgmasters.net> writes:
>> I'm happy to work up a prototype unless the consensus is that we
>> absolutely don't want a second JSON parser in core.
> 
> How much code are we talking about?  If the answer is "a few hundred
> lines", it's a lot easier to swallow than if it's "a few thousand".

It's currently about a thousand lines but we have a lot of functions to 
convert to/from specific types.  I imagine the line count would be 
similar using one of the approaches I discussed above.

Current source attached for reference.

Regards,
-- 
-David
david@pgmasters.net

Attachments:

json.c (text/plain, 29.2K) download /*********************************************************************************************************************************** Convert JSON to/from KeyValue ***********************************************************************************************************************************/ #include "build.auto.h" #include <ctype.h> #include <string.h> #include "common/debug.h" #include "common/log.h" #include "common/type/json.h" /*********************************************************************************************************************************** Prototypes ***********************************************************************************************************************************/ static Variant *jsonToVarInternal(const char *json, unsigned int *jsonPos); /*********************************************************************************************************************************** Consume whitespace ***********************************************************************************************************************************/ static void jsonConsumeWhiteSpace(const char *json, unsigned int *jsonPos) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRINGZ, json); FUNCTION_TEST_PARAM_P(UINT, jsonPos); FUNCTION_TEST_END(); // Consume whitespace while (json[*jsonPos] == ' ' || json[*jsonPos] == '\t' || json[*jsonPos] == '\n' || json[*jsonPos] == '\r') (*jsonPos)++; FUNCTION_TEST_RETURN_VOID(); } /*********************************************************************************************************************************** Convert a json string to a bool ***********************************************************************************************************************************/ static bool jsonToBoolInternal(const char *json, unsigned int *jsonPos) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRINGZ, json); FUNCTION_TEST_PARAM_P(UINT, jsonPos); FUNCTION_TEST_END(); bool result; if (strncmp(json + *jsonPos, TRUE_Z, 4) == 0) { result = true; *jsonPos += 4; } else if (strncmp(json + *jsonPos, FALSE_Z, 5) == 0) { result = false; *jsonPos += 5; } else THROW_FMT(JsonFormatError, "expected boolean at '%s'", json + *jsonPos); FUNCTION_TEST_RETURN(result); } bool jsonToBool(const String *json) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_END(); unsigned int jsonPos = 0; jsonConsumeWhiteSpace(strPtr(json), &jsonPos); bool result = jsonToBoolInternal(strPtr(json), &jsonPos); jsonConsumeWhiteSpace(strPtr(json), &jsonPos); if (jsonPos != strSize(json)) THROW_FMT(JsonFormatError, "unexpected characters after boolean at '%s'", strPtr(json) + jsonPos); FUNCTION_TEST_RETURN(result); } /*********************************************************************************************************************************** Convert a json number to various integer types ***********************************************************************************************************************************/ static Variant * jsonToNumberInternal(const char *json, unsigned int *jsonPos) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRINGZ, json); FUNCTION_TEST_PARAM_P(UINT, jsonPos); FUNCTION_TEST_END(); Variant *result = NULL; unsigned int beginPos = *jsonPos; bool intSigned = false; // Consume the - if (json[*jsonPos] == '-') { (*jsonPos)++; intSigned = true; } // Consume all digits while (isdigit(json[*jsonPos])) (*jsonPos)++; // Invalid if only a - was found if (json[*jsonPos - 1] == '-') THROW_FMT(JsonFormatError, "found '-' with no integer at '%s'", json + beginPos); MEM_CONTEXT_TEMP_BEGIN() { // Extract the numeric as a string String *resultStr = strNewN(json + beginPos, *jsonPos - beginPos); // Convert the string to a integer variant memContextSwitch(MEM_CONTEXT_OLD()); if (intSigned) result = varNewInt64(cvtZToInt64(strPtr(resultStr))); else result = varNewUInt64(cvtZToUInt64(strPtr(resultStr))); memContextSwitch(MEM_CONTEXT_TEMP()); } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(result); } static Variant * jsonToNumber(const String *json) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_END(); unsigned int jsonPos = 0; jsonConsumeWhiteSpace(strPtr(json), &jsonPos); Variant *result = jsonToNumberInternal(strPtr(json), &jsonPos); jsonConsumeWhiteSpace(strPtr(json), &jsonPos); if (jsonPos != strSize(json)) THROW_FMT(JsonFormatError, "unexpected characters after number at '%s'", strPtr(json) + jsonPos); FUNCTION_TEST_RETURN(result); } int jsonToInt(const String *json) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_END(); int result = 0; MEM_CONTEXT_TEMP_BEGIN() { result = varIntForce(jsonToNumber(json)); } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(result); } int64_t jsonToInt64(const String *json) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_END(); int64_t result = 0; MEM_CONTEXT_TEMP_BEGIN() { result = varInt64Force(jsonToNumber(json)); } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(result); } unsigned int jsonToUInt(const String *json) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_END(); unsigned int result = 0; MEM_CONTEXT_TEMP_BEGIN() { result = varUIntForce(jsonToNumber(json)); } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(result); } uint64_t jsonToUInt64(const String *json) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_END(); uint64_t result = 0; MEM_CONTEXT_TEMP_BEGIN() { result = varUInt64Force(jsonToNumber(json)); } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(result); } /*********************************************************************************************************************************** Convert a json string to a String ***********************************************************************************************************************************/ static String * jsonToStrInternal(const char *json, unsigned int *jsonPos) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRINGZ, json); FUNCTION_TEST_PARAM_P(UINT, jsonPos); FUNCTION_TEST_END(); String *result = strNew(""); if (json[*jsonPos] != '"') THROW_FMT(JsonFormatError, "expected '\"' at '%s'", json + *jsonPos); MEM_CONTEXT_TEMP_BEGIN() { (*jsonPos)++; while (json[*jsonPos] != '"') { if (json[*jsonPos] == '\\') { (*jsonPos)++;; switch (json[*jsonPos]) { case '"': strCatChr(result, '"'); break; case '\\': strCatChr(result, '\\'); break; case '/': strCatChr(result, '/'); break; case 'n': strCatChr(result, '\n'); break; case 'r': strCatChr(result, '\r'); break; case 't': strCatChr(result, '\t'); break; case 'b': strCatChr(result, '\b'); break; case 'f': strCatChr(result, '\f'); break; default: THROW_FMT(JsonFormatError, "invalid escape character '%c'", json[*jsonPos]); } } else { if (json[*jsonPos] == '\0') THROW(JsonFormatError, "expected '\"' but found null delimiter"); strCatChr(result, json[*jsonPos]); } (*jsonPos)++;; }; // Advance the character array pointer to the next element after the string (*jsonPos)++;; } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(result); } String * jsonToStr(const String *json) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_END(); unsigned int jsonPos = 0; jsonConsumeWhiteSpace(strPtr(json), &jsonPos); String *result = NULL; if (strncmp(strPtr(json), NULL_Z, 4) == 0) jsonPos += 4; else result = jsonToStrInternal(strPtr(json), &jsonPos); jsonConsumeWhiteSpace(strPtr(json), &jsonPos); if (jsonPos != strSize(json)) THROW_FMT(JsonFormatError, "unexpected characters after string at '%s'", strPtr(json) + jsonPos); FUNCTION_TEST_RETURN(result); } /*********************************************************************************************************************************** Convert a json object to a KeyValue ***********************************************************************************************************************************/ static KeyValue * jsonToKvInternal(const char *json, unsigned int *jsonPos) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRINGZ, json); FUNCTION_TEST_PARAM_P(UINT, jsonPos); FUNCTION_TEST_END(); KeyValue *result = kvNew(); MEM_CONTEXT_TEMP_BEGIN() { // Move position to the first key/value in the object (*jsonPos)++; jsonConsumeWhiteSpace(json, jsonPos); // Only proceed if the array is not empty if (json[*jsonPos] != '}') { do { if (json[*jsonPos] == ',') { (*jsonPos)++; jsonConsumeWhiteSpace(json, jsonPos); } Variant *key = varNewStr(jsonToStrInternal(json, jsonPos)); jsonConsumeWhiteSpace(json, jsonPos); if (json[*jsonPos] != ':') THROW_FMT(JsonFormatError, "expected ':' at '%s'", json + *jsonPos); (*jsonPos)++; jsonConsumeWhiteSpace(json, jsonPos); kvPut(result, key, jsonToVarInternal(json, jsonPos)); } while (json[*jsonPos] == ','); } if (json[*jsonPos] != '}') THROW_FMT(JsonFormatError, "expected '}' at '%s'", json + *jsonPos); (*jsonPos)++; } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(result); } KeyValue * jsonToKv(const String *json) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_END(); unsigned int jsonPos = 0; jsonConsumeWhiteSpace(strPtr(json), &jsonPos); if (strPtr(json)[jsonPos] != '{') THROW_FMT(JsonFormatError, "expected '{' at '%s'", strPtr(json) + jsonPos); KeyValue *result = jsonToKvInternal(strPtr(json), &jsonPos); jsonConsumeWhiteSpace(strPtr(json), &jsonPos); if (jsonPos != strSize(json)) THROW_FMT(JsonFormatError, "unexpected characters after object at '%s'", strPtr(json) + jsonPos); FUNCTION_TEST_RETURN(result); } /*********************************************************************************************************************************** Convert a json string to an array ***********************************************************************************************************************************/ static VariantList * jsonToVarLstInternal(const char *json, unsigned int *jsonPos) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRINGZ, json); FUNCTION_TEST_PARAM_P(UINT, jsonPos); FUNCTION_TEST_END(); VariantList *result = varLstNew(); if (json[*jsonPos] != '[') THROW_FMT(JsonFormatError, "expected '[' at '%s'", json + *jsonPos); MEM_CONTEXT_TEMP_BEGIN() { // Move position to the first element in the array (*jsonPos)++; jsonConsumeWhiteSpace(json, jsonPos); // Only proceed if the array is not empty if (json[*jsonPos] != ']') { do { if (json[*jsonPos] == ',') { (*jsonPos)++; jsonConsumeWhiteSpace(json, jsonPos); } memContextSwitch(MEM_CONTEXT_OLD()); varLstAdd(result, jsonToVarInternal(json, jsonPos)); memContextSwitch(MEM_CONTEXT_TEMP()); jsonConsumeWhiteSpace(json, jsonPos); } while (json[*jsonPos] == ','); } if (json[*jsonPos] != ']') THROW_FMT(JsonFormatError, "expected ']' at '%s'", json + *jsonPos); (*jsonPos)++; } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(result); } VariantList * jsonToVarLst(const String *json) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_END(); unsigned int jsonPos = 0; jsonConsumeWhiteSpace(strPtr(json), &jsonPos); VariantList *result = jsonToVarLstInternal(strPtr(json), &jsonPos); jsonConsumeWhiteSpace(strPtr(json), &jsonPos); if (jsonPos != strSize(json)) THROW_FMT(JsonFormatError, "unexpected characters after array at '%s'", strPtr(json) + jsonPos); FUNCTION_TEST_RETURN(result); } /*********************************************************************************************************************************** Convert JSON to a variant ***********************************************************************************************************************************/ static Variant * jsonToVarInternal(const char *json, unsigned int *jsonPos) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRINGZ, json); FUNCTION_TEST_PARAM_P(UINT, jsonPos); FUNCTION_TEST_END(); Variant *result = NULL; jsonConsumeWhiteSpace(json, jsonPos); // There should be some data if (json[*jsonPos] == '\0') THROW(JsonFormatError, "expected data"); // Determine data type switch (json[*jsonPos]) { // String case '"': { result = varNewStr(jsonToStrInternal(json, jsonPos)); break; } // Integer case '-': case '0' ... '9': { result = jsonToNumberInternal(json, jsonPos); break; } // Boolean case 't': case 'f': { result = varNewBool(jsonToBoolInternal(json, jsonPos)); break; } // Null case 'n': { if (strncmp(json + *jsonPos, NULL_Z, 4) == 0) *jsonPos += 4; else THROW_FMT(JsonFormatError, "expected null at '%s'", json + *jsonPos); break; } // Array case '[': { result = varNewVarLst(jsonToVarLstInternal(json, jsonPos)); break; } // Object case '{': { result = varNewKv(jsonToKvInternal(json, jsonPos)); break; } // Object default: { THROW_FMT(JsonFormatError, "invalid type at '%s'", json + *jsonPos); break; } } jsonConsumeWhiteSpace(json, jsonPos); FUNCTION_TEST_RETURN(result); } Variant * jsonToVar(const String *json) { FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(STRING, json); FUNCTION_LOG_END(); const char *jsonPtr = strPtr(json); unsigned int jsonPos = 0; FUNCTION_LOG_RETURN(VARIANT, jsonToVarInternal(jsonPtr, &jsonPos)); } /*********************************************************************************************************************************** Convert a boolean to JSON ***********************************************************************************************************************************/ const String * jsonFromBool(bool value) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(BOOL, value); FUNCTION_TEST_END(); FUNCTION_TEST_RETURN(value ? TRUE_STR : FALSE_STR); } /*********************************************************************************************************************************** Convert a number to JSON ***********************************************************************************************************************************/ String * jsonFromInt(int number) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(INT, number); FUNCTION_TEST_END(); char working[CVT_BASE10_BUFFER_SIZE]; cvtIntToZ(number, working, sizeof(working)); FUNCTION_TEST_RETURN(strNew(working)); } String * jsonFromInt64(int64_t number) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(INT64, number); FUNCTION_TEST_END(); char working[CVT_BASE10_BUFFER_SIZE]; cvtInt64ToZ(number, working, sizeof(working)); FUNCTION_TEST_RETURN(strNew(working)); } String * jsonFromUInt(unsigned int number) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(UINT, number); FUNCTION_TEST_END(); char working[CVT_BASE10_BUFFER_SIZE]; cvtUIntToZ(number, working, sizeof(working)); FUNCTION_TEST_RETURN(strNew(working)); } String * jsonFromUInt64(uint64_t number) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(UINT64, number); FUNCTION_TEST_END(); char working[CVT_BASE10_BUFFER_SIZE]; cvtUInt64ToZ(number, working, sizeof(working)); FUNCTION_TEST_RETURN(strNew(working)); } /*********************************************************************************************************************************** Output and escape a string ***********************************************************************************************************************************/ static void jsonFromStrInternal(String *json, const String *string) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, json); FUNCTION_TEST_PARAM(STRING, string); FUNCTION_TEST_END(); ASSERT(json != NULL); // If string is null if (string == NULL) { strCat(json, NULL_Z); } // Else escape and output string else { strCatChr(json, '"'); for (unsigned int stringIdx = 0; stringIdx < strSize(string); stringIdx++) { char stringChr = strPtr(string)[stringIdx]; switch (stringChr) { case '"': strCat(json, "\\\""); break; case '\\': strCat(json, "\\\\"); break; case '\n': strCat(json, "\\n"); break; case '\r': strCat(json, "\\r"); break; case '\t': strCat(json, "\\t"); break; case '\b': strCat(json, "\\b"); break; case '\f': strCat(json, "\\f"); break; default: strCatChr(json, stringChr); break; } } strCatChr(json, '"'); } FUNCTION_TEST_RETURN_VOID(); } String * jsonFromStr(const String *string) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(STRING, string); FUNCTION_TEST_END(); String *json = strNew(""); jsonFromStrInternal(json, string); FUNCTION_TEST_RETURN(json); } /*********************************************************************************************************************************** Internal recursive function to walk a KeyValue and return a json string ***********************************************************************************************************************************/ static String * jsonFromKvInternal(const KeyValue *kv) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(KEY_VALUE, kv); FUNCTION_TEST_END(); ASSERT(kv != NULL); String *result = strNew("{"); MEM_CONTEXT_TEMP_BEGIN() { const StringList *keyList = strLstSort(strLstNewVarLst(kvKeyList(kv)), sortOrderAsc); for (unsigned int keyIdx = 0; keyIdx < strLstSize(keyList); keyIdx++) { String *key = strLstGet(keyList, keyIdx); const Variant *value = kvGet(kv, VARSTR(key)); // If going to add another key, prepend a comma if (keyIdx > 0) strCat(result, ","); // Keys are always strings in the output, so add starting quote and colon. strCatFmt(result, "\"%s\":", strPtr(key)); // NULL value if (value == NULL) strCat(result, NULL_Z); else { switch (varType(value)) { case varTypeKeyValue: { strCat(result, strPtr(jsonFromKvInternal(kvDup(varKv(value))))); break; } case varTypeVariantList: { // If the array is empty, then do not add formatting, else process the array. if (varVarLst(value) == NULL) strCat(result, NULL_Z); else if (varLstSize(varVarLst(value)) == 0) strCat(result, "[]"); else { strCat(result, "["); for (unsigned int arrayIdx = 0; arrayIdx < varLstSize(varVarLst(value)); arrayIdx++) { Variant *arrayValue = varLstGet(varVarLst(value), arrayIdx); // If going to add another element, add a comma if (arrayIdx > 0) strCat(result, ","); // If array value is null if (arrayValue == NULL) { strCat(result, NULL_Z); } // If the type is a string, add leading and trailing double quotes else if (varType(arrayValue) == varTypeString) { jsonFromStrInternal(result, varStr(arrayValue)); } else if (varType(arrayValue) == varTypeKeyValue) { strCat(result, strPtr(jsonFromKvInternal(kvDup(varKv(arrayValue))))); } else if (varType(arrayValue) == varTypeVariantList) { strCat(result, strPtr(jsonFromVar(arrayValue))); } // Numeric, Boolean or other type else strCat(result, strPtr(varStrForce(arrayValue))); } strCat(result, "]"); } break; } // String case varTypeString: { jsonFromStrInternal(result, varStr(value)); break; } default: { strCat(result, strPtr(varStrForce(value))); break; } } } } result = strCat(result, "}"); } MEM_CONTEXT_TEMP_END(); FUNCTION_TEST_RETURN(result); } /*********************************************************************************************************************************** Convert KeyValue object to JSON string. Currently this function is only intended to convert the limited types that are included in info files. More types will be added as needed. Since this function is only intended to read internally-generated JSON it is assumed to be well-formed with no extraneous whitespace. ***********************************************************************************************************************************/ String * jsonFromKv(const KeyValue *kv) { FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(KEY_VALUE, kv); FUNCTION_LOG_END(); ASSERT(kv != NULL); String *result = NULL; MEM_CONTEXT_TEMP_BEGIN() { String *jsonStr = jsonFromKvInternal(kv); // Duplicate the string into the calling context memContextSwitch(MEM_CONTEXT_OLD()); result = strDup(jsonStr); memContextSwitch(MEM_CONTEXT_TEMP()); } MEM_CONTEXT_TEMP_END(); FUNCTION_LOG_RETURN(STRING, result); } /*********************************************************************************************************************************** Convert Variant object to JSON string. Currently this function is only intended to convert the limited types that are included in info files. More types will be added as needed. ***********************************************************************************************************************************/ String * jsonFromVar(const Variant *var) { FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(VARIANT, var); FUNCTION_LOG_END(); String *result = NULL; MEM_CONTEXT_TEMP_BEGIN() { String *jsonStr = strNew(""); // If VariantList then process each item in the array. Currently the list must be KeyValue types. if (var == NULL) { strCat(jsonStr, strPtr(NULL_STR)); } else if (varType(var) == varTypeBool) { strCat(jsonStr, strPtr(jsonFromBool(varBool(var)))); } else if (varType(var) == varTypeUInt) { strCat(jsonStr, strPtr(jsonFromUInt(varUInt(var)))); } else if (varType(var) == varTypeUInt64) { strCat(jsonStr, strPtr(jsonFromUInt64(varUInt64(var)))); } else if (varType(var) == varTypeString) { jsonFromStrInternal(jsonStr, varStr(var)); } else if (varType(var) == varTypeVariantList) { const VariantList *vl = varVarLst(var); // If not an empty array if (varLstSize(vl) > 0) { strCat(jsonStr, "["); // Currently only KeyValue and String lists are supported for (unsigned int vlIdx = 0; vlIdx < varLstSize(vl); vlIdx++) { // If going to add another key, append a comma if (vlIdx > 0) strCat(jsonStr, ","); Variant *varSub = varLstGet(vl, vlIdx); if (varSub == NULL) { strCat(jsonStr, NULL_Z); } else if (varType(varSub) == varTypeBool) { strCat(jsonStr, strPtr(jsonFromBool(varBool(varSub)))); } else if (varType(varSub) == varTypeKeyValue) { strCat(jsonStr, strPtr(jsonFromKvInternal(varKv(varSub)))); } else if (varType(varSub) == varTypeVariantList) { strCat(jsonStr, strPtr(jsonFromVar(varSub))); } else if (varType(varSub) == varTypeInt) { strCat(jsonStr, strPtr(jsonFromInt(varInt(varSub)))); } else if (varType(varSub) == varTypeInt64) { strCat(jsonStr, strPtr(jsonFromInt64(varInt64(varSub)))); } else if (varType(varSub) == varTypeUInt) { strCat(jsonStr, strPtr(jsonFromUInt(varUInt(varSub)))); } else if (varType(varSub) == varTypeUInt64) { strCat(jsonStr, strPtr(jsonFromUInt64(varUInt64(varSub)))); } else jsonFromStrInternal(jsonStr, varStr(varSub)); } // Close the array strCat(jsonStr, "]"); } // Else empty array else strCat(jsonStr, "[]"); } else if (varType(var) == varTypeKeyValue) { strCat(jsonStr, strPtr(jsonFromKvInternal(varKv(var)))); } else THROW(JsonFormatError, "variant type is invalid"); // Duplicate the string into the calling context memContextSwitch(MEM_CONTEXT_OLD()); result = strDup(jsonStr); memContextSwitch(MEM_CONTEXT_TEMP()); } MEM_CONTEXT_TEMP_END(); FUNCTION_LOG_RETURN(STRING, result); }
json.h (text/plain, 1.3K) download /*********************************************************************************************************************************** Convert JSON to/from KeyValue ***********************************************************************************************************************************/ #ifndef COMMON_TYPE_JSON_H #define COMMON_TYPE_JSON_H #include "common/type/keyValue.h" /*********************************************************************************************************************************** Functions ***********************************************************************************************************************************/ bool jsonToBool(const String *json); int jsonToInt(const String *json); int64_t jsonToInt64(const String *json); KeyValue *jsonToKv(const String *json); String *jsonToStr(const String *json); unsigned int jsonToUInt(const String *json); uint64_t jsonToUInt64(const String *json); Variant *jsonToVar(const String *json); VariantList *jsonToVarLst(const String *json); const String *jsonFromBool(bool value); String *jsonFromInt(int number); String *jsonFromInt64(int64_t number); String *jsonFromKv(const KeyValue *kv); String *jsonFromStr(const String *string); String *jsonFromUInt(unsigned int number); String *jsonFromUInt64(uint64_t number); String *jsonFromVar(const Variant *var); #endif

view thread (243+ messages)  latest in thread

Message-ID: <aa9fbed1-247a-3565-3c55-22b1cfb694fb@pgmasters.net>
Permalink:  ../aa9fbed1-247a-3565-3c55-22b1cfb694fb@pgmasters.net/
Also on:    postgresql.org/message-id/aa9fbed1-247a-3565-3c55-22b1cfb694fb@pgmasters.net

 · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: david@pgmasters.net, tgl@sss.pgh.pa.us, sfrost@snowman.net, david@fetter.org, robertmhaas@gmail.com, nospam-pg-abuse@bloodgate.com, suraj.kharage@enterprisedb.com, rushabh.lathia@gmail.com, andrew.dunstan@2ndquadrant.com, jeevan.chalke@enterprisedb.com, vignesh21@gmail.com
  Subject: Re: backup manifests
  In-Reply-To: <aa9fbed1-247a-3565-3c55-22b1cfb694fb@pgmasters.net>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox