in ext/pg_query/pg_query_parse_plpgsql.c [379:451]
PgQueryPlpgsqlParseResult pg_query_parse_plpgsql(const char* input)
{
MemoryContext ctx = NULL;
PgQueryPlpgsqlParseResult result = {0};
PgQueryInternalParsetreeAndError parse_result;
createFunctionStmts statements;
size_t i;
ctx = pg_query_enter_memory_context();
parse_result = pg_query_raw_parse(input);
result.error = parse_result.error;
if (result.error != NULL) {
pg_query_exit_memory_context(ctx);
return result;
}
statements.stmts_buf_size = 100;
statements.stmts = (CreateFunctionStmt**) palloc(statements.stmts_buf_size * sizeof(CreateFunctionStmt*));
statements.stmts_count = 0;
create_function_stmts_walker((Node*) parse_result.tree, &statements);
if (statements.stmts_count == 0) {
result.plpgsql_funcs = strdup("[]");
pg_query_exit_memory_context(ctx);
return result;
}
result.plpgsql_funcs = strdup("[\n");
for (i = 0; i < statements.stmts_count; i++) {
PgQueryInternalPlpgsqlFuncAndError func_and_error;
func_and_error = pg_query_raw_parse_plpgsql(statements.stmts[i]);
// These are all malloc-ed and will survive exiting the memory context, the caller is responsible to free them now
result.error = func_and_error.error;
if (result.error != NULL) {
pg_query_exit_memory_context(ctx);
return result;
}
if (func_and_error.func != NULL) {
char *func_json;
char *new_out;
func_json = plpgsqlToJSON(func_and_error.func);
plpgsql_free_function_memory(func_and_error.func);
int err = asprintf(&new_out, "%s%s,\n", result.plpgsql_funcs, func_json);
if (err == -1) {
PgQueryError* error = malloc(sizeof(PgQueryError));
error->message = strdup("Failed to output PL/pgSQL functions due to asprintf failure");
result.error = error;
} else {
free(result.plpgsql_funcs);
result.plpgsql_funcs = new_out;
}
pfree(func_json);
}
}
result.plpgsql_funcs[strlen(result.plpgsql_funcs) - 2] = '\n';
result.plpgsql_funcs[strlen(result.plpgsql_funcs) - 1] = ']';
free(parse_result.stderr_buffer);
pg_query_exit_memory_context(ctx);
return result;
}