#include "pg_query_outfuncs.h" #include "postgres.h" #include #include "access/relation.h" #include "nodes/parsenodes.h" #include "nodes/plannodes.h" #include "nodes/value.h" #include "utils/datum.h" #include "pg_query_json_helper.c" #define OUT_TYPE(typename, typename_c) StringInfo #define OUT_NODE(typename, typename_c, typename_underscore, typename_underscore_upcase, typename_cast, fldname) \ { \ WRITE_NODE_TYPE(CppAsString(typename)); \ _out##typename_c(out, (const typename_cast *) obj); \ } /* Write the label for the node type */ #define WRITE_NODE_TYPE(nodelabel) \ appendStringInfoString(out, "\"" nodelabel "\":{") /* Write an integer field */ #define WRITE_INT_FIELD(outname, outname_json, fldname) \ if (node->fldname != 0) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%d,", node->fldname); \ } /* Write an unsigned integer field */ #define WRITE_UINT_FIELD(outname, outname_json, fldname) \ if (node->fldname != 0) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%u,", node->fldname); \ } /* Write an unsigned integer field */ #define WRITE_UINT64_FIELD(outname, outname_json, fldname) \ if (node->fldname != 0) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":" UINT64_FORMAT ",", node->fldname); \ } /* Write a long-integer field */ #define WRITE_LONG_FIELD(outname, outname_json, fldname) \ if (node->fldname != 0) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%ld,", node->fldname); \ } /* Write a char field (ie, one ascii character) */ #define WRITE_CHAR_FIELD(outname, outname_json, fldname) \ if (node->fldname != 0) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":\"%c\",", node->fldname); \ } /* Write an enumerated-type field */ #define WRITE_ENUM_FIELD(typename, outname, outname_json, fldname) \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":\"%s\",", \ _enumToString##typename(node->fldname)); /* Write a float field */ #define WRITE_FLOAT_FIELD(outname, outname_json, fldname) \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%f,", node->fldname) /* Write a boolean field */ #define WRITE_BOOL_FIELD(outname, outname_json, fldname) \ if (node->fldname) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%s,", \ booltostr(node->fldname)); \ } /* Write a character-string (possibly NULL) field */ #define WRITE_STRING_FIELD(outname, outname_json, fldname) \ if (node->fldname != NULL) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":"); \ _outToken(out, node->fldname); \ appendStringInfo(out, ","); \ } #define WRITE_LIST_FIELD(outname, outname_json, fldname) \ if (node->fldname != NULL) { \ const ListCell *lc; \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":"); \ appendStringInfoChar(out, '['); \ foreach(lc, node->fldname) { \ if (lfirst(lc) == NULL) \ appendStringInfoString(out, "{}"); \ else \ _outNode(out, lfirst(lc)); \ if (lnext(node->fldname, lc)) \ appendStringInfoString(out, ","); \ } \ appendStringInfo(out, "],"); \ } #define WRITE_NODE_FIELD(outname, outname_json, fldname) \ if (true) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":"); \ _outNode(out, &node->fldname); \ appendStringInfo(out, ","); \ } #define WRITE_NODE_PTR_FIELD(outname, outname_json, fldname) \ if (node->fldname != NULL) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":"); \ _outNode(out, node->fldname); \ appendStringInfo(out, ","); \ } #define WRITE_SPECIFIC_NODE_FIELD(typename, typename_underscore, outname, outname_json, fldname) \ { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":{"); \ _out##typename(out, &node->fldname); \ removeTrailingDelimiter(out); \ appendStringInfo(out, "},"); \ } #define WRITE_SPECIFIC_NODE_PTR_FIELD(typename, typename_underscore, outname, outname_json, fldname) \ if (node->fldname != NULL) { \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":{"); \ _out##typename(out, node->fldname); \ removeTrailingDelimiter(out); \ appendStringInfo(out, "},"); \ } #define WRITE_BITMAPSET_FIELD(outname, outname_json, fldname) \ if (!bms_is_empty(node->fldname)) \ { \ int x = 0; \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":["); \ while ((x = bms_next_member(node->fldname, x)) >= 0) \ appendStringInfo(out, "%d,", x); \ removeTrailingDelimiter(out); \ appendStringInfo(out, "],"); \ } static void _outNode(StringInfo out, const void *obj); static void _outList(StringInfo out, const List *node) { const ListCell *lc; appendStringInfo(out, "\"items\":"); appendStringInfoChar(out, '['); foreach(lc, node) { if (lfirst(lc) == NULL) appendStringInfoString(out, "{}"); else _outNode(out, lfirst(lc)); if (lnext(node, lc)) appendStringInfoString(out, ","); } appendStringInfoChar(out, ']'); appendStringInfo(out, ","); } static void _outIntList(StringInfo out, const List *node) { const ListCell *lc; appendStringInfo(out, "\"items\":"); appendStringInfoChar(out, '['); foreach(lc, node) { appendStringInfo(out, "%d", lfirst_int(lc)); if (lnext(node, lc)) appendStringInfoString(out, ","); } appendStringInfoChar(out, ']'); appendStringInfo(out, ","); } static void _outOidList(StringInfo out, const List *node) { const ListCell *lc; appendStringInfo(out, "\"items\":"); appendStringInfoChar(out, '['); foreach(lc, node) { appendStringInfo(out, "%u", lfirst_oid(lc)); if (lnext(node, lc)) appendStringInfoString(out, ","); } appendStringInfoChar(out, ']'); appendStringInfo(out, ","); } static void _outInteger(StringInfo out, const Integer *node) { /* Don't output anything if the value is the default (0), to match * protobuf's behavior. */ if (node->ival != 0) appendStringInfo(out, "\"ival\":%d", node->ival); } static void _outBoolean(StringInfo out, const Boolean *node) { appendStringInfo(out, "\"boolval\":%s", booltostr(node->boolval)); } static void _outFloat(StringInfo out, const Float *node) { appendStringInfo(out, "\"fval\":"); _outToken(out, node->fval); } static void _outString(StringInfo out, const String *node) { appendStringInfo(out, "\"sval\":"); _outToken(out, node->sval); } static void _outBitString(StringInfo out, const BitString *node) { appendStringInfo(out, "\"bsval\":"); _outToken(out, node->bsval); } static void _outAConst(StringInfo out, const A_Const *node) { if (node->isnull) { appendStringInfo(out, "\"isnull\":true"); } else { switch (node->val.node.type) { case T_Integer: appendStringInfoString(out, "\"ival\":{"); _outInteger(out, &node->val.ival); appendStringInfoChar(out, '}'); break; case T_Float: appendStringInfoString(out, "\"fval\":{"); _outFloat(out, &node->val.fval); appendStringInfoChar(out, '}'); break; case T_Boolean: appendStringInfo(out, "\"boolval\":{%s}", node->val.boolval.boolval ? "\"boolval\":true" : ""); break; case T_String: appendStringInfoString(out, "\"sval\":{"); _outString(out, &node->val.sval); appendStringInfoChar(out, '}'); break; case T_BitString: appendStringInfoString(out, "\"bsval\":{"); _outBitString(out, &node->val.bsval); appendStringInfoChar(out, '}'); break; // Unreachable, A_Const cannot contain any other nodes. default: Assert(false); } } appendStringInfo(out, ",\"location\":%d", node->location); } #include "pg_query_enum_defs.c" #include "pg_query_outfuncs_defs.c" static void _outNode(StringInfo out, const void *obj) { if (obj == NULL) { appendStringInfoString(out, "null"); } else { appendStringInfoChar(out, '{'); switch (nodeTag(obj)) { #include "pg_query_outfuncs_conds.c" default: elog(WARNING, "could not dump unrecognized node type: %d", (int) nodeTag(obj)); appendStringInfo(out, "}"); return; } removeTrailingDelimiter(out); appendStringInfo(out, "}}"); } } char * pg_query_node_to_json(const void *obj) { StringInfoData out; initStringInfo(&out); _outNode(&out, obj); return out.data; } char * pg_query_nodes_to_json(const void *obj) { StringInfoData out; const ListCell *lc; initStringInfo(&out); if (obj == NULL) /* Make sure we generate valid JSON for empty queries */ { appendStringInfo(&out, "{\"version\":%d,\"stmts\":[]}", PG_VERSION_NUM); } else { appendStringInfoString(&out, "{"); appendStringInfo(&out, "\"version\":%d,", PG_VERSION_NUM); appendStringInfoString(&out, "\"stmts\":"); appendStringInfoChar(&out, '['); foreach(lc, obj) { appendStringInfoChar(&out, '{'); _outRawStmt(&out, lfirst(lc)); removeTrailingDelimiter(&out); appendStringInfoChar(&out, '}'); if (lnext(obj, lc)) appendStringInfoString(&out, ","); } appendStringInfoChar(&out, ']'); appendStringInfoString(&out, "}"); } return out.data; }