#include "pg_query.h" #include "pg_query_json_plpgsql.h" #include "pg_query_json_helper.c" /* 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 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 an enumerated-type field as an integer code */ #define WRITE_ENUM_FIELD(outname, outname_json, fldname) \ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%d,", \ (int) 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_INT_VALUE(fldname, value) \ if (value != 0) { \ appendStringInfo(out, "\"" CppAsString(fldname) "\":%d,", value); \ } #define WRITE_STRING_VALUE(fldname, value) \ if (true) { \ appendStringInfo(out, "\"" CppAsString(fldname) "\":"); \ _outToken(out, value); \ appendStringInfo(out, ","); \ } #define WRITE_OBJ_FIELD(fldname, outfunc) \ if (node->fldname != NULL) { \ appendStringInfo(out, "\"" CppAsString(fldname) "\":{"); \ outfunc(out, node->fldname); \ removeTrailingDelimiter(out); \ appendStringInfo(out, "}},"); \ } #define WRITE_LIST_FIELD(fldname, fldtype, outfunc) \ if (node->fldname != NULL) { \ ListCell *lc; \ appendStringInfo(out, "\"" CppAsString(fldname) "\":["); \ foreach(lc, node->fldname) { \ appendStringInfoString(out, "{"); \ outfunc(out, (fldtype *) lfirst(lc)); \ removeTrailingDelimiter(out); \ appendStringInfoString(out, "}},"); \ } \ removeTrailingDelimiter(out); \ appendStringInfoString(out, "],"); \ } #define WRITE_STATEMENTS_FIELD(fldname) \ if (node->fldname != NULL) { \ ListCell *lc; \ appendStringInfo(out, "\"" CppAsString(fldname) "\":["); \ foreach(lc, node->fldname) { \ dump_stmt(out, (PLpgSQL_stmt *) lfirst(lc)); \ } \ removeTrailingDelimiter(out); \ appendStringInfoString(out, "],"); \ } #define WRITE_EXPR_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_expr) #define WRITE_BLOCK_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_block) #define WRITE_RECORD_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_record) #define WRITE_ROW_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_row) #define WRITE_VAR_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_var) #define WRITE_VARIABLE_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_variable); static void dump_record(StringInfo out, PLpgSQL_rec *stmt); static void dump_row(StringInfo out, PLpgSQL_row *stmt); static void dump_var(StringInfo out, PLpgSQL_var *stmt); static void dump_variable(StringInfo out, PLpgSQL_variable *stmt); static void dump_record_field(StringInfo out, PLpgSQL_recfield *node); static void dump_stmt(StringInfo out, PLpgSQL_stmt *stmt); static void dump_block(StringInfo out, PLpgSQL_stmt_block *block); static void dump_exception_block(StringInfo out, PLpgSQL_exception_block *node); static void dump_assign(StringInfo out, PLpgSQL_stmt_assign *stmt); static void dump_if(StringInfo out, PLpgSQL_stmt_if *stmt); static void dump_if_elsif(StringInfo out, PLpgSQL_if_elsif *node); static void dump_case(StringInfo out, PLpgSQL_stmt_case *stmt); static void dump_case_when(StringInfo out, PLpgSQL_case_when *node); static void dump_loop(StringInfo out, PLpgSQL_stmt_loop *stmt); static void dump_while(StringInfo out, PLpgSQL_stmt_while *stmt); static void dump_fori(StringInfo out, PLpgSQL_stmt_fori *stmt); static void dump_fors(StringInfo out, PLpgSQL_stmt_fors *stmt); static void dump_forc(StringInfo out, PLpgSQL_stmt_forc *stmt); static void dump_foreach_a(StringInfo out, PLpgSQL_stmt_foreach_a *stmt); static void dump_exit(StringInfo out, PLpgSQL_stmt_exit *stmt); static void dump_return(StringInfo out, PLpgSQL_stmt_return *stmt); static void dump_return_next(StringInfo out, PLpgSQL_stmt_return_next *stmt); static void dump_return_query(StringInfo out, PLpgSQL_stmt_return_query *stmt); static void dump_raise(StringInfo out, PLpgSQL_stmt_raise *stmt); static void dump_raise_option(StringInfo out, PLpgSQL_raise_option *node); static void dump_assert(StringInfo out, PLpgSQL_stmt_assert *stmt); static void dump_execsql(StringInfo out, PLpgSQL_stmt_execsql *stmt); static void dump_dynexecute(StringInfo out, PLpgSQL_stmt_dynexecute *stmt); static void dump_dynfors(StringInfo out, PLpgSQL_stmt_dynfors *stmt); static void dump_getdiag(StringInfo out, PLpgSQL_stmt_getdiag *stmt); static void dump_getdiag_item(StringInfo out, PLpgSQL_diag_item *node); static void dump_open(StringInfo out, PLpgSQL_stmt_open *stmt); static void dump_fetch(StringInfo out, PLpgSQL_stmt_fetch *stmt); static void dump_close(StringInfo out, PLpgSQL_stmt_close *stmt); static void dump_perform(StringInfo out, PLpgSQL_stmt_perform *stmt); static void dump_call(StringInfo out, PLpgSQL_stmt_call *stmt); static void dump_commit(StringInfo out, PLpgSQL_stmt_commit *stmt); static void dump_rollback(StringInfo out, PLpgSQL_stmt_rollback *stmt); static void dump_expr(StringInfo out, PLpgSQL_expr *expr); static void dump_function(StringInfo out, PLpgSQL_function *func); static void dump_exception(StringInfo out, PLpgSQL_exception *node); static void dump_condition(StringInfo out, PLpgSQL_condition *node); static void dump_type(StringInfo out, PLpgSQL_type *node); static void dump_stmt(StringInfo out, PLpgSQL_stmt *node) { appendStringInfoChar(out, '{'); switch (node->cmd_type) { case PLPGSQL_STMT_BLOCK: dump_block(out, (PLpgSQL_stmt_block *) node); break; case PLPGSQL_STMT_ASSIGN: dump_assign(out, (PLpgSQL_stmt_assign *) node); break; case PLPGSQL_STMT_IF: dump_if(out, (PLpgSQL_stmt_if *) node); break; case PLPGSQL_STMT_CASE: dump_case(out, (PLpgSQL_stmt_case *) node); break; case PLPGSQL_STMT_LOOP: dump_loop(out, (PLpgSQL_stmt_loop *) node); break; case PLPGSQL_STMT_WHILE: dump_while(out, (PLpgSQL_stmt_while *) node); break; case PLPGSQL_STMT_FORI: dump_fori(out, (PLpgSQL_stmt_fori *) node); break; case PLPGSQL_STMT_FORS: dump_fors(out, (PLpgSQL_stmt_fors *) node); break; case PLPGSQL_STMT_FORC: dump_forc(out, (PLpgSQL_stmt_forc *) node); break; case PLPGSQL_STMT_FOREACH_A: dump_foreach_a(out, (PLpgSQL_stmt_foreach_a *) node); break; case PLPGSQL_STMT_EXIT: dump_exit(out, (PLpgSQL_stmt_exit *) node); break; case PLPGSQL_STMT_RETURN: dump_return(out, (PLpgSQL_stmt_return *) node); break; case PLPGSQL_STMT_RETURN_NEXT: dump_return_next(out, (PLpgSQL_stmt_return_next *) node); break; case PLPGSQL_STMT_RETURN_QUERY: dump_return_query(out, (PLpgSQL_stmt_return_query *) node); break; case PLPGSQL_STMT_RAISE: dump_raise(out, (PLpgSQL_stmt_raise *) node); break; case PLPGSQL_STMT_ASSERT: dump_assert(out, (PLpgSQL_stmt_assert *) node); break; case PLPGSQL_STMT_EXECSQL: dump_execsql(out, (PLpgSQL_stmt_execsql *) node); break; case PLPGSQL_STMT_DYNEXECUTE: dump_dynexecute(out, (PLpgSQL_stmt_dynexecute *) node); break; case PLPGSQL_STMT_DYNFORS: dump_dynfors(out, (PLpgSQL_stmt_dynfors *) node); break; case PLPGSQL_STMT_GETDIAG: dump_getdiag(out, (PLpgSQL_stmt_getdiag *) node); break; case PLPGSQL_STMT_OPEN: dump_open(out, (PLpgSQL_stmt_open *) node); break; case PLPGSQL_STMT_FETCH: dump_fetch(out, (PLpgSQL_stmt_fetch *) node); break; case PLPGSQL_STMT_CLOSE: dump_close(out, (PLpgSQL_stmt_close *) node); break; case PLPGSQL_STMT_PERFORM: dump_perform(out, (PLpgSQL_stmt_perform *) node); break; case PLPGSQL_STMT_CALL: dump_call(out, (PLpgSQL_stmt_call *) node); break; case PLPGSQL_STMT_COMMIT: dump_commit(out, (PLpgSQL_stmt_commit *) node); break; case PLPGSQL_STMT_ROLLBACK: dump_rollback(out, (PLpgSQL_stmt_rollback *) node); break; default: elog(ERROR, "unrecognized cmd_type: %d", node->cmd_type); break; } removeTrailingDelimiter(out); appendStringInfoString(out, "}},"); } static void dump_block(StringInfo out, PLpgSQL_stmt_block *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_block"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_STRING_FIELD(label, label, label); WRITE_STATEMENTS_FIELD(body); WRITE_OBJ_FIELD(exceptions, dump_exception_block); removeTrailingDelimiter(out); } static void dump_exception_block(StringInfo out, PLpgSQL_exception_block *node) { WRITE_NODE_TYPE("PLpgSQL_exception_block"); WRITE_LIST_FIELD(exc_list, PLpgSQL_exception, dump_exception); } static void dump_exception(StringInfo out, PLpgSQL_exception *node) { PLpgSQL_condition *cond; WRITE_NODE_TYPE("PLpgSQL_exception"); appendStringInfo(out, "\"conditions\":["); for (cond = node->conditions; cond; cond = cond->next) { appendStringInfoString(out, "{"); dump_condition(out, cond); removeTrailingDelimiter(out); appendStringInfoString(out, "}},"); } removeTrailingDelimiter(out); appendStringInfoString(out, "],"); WRITE_STATEMENTS_FIELD(action); } static void dump_condition(StringInfo out, PLpgSQL_condition *node) { WRITE_NODE_TYPE("PLpgSQL_condition"); WRITE_STRING_FIELD(condname, condname, condname); } static void dump_assign(StringInfo out, PLpgSQL_stmt_assign *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_assign"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_INT_FIELD(varno, varno, varno); WRITE_EXPR_FIELD(expr); } static void dump_if(StringInfo out, PLpgSQL_stmt_if *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_if"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(cond); WRITE_STATEMENTS_FIELD(then_body); WRITE_LIST_FIELD(elsif_list, PLpgSQL_if_elsif, dump_if_elsif); WRITE_STATEMENTS_FIELD(else_body); } static void dump_if_elsif(StringInfo out, PLpgSQL_if_elsif *node) { WRITE_NODE_TYPE("PLpgSQL_if_elsif"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(cond); WRITE_STATEMENTS_FIELD(stmts); } static void dump_case(StringInfo out, PLpgSQL_stmt_case *node) { ListCell *l; WRITE_NODE_TYPE("PLpgSQL_stmt_case"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(t_expr); WRITE_INT_FIELD(t_varno, t_varno, t_varno); WRITE_LIST_FIELD(case_when_list, PLpgSQL_case_when, dump_case_when); WRITE_BOOL_FIELD(have_else, have_else, have_else); WRITE_STATEMENTS_FIELD(else_stmts); } static void dump_case_when(StringInfo out, PLpgSQL_case_when *node) { WRITE_NODE_TYPE("PLpgSQL_case_when"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(expr); WRITE_STATEMENTS_FIELD(stmts); } static void dump_loop(StringInfo out, PLpgSQL_stmt_loop *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_loop"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_STRING_FIELD(label, label, label); WRITE_STATEMENTS_FIELD(body); } static void dump_while(StringInfo out, PLpgSQL_stmt_while *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_while"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_STRING_FIELD(label, label, label); WRITE_EXPR_FIELD(cond); WRITE_STATEMENTS_FIELD(body); } /* FOR statement with integer loopvar */ static void dump_fori(StringInfo out, PLpgSQL_stmt_fori *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_fori"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_STRING_FIELD(label, label, label); WRITE_VAR_FIELD(var); WRITE_EXPR_FIELD(lower); WRITE_EXPR_FIELD(upper); WRITE_EXPR_FIELD(step); WRITE_BOOL_FIELD(reverse, reverse, reverse); WRITE_STATEMENTS_FIELD(body); } static void dump_fors(StringInfo out, PLpgSQL_stmt_fors *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_fors"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_STRING_FIELD(label, label, label); WRITE_VARIABLE_FIELD(var); WRITE_STATEMENTS_FIELD(body); WRITE_EXPR_FIELD(query); } static void dump_forc(StringInfo out, PLpgSQL_stmt_forc *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_forc"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_STRING_FIELD(label, label, label); WRITE_VARIABLE_FIELD(var); WRITE_STATEMENTS_FIELD(body); WRITE_INT_FIELD(curvar, curvar, curvar); WRITE_EXPR_FIELD(argquery); } static void dump_foreach_a(StringInfo out, PLpgSQL_stmt_foreach_a *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_foreach_a"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_STRING_FIELD(label, label, label); WRITE_INT_FIELD(varno, varno, varno); WRITE_INT_FIELD(slice, slice, slice); WRITE_EXPR_FIELD(expr); WRITE_STATEMENTS_FIELD(body); } static void dump_open(StringInfo out, PLpgSQL_stmt_open *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_open"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_INT_FIELD(curvar, curvar, curvar); WRITE_INT_FIELD(cursor_options, cursor_options, cursor_options); WRITE_EXPR_FIELD(argquery); WRITE_EXPR_FIELD(query); WRITE_EXPR_FIELD(dynquery); WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr); } static void dump_fetch(StringInfo out, PLpgSQL_stmt_fetch *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_fetch"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_VARIABLE_FIELD(target); WRITE_INT_FIELD(curvar, curvar, curvar); WRITE_ENUM_FIELD(direction, direction, direction); WRITE_LONG_FIELD(how_many, how_many, how_many); WRITE_EXPR_FIELD(expr); WRITE_BOOL_FIELD(is_move, is_move, is_move); WRITE_BOOL_FIELD(returns_multiple_rows, returns_multiple_rows, returns_multiple_rows); } static void dump_close(StringInfo out, PLpgSQL_stmt_close *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_close"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_INT_FIELD(curvar, curvar, curvar); } static void dump_perform(StringInfo out, PLpgSQL_stmt_perform *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_perform"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(expr); } static void dump_call(StringInfo out, PLpgSQL_stmt_call *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_call"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(expr); WRITE_BOOL_FIELD(is_call, is_call, is_call); WRITE_VARIABLE_FIELD(target); } static void dump_commit(StringInfo out, PLpgSQL_stmt_commit *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_commit"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_BOOL_FIELD(chain, chain, chain); } static void dump_rollback(StringInfo out, PLpgSQL_stmt_rollback *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_rollback"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_BOOL_FIELD(chain, chain, chain); } static void dump_exit(StringInfo out, PLpgSQL_stmt_exit *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_exit"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_BOOL_FIELD(is_exit, is_exit, is_exit); WRITE_STRING_FIELD(label, label, label); WRITE_EXPR_FIELD(cond); } static void dump_return(StringInfo out, PLpgSQL_stmt_return *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_return"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(expr); //WRITE_INT_FIELD(retvarno); } static void dump_return_next(StringInfo out, PLpgSQL_stmt_return_next *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_return_next"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(expr); //WRITE_INT_FIELD(retvarno); } static void dump_return_query(StringInfo out, PLpgSQL_stmt_return_query *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_return_query"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(query); WRITE_EXPR_FIELD(dynquery); WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr); } static void dump_raise(StringInfo out, PLpgSQL_stmt_raise *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_raise"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_INT_FIELD(elog_level, elog_level, elog_level); WRITE_STRING_FIELD(condname, condname, condname); WRITE_STRING_FIELD(message, message, message); WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr); WRITE_LIST_FIELD(options, PLpgSQL_raise_option, dump_raise_option); } static void dump_raise_option(StringInfo out, PLpgSQL_raise_option *node) { WRITE_NODE_TYPE("PLpgSQL_raise_option"); WRITE_ENUM_FIELD(opt_type, opt_type, opt_type); WRITE_EXPR_FIELD(expr); } static void dump_assert(StringInfo out, PLpgSQL_stmt_assert *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_assert"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(cond); WRITE_EXPR_FIELD(message); } static void dump_execsql(StringInfo out, PLpgSQL_stmt_execsql *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_execsql"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(sqlstmt); //WRITE_BOOL_FIELD(mod_stmt); // This is only populated when executing the function WRITE_BOOL_FIELD(into, into, into); WRITE_BOOL_FIELD(strict, strict, strict); WRITE_VARIABLE_FIELD(target); } static void dump_dynexecute(StringInfo out, PLpgSQL_stmt_dynexecute *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_dynexecute"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_EXPR_FIELD(query); WRITE_BOOL_FIELD(into, into, into); WRITE_BOOL_FIELD(strict, strict, strict); WRITE_VARIABLE_FIELD(target); WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr); } static void dump_dynfors(StringInfo out, PLpgSQL_stmt_dynfors *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_dynfors"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_STRING_FIELD(label, label, label); WRITE_VARIABLE_FIELD(var); WRITE_STATEMENTS_FIELD(body); WRITE_EXPR_FIELD(query); WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr); } static void dump_getdiag(StringInfo out, PLpgSQL_stmt_getdiag *node) { WRITE_NODE_TYPE("PLpgSQL_stmt_getdiag"); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_BOOL_FIELD(is_stacked, is_stacked, is_stacked); WRITE_LIST_FIELD(diag_items, PLpgSQL_diag_item, dump_getdiag_item); } static void dump_getdiag_item(StringInfo out, PLpgSQL_diag_item *node) { WRITE_NODE_TYPE("PLpgSQL_diag_item"); WRITE_STRING_VALUE(kind, plpgsql_getdiag_kindname(node->kind)); WRITE_INT_FIELD(target, target, target); } static void dump_expr(StringInfo out, PLpgSQL_expr *node) { WRITE_NODE_TYPE("PLpgSQL_expr"); WRITE_STRING_FIELD(query, query, query); WRITE_ENUM_FIELD(parseMode, parseMode, parseMode); } static void dump_function(StringInfo out, PLpgSQL_function *node) { int i; PLpgSQL_datum *d; WRITE_NODE_TYPE("PLpgSQL_function"); WRITE_INT_FIELD(new_varno, new_varno, new_varno); WRITE_INT_FIELD(old_varno, old_varno, old_varno); appendStringInfoString(out, "\"datums\":"); appendStringInfoChar(out, '['); for (i = 0; i < node->ndatums; i++) { appendStringInfoChar(out, '{'); d = node->datums[i]; switch (d->dtype) { case PLPGSQL_DTYPE_VAR: dump_var(out, (PLpgSQL_var *) d); break; case PLPGSQL_DTYPE_ROW: dump_row(out, (PLpgSQL_row *) d); break; case PLPGSQL_DTYPE_REC: dump_record(out, (PLpgSQL_rec *) d); break; case PLPGSQL_DTYPE_RECFIELD: dump_record_field(out, (PLpgSQL_recfield *) d); break; default: elog(WARNING, "could not dump unrecognized dtype: %d", (int) d->dtype); } removeTrailingDelimiter(out); appendStringInfoString(out, "}},"); } removeTrailingDelimiter(out); appendStringInfoString(out, "],"); WRITE_BLOCK_FIELD(action); } static void dump_var(StringInfo out, PLpgSQL_var *node) { WRITE_NODE_TYPE("PLpgSQL_var"); WRITE_STRING_FIELD(refname, refname, refname); WRITE_INT_FIELD(lineno, lineno, lineno); WRITE_OBJ_FIELD(datatype, dump_type); WRITE_BOOL_FIELD(isconst, isconst, isconst); WRITE_BOOL_FIELD(notnull, notnull, notnull); WRITE_EXPR_FIELD(default_val); WRITE_EXPR_FIELD(cursor_explicit_expr); WRITE_INT_FIELD(cursor_explicit_argrow, cursor_explicit_argrow, cursor_explicit_argrow); WRITE_INT_FIELD(cursor_options, cursor_options, cursor_options); } static void dump_variable(StringInfo out, PLpgSQL_variable *node) { switch (node->dtype) { case PLPGSQL_DTYPE_REC: dump_record(out, (PLpgSQL_rec *) node); break; case PLPGSQL_DTYPE_VAR: dump_var(out, (PLpgSQL_var *) node); break; case PLPGSQL_DTYPE_ROW: dump_row(out, (PLpgSQL_row *) node); break; default: elog(ERROR, "unrecognized variable type: %d", node->dtype); break; } } static void dump_type(StringInfo out, PLpgSQL_type *node) { WRITE_NODE_TYPE("PLpgSQL_type"); WRITE_STRING_FIELD(typname, typname, typname); } static void dump_row(StringInfo out, PLpgSQL_row *node) { int i = 0; WRITE_NODE_TYPE("PLpgSQL_row"); WRITE_STRING_FIELD(refname, refname, refname); WRITE_INT_FIELD(lineno, lineno, lineno); appendStringInfoString(out, "\"fields\":"); appendStringInfoChar(out, '['); for (i = 0; i < node->nfields; i++) { if (node->fieldnames[i]) { appendStringInfoChar(out, '{'); WRITE_STRING_VALUE(name, node->fieldnames[i]); WRITE_INT_VALUE(varno, node->varnos[i]); removeTrailingDelimiter(out); appendStringInfoString(out, "},"); } else { appendStringInfoString(out, "null,"); } } removeTrailingDelimiter(out); appendStringInfoString(out, "],"); } static void dump_record(StringInfo out, PLpgSQL_rec *node) { WRITE_NODE_TYPE("PLpgSQL_rec"); WRITE_STRING_FIELD(refname, refname, refname); WRITE_INT_FIELD(dno, dno, dno); WRITE_INT_FIELD(lineno, lineno, lineno); } static void dump_record_field(StringInfo out, PLpgSQL_recfield *node) { WRITE_NODE_TYPE("PLpgSQL_recfield"); WRITE_STRING_FIELD(fieldname, fieldname, fieldname); WRITE_INT_FIELD(recparentno, recparentno, recparentno); } char * plpgsqlToJSON(PLpgSQL_function *func) { StringInfoData str; initStringInfo(&str); appendStringInfoChar(&str, '{'); dump_function(&str, func); removeTrailingDelimiter(&str); appendStringInfoString(&str, "}}"); return str.data; }