#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 "protobuf/pg_query.pb-c.h" #define OUT_TYPE(typename, typename_c) PgQuery__##typename_c* #define OUT_NODE(typename, typename_c, typename_underscore, typename_underscore_upcase, typename_cast, fldname) \ { \ PgQuery__##typename_c *__node = palloc(sizeof(PgQuery__##typename_c)); \ pg_query__##typename_underscore##__init(__node); \ _out##typename_c(__node, (const typename_cast *) obj); \ out->fldname = __node; \ out->node_case = PG_QUERY__NODE__NODE_##typename_underscore_upcase; \ } #define WRITE_INT_FIELD(outname, outname_json, fldname) out->outname = node->fldname; #define WRITE_UINT_FIELD(outname, outname_json, fldname) out->outname = node->fldname; #define WRITE_UINT64_FIELD(outname, outname_json, fldname) out->outname = node->fldname; #define WRITE_LONG_FIELD(outname, outname_json, fldname) out->outname = node->fldname; #define WRITE_FLOAT_FIELD(outname, outname_json, fldname) out->outname = node->fldname; #define WRITE_BOOL_FIELD(outname, outname_json, fldname) out->outname = node->fldname; #define WRITE_CHAR_FIELD(outname, outname_json, fldname) \ if (node->fldname != 0) { \ out->outname = palloc(sizeof(char) * 2); \ out->outname[0] = node->fldname; \ out->outname[1] = '\0'; \ } #define WRITE_STRING_FIELD(outname, outname_json, fldname) \ if (node->fldname != NULL) { \ out->outname = pstrdup(node->fldname); \ } #define WRITE_ENUM_FIELD(typename, outname, outname_json, fldname) \ out->outname = _enumToInt##typename(node->fldname); #define WRITE_LIST_FIELD(outname, outname_json, fldname) \ if (node->fldname != NULL) { \ out->n_##outname = list_length(node->fldname); \ out->outname = palloc(sizeof(PgQuery__Node*) * out->n_##outname); \ for (int i = 0; i < out->n_##outname; i++) \ { \ PgQuery__Node *__node = palloc(sizeof(PgQuery__Node)); \ pg_query__node__init(__node); \ out->outname[i] = __node; \ _outNode(out->outname[i], list_nth(node->fldname, i)); \ } \ } #define WRITE_BITMAPSET_FIELD(outname, outname_json, fldname) \ if (!bms_is_empty(node->fldname)) \ { \ int x = -1; \ int i = 0; \ out->n_##outname = bms_num_members(node->fldname); \ out->outname = palloc(sizeof(PgQuery__Node*) * out->n_##outname); \ while ((x = bms_next_member(node->fldname, x)) >= 0) \ out->outname[i++] = x; \ } #define WRITE_NODE_FIELD(outname, outname_json, fldname) \ { \ PgQuery__Node *__node = palloc(sizeof(PgQuery__Node)); \ pg_query__node__init(__node); \ out->outname = __node; \ _outNode(out->outname, &node->fldname); \ } #define WRITE_NODE_PTR_FIELD(outname, outname_json, fldname) \ if (node->fldname != NULL) { \ PgQuery__Node *__node = palloc(sizeof(PgQuery__Node)); \ pg_query__node__init(__node); \ out->outname = __node; \ _outNode(out->outname, node->fldname); \ } #define WRITE_SPECIFIC_NODE_FIELD(typename, typename_underscore, outname, outname_json, fldname) \ { \ PgQuery__##typename *__node = palloc(sizeof(PgQuery__##typename)); \ pg_query__##typename_underscore##__init(__node); \ _out##typename(__node, &node->fldname); \ out->outname = __node; \ } #define WRITE_SPECIFIC_NODE_PTR_FIELD(typename, typename_underscore, outname, outname_json, fldname) \ if (node->fldname != NULL) { \ PgQuery__##typename *__node = palloc(sizeof(PgQuery__##typename)); \ pg_query__##typename_underscore##__init(__node); \ _out##typename(__node, node->fldname); \ out->outname = __node; \ } static void _outNode(PgQuery__Node* out, const void *obj); static void _outList(PgQuery__List* out, const List *node) { const ListCell *lc; int i = 0; out->n_items = list_length(node); out->items = palloc(sizeof(PgQuery__Node*) * out->n_items); foreach(lc, node) { out->items[i] = palloc(sizeof(PgQuery__Node)); pg_query__node__init(out->items[i]); _outNode(out->items[i], lfirst(lc)); i++; } } static void _outIntList(PgQuery__IntList* out, const List *node) { const ListCell *lc; int i = 0; out->n_items = list_length(node); out->items = palloc(sizeof(PgQuery__Node*) * out->n_items); foreach(lc, node) { out->items[i] = palloc(sizeof(PgQuery__Node)); pg_query__node__init(out->items[i]); _outNode(out->items[i], lfirst(lc)); i++; } } static void _outOidList(PgQuery__OidList* out, const List *node) { const ListCell *lc; int i = 0; out->n_items = list_length(node); out->items = palloc(sizeof(PgQuery__Node*) * out->n_items); foreach(lc, node) { out->items[i] = palloc(sizeof(PgQuery__Node)); pg_query__node__init(out->items[i]); _outNode(out->items[i], lfirst(lc)); i++; } } // TODO: Add Bitmapset static void _outInteger(PgQuery__Integer* out, const Integer *node) { out->ival = node->ival; } static void _outFloat(PgQuery__Float* out, const Float *node) { out->fval = node->fval; } static void _outBoolean(PgQuery__Boolean* out, const Boolean *node) { out->boolval = node->boolval; } static void _outString(PgQuery__String* out, const String *node) { out->sval = node->sval; } static void _outBitString(PgQuery__BitString* out, const BitString *node) { out->bsval = node->bsval; } static void _outAConst(PgQuery__AConst* out, const A_Const *node) { out->isnull = node->isnull; out->location = node->location; if (!node->isnull) { switch (nodeTag(&node->val.node)) { case T_Integer: { PgQuery__Integer *value = palloc(sizeof(PgQuery__Integer)); pg_query__integer__init(value); value->ival = node->val.ival.ival; out->val_case = PG_QUERY__A__CONST__VAL_IVAL; out->ival = value; break; } case T_Float: { PgQuery__Float *value = palloc(sizeof(PgQuery__Float)); pg_query__float__init(value); value->fval = pstrdup(node->val.fval.fval); out->val_case = PG_QUERY__A__CONST__VAL_FVAL; out->fval = value; break; } case T_Boolean: { PgQuery__Boolean *value = palloc(sizeof(PgQuery__Boolean)); pg_query__boolean__init(value); value->boolval = node->val.boolval.boolval; out->val_case = PG_QUERY__A__CONST__VAL_BOOLVAL; out->boolval = value; break; } case T_String: { PgQuery__String *value = palloc(sizeof(PgQuery__String)); pg_query__string__init(value); value->sval = pstrdup(node->val.sval.sval); out->val_case = PG_QUERY__A__CONST__VAL_SVAL; out->sval = value; break; } case T_BitString: { PgQuery__BitString *value = palloc(sizeof(PgQuery__BitString)); pg_query__bit_string__init(value); value->bsval = pstrdup(node->val.bsval.bsval); out->val_case = PG_QUERY__A__CONST__VAL_BSVAL; out->bsval = value; break; } default: // Unreachable Assert(false); } } } #include "pg_query_enum_defs.c" #include "pg_query_outfuncs_defs.c" static void _outNode(PgQuery__Node* out, const void *obj) { if (obj == NULL) return; // Keep out as NULL switch (nodeTag(obj)) { #include "pg_query_outfuncs_conds.c" default: printf("could not dump unrecognized node type: %d", (int) nodeTag(obj)); elog(WARNING, "could not dump unrecognized node type: %d", (int) nodeTag(obj)); return; } } PgQueryProtobuf pg_query_nodes_to_protobuf(const void *obj) { PgQueryProtobuf protobuf; const ListCell *lc; int i = 0; PgQuery__ParseResult parse_result = PG_QUERY__PARSE_RESULT__INIT; parse_result.version = PG_VERSION_NUM; if (obj == NULL) { parse_result.n_stmts = 0; parse_result.stmts = NULL; } else { parse_result.n_stmts = list_length(obj); parse_result.stmts = palloc(sizeof(PgQuery__RawStmt*) * parse_result.n_stmts); foreach(lc, obj) { parse_result.stmts[i] = palloc(sizeof(PgQuery__RawStmt)); pg_query__raw_stmt__init(parse_result.stmts[i]); _outRawStmt(parse_result.stmts[i], lfirst(lc)); i++; } } protobuf.len = pg_query__parse_result__get_packed_size(&parse_result); // Note: This is intentionally malloc so exiting the memory context doesn't free this protobuf.data = malloc(sizeof(char) * protobuf.len); pg_query__parse_result__pack(&parse_result, (void*) protobuf.data); return protobuf; }