diff --git a/src/pg_query_fingerprint.c b/src/pg_query_fingerprint.c index 8e15b821..0c77a856 100644 --- a/src/pg_query_fingerprint.c +++ b/src/pg_query_fingerprint.c @@ -5,6 +5,7 @@ #include "pg_query_fingerprint.h" #include "postgres.h" +#include "miscadmin.h" #include "xxhash/xxhash.h" #include "lib/ilist.h" @@ -263,6 +264,7 @@ _fingerprintFreeContext(FingerprintContext *ctx) { void _fingerprintNode(FingerprintContext *ctx, const void *obj, const void *parent, char *field_name, unsigned int depth) { + check_stack_depth(); // Some queries are overly complex in their parsetree - lets consistently cut them off at 100 nodes deep if (depth >= 100) { return; diff --git a/src/pg_query_json_plpgsql.c b/src/pg_query_json_plpgsql.c index ec5134bd..693a05ad 100644 --- a/src/pg_query_json_plpgsql.c +++ b/src/pg_query_json_plpgsql.c @@ -1,4 +1,6 @@ #include "pg_query.h" +#include "postgres.h" +#include "miscadmin.h" #include "pg_query_json_plpgsql.h" #include "pg_query_json_helper.c" @@ -138,6 +140,7 @@ static void dump_type(StringInfo out, PLpgSQL_type *node); static void dump_stmt(StringInfo out, PLpgSQL_stmt *node) { + check_stack_depth(); appendStringInfoChar(out, '{'); switch (node->cmd_type) { @@ -627,6 +630,7 @@ dump_getdiag_item(StringInfo out, PLpgSQL_diag_item *node) static void dump_expr(StringInfo out, PLpgSQL_expr *node) { + check_stack_depth(); WRITE_NODE_TYPE("PLpgSQL_expr"); WRITE_STRING_FIELD(query, query, query); @@ -812,7 +816,10 @@ pg_query_plpgsql_reset_aliases(void) int i; for (i = 0; i < plpgsql_naliases; i++) free(plpgsql_aliases[i].name); + free(plpgsql_aliases); + plpgsql_aliases = NULL; plpgsql_naliases = 0; + plpgsql_aliases_size = 0; } void diff --git a/src/pg_query_outfuncs_json.c b/src/pg_query_outfuncs_json.c index e5025ed6..0801ed47 100644 --- a/src/pg_query_outfuncs_json.c +++ b/src/pg_query_outfuncs_json.c @@ -1,6 +1,7 @@ #include "pg_query_outfuncs.h" #include "postgres.h" +#include "miscadmin.h" #include @@ -289,6 +290,7 @@ _outAConst(StringInfo out, const A_Const *node) static void _outNode(StringInfo out, const void *obj) { + check_stack_depth(); if (obj == NULL) { appendStringInfoString(out, "null"); diff --git a/src/pg_query_outfuncs_protobuf.c b/src/pg_query_outfuncs_protobuf.c index 64ccdf1b..c7bcd34a 100644 --- a/src/pg_query_outfuncs_protobuf.c +++ b/src/pg_query_outfuncs_protobuf.c @@ -1,6 +1,7 @@ #include "pg_query_outfuncs.h" #include "postgres.h" +#include "miscadmin.h" #include #include "access/relation.h" #include "nodes/parsenodes.h" @@ -246,6 +247,7 @@ _outAConst(PgQuery__AConst* out, const A_Const *node) static void _outNode(PgQuery__Node* out, const void *obj) { + check_stack_depth(); if (obj == NULL) return; // Keep out as NULL diff --git a/src/pg_query_parse.c b/src/pg_query_parse.c index 3f2c111a..60077bbf 100644 --- a/src/pg_query_parse.c +++ b/src/pg_query_parse.c @@ -135,9 +135,39 @@ PgQueryParseResult pg_query_parse_opts(const char* input, int parser_options) result.stderr_buffer = parsetree_and_error.stderr_buffer; result.error = parsetree_and_error.error; - tree_json = pg_query_nodes_to_json(parsetree_and_error.tree); - result.parse_tree = strdup(tree_json); - pfree(tree_json); + if (result.error == NULL) + { + PG_TRY(); + { + tree_json = pg_query_nodes_to_json(parsetree_and_error.tree); + result.parse_tree = strdup(tree_json); + pfree(tree_json); + } + PG_CATCH(); + { + ErrorData* error_data; + PgQueryError* error; + + MemoryContextSwitchTo(ctx); + error_data = CopyErrorData(); + error = malloc(sizeof(PgQueryError)); + error->message = strdup(error_data->message); + error->filename = strdup(error_data->filename); + error->funcname = strdup(error_data->funcname); + error->context = NULL; + error->lineno = error_data->lineno; + error->cursorpos = error_data->cursorpos; + result.error = error; + FlushErrorState(); + } + PG_END_TRY(); + } + else + { + tree_json = pg_query_nodes_to_json(parsetree_and_error.tree); + result.parse_tree = strdup(tree_json); + pfree(tree_json); + } pg_query_exit_memory_context(ctx); diff --git a/src/pg_query_parse_plpgsql.c b/src/pg_query_parse_plpgsql.c index 79402515..ca46f85f 100644 --- a/src/pg_query_parse_plpgsql.c +++ b/src/pg_query_parse_plpgsql.c @@ -671,6 +671,8 @@ PgQueryPlpgsqlParseResult pg_query_parse_plpgsql(const char* input) result.plpgsql_funcs[strlen(result.plpgsql_funcs) - 1] = ']'; free(parse_result.stderr_buffer); + /* Drop the aliases recorded during this compile so nothing outlives the call */ + pg_query_plpgsql_reset_aliases(); pg_query_exit_memory_context(ctx); return result; diff --git a/src/postgres/src_backend_utils_misc_stack_depth.c b/src/postgres/src_backend_utils_misc_stack_depth.c index b1b6690f..eecb6b28 100644 --- a/src/postgres/src_backend_utils_misc_stack_depth.c +++ b/src/postgres/src_backend_utils_misc_stack_depth.c @@ -146,3 +146,14 @@ stack_is_too_deep(void) #if defined(HAVE_GETRLIMIT) #else #endif + +/* libpg-query-node: set the stack-depth reference point and limit from the embedder. */ +void +pg_query_set_stack_limit(size_t bytes) +{ + char here; + + stack_base_ptr = &here; + max_stack_depth_bytes = (ssize_t) bytes; + max_stack_depth = (int) (bytes / 1024); +} diff --git a/src/postgres_deparse.c b/src/postgres_deparse.c index e2bdf87d..15fd2466 100644 --- a/src/postgres_deparse.c +++ b/src/postgres_deparse.c @@ -1,6 +1,7 @@ #include "postgres_deparse.h" #include "postgres.h" +#include "miscadmin.h" #include "catalog/index.h" #include "catalog/pg_am.h" #include "catalog/pg_attribute.h" @@ -784,6 +785,7 @@ static void deparseCExpr(DeparseState *state, Node *node); // "a_expr" in gram.y static void deparseExpr(DeparseState *state, Node *node, DeparseNodeContext context) { + check_stack_depth(); if (node == NULL) return; switch (nodeTag(node))