#include "pg_query.h"
#include "pg_query_internal.h"
#include "pg_query_outfuncs.h"
#include "parser/parser.h"
#include "parser/scanner.h"
#include "parser/scansup.h"
#include <unistd.h>
#include <fcntl.h>
PgQueryInternalParsetreeAndError pg_query_raw_parse(const char* input, int parser_options)
{
PgQueryInternalParsetreeAndError result = {0};
MemoryContext parse_context = CurrentMemoryContext;
char stderr_buffer[STDERR_BUFFER_LEN + 1] = {0};
#ifndef DEBUG
int stderr_global;
int stderr_pipe[2];
#endif
#ifndef DEBUG
if (pipe(stderr_pipe) != 0) {
PgQueryError* error = malloc(sizeof(PgQueryError));
error->message = strdup("Failed to open pipe, too many open file descriptors")
result.error = error;
return result;
}
fcntl(stderr_pipe[0], F_SETFL, fcntl(stderr_pipe[0], F_GETFL) | O_NONBLOCK);
stderr_global = dup(STDERR_FILENO);
dup2(stderr_pipe[1], STDERR_FILENO);
close(stderr_pipe[1]);
#endif
PG_TRY();
{
RawParseMode rawParseMode = RAW_PARSE_DEFAULT;
switch (parser_options & PG_QUERY_PARSE_MODE_BITMASK)
{
case PG_QUERY_PARSE_TYPE_NAME:
rawParseMode = RAW_PARSE_TYPE_NAME;
break;
case PG_QUERY_PARSE_PLPGSQL_EXPR:
rawParseMode = RAW_PARSE_PLPGSQL_EXPR;
break;
case PG_QUERY_PARSE_PLPGSQL_ASSIGN1:
rawParseMode = RAW_PARSE_PLPGSQL_ASSIGN1;
break;
case PG_QUERY_PARSE_PLPGSQL_ASSIGN2:
rawParseMode = RAW_PARSE_PLPGSQL_ASSIGN2;
break;
case PG_QUERY_PARSE_PLPGSQL_ASSIGN3:
rawParseMode = RAW_PARSE_PLPGSQL_ASSIGN3;
break;
}
if ((parser_options & PG_QUERY_DISABLE_BACKSLASH_QUOTE) == PG_QUERY_DISABLE_BACKSLASH_QUOTE) {
backslash_quote = BACKSLASH_QUOTE_OFF;
} else {
backslash_quote = BACKSLASH_QUOTE_SAFE_ENCODING;
}
standard_conforming_strings = !((parser_options & PG_QUERY_DISABLE_STANDARD_CONFORMING_STRINGS) == PG_QUERY_DISABLE_STANDARD_CONFORMING_STRINGS);
escape_string_warning = !((parser_options & PG_QUERY_DISABLE_ESCAPE_STRING_WARNING) == PG_QUERY_DISABLE_ESCAPE_STRING_WARNING);
result.tree = raw_parser(input, rawParseMode);
backslash_quote = BACKSLASH_QUOTE_SAFE_ENCODING;
standard_conforming_strings = true;
escape_string_warning = true;
#ifndef DEBUG
read(stderr_pipe[0], stderr_buffer, STDERR_BUFFER_LEN);
#endif
result.stderr_buffer = strdup(stderr_buffer);
}
PG_CATCH();
{
ErrorData* error_data;
PgQueryError* error;
MemoryContextSwitchTo(parse_context);
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();
#ifndef DEBUG
dup2(stderr_global, STDERR_FILENO);
close(stderr_pipe[0]);
close(stderr_global);
#endif
return result;
}
PgQueryParseResult pg_query_parse(const char* input)
{
return pg_query_parse_opts(input, PG_QUERY_PARSE_DEFAULT);
}
PgQueryParseResult pg_query_parse_opts(const char* input, int parser_options)
{
MemoryContext ctx = NULL;
PgQueryInternalParsetreeAndError parsetree_and_error;
PgQueryParseResult result = {0};
char *tree_json = NULL;
ctx = pg_query_enter_memory_context();
parsetree_and_error = pg_query_raw_parse(input, 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);
pg_query_exit_memory_context(ctx);
return result;
}
PgQueryProtobufParseResult pg_query_parse_protobuf(const char* input)
{
return pg_query_parse_protobuf_opts(input, PG_QUERY_PARSE_DEFAULT);
}
PgQueryProtobufParseResult pg_query_parse_protobuf_opts(const char* input, int parser_options)
{
MemoryContext ctx = NULL;
PgQueryInternalParsetreeAndError parsetree_and_error;
PgQueryProtobufParseResult result = {0};
ctx = pg_query_enter_memory_context();
parsetree_and_error = pg_query_raw_parse(input, parser_options);
result.stderr_buffer = parsetree_and_error.stderr_buffer;
result.error = parsetree_and_error.error;
result.parse_tree = pg_query_nodes_to_protobuf(parsetree_and_error.tree);
pg_query_exit_memory_context(ctx);
return result;
}
void pg_query_free_parse_result(PgQueryParseResult result)
{
if (result.error) {
pg_query_free_error(result.error);
}
free(result.parse_tree);
free(result.stderr_buffer);
}
void pg_query_free_protobuf_parse_result(PgQueryProtobufParseResult result)
{
if (result.error) {
pg_query_free_error(result.error);
}
free(result.parse_tree.data);
free(result.stderr_buffer);
}