Coverage Report

Created: 2023-11-19 06:08

/src/libpg_query/src/pg_query_parse.c
Line
Count
Source (jump to first uncovered line)
1
#include "pg_query.h"
2
#include "pg_query_internal.h"
3
#include "pg_query_outfuncs.h"
4
5
#include "parser/parser.h"
6
#include "parser/scanner.h"
7
#include "parser/scansup.h"
8
9
#include <unistd.h>
10
#include <fcntl.h>
11
12
PgQueryInternalParsetreeAndError pg_query_raw_parse(const char* input)
13
245
{
14
245
  PgQueryInternalParsetreeAndError result = {0};
15
245
  MemoryContext parse_context = CurrentMemoryContext;
16
17
245
  char stderr_buffer[STDERR_BUFFER_LEN + 1] = {0};
18
#ifndef DEBUG
19
  int stderr_global;
20
  int stderr_pipe[2];
21
#endif
22
23
#ifndef DEBUG
24
  // Setup pipe for stderr redirection
25
  if (pipe(stderr_pipe) != 0) {
26
    PgQueryError* error = malloc(sizeof(PgQueryError));
27
28
    error->message = strdup("Failed to open pipe, too many open file descriptors")
29
30
    result.error = error;
31
32
    return result;
33
  }
34
35
  fcntl(stderr_pipe[0], F_SETFL, fcntl(stderr_pipe[0], F_GETFL) | O_NONBLOCK);
36
37
  // Redirect stderr to the pipe
38
  stderr_global = dup(STDERR_FILENO);
39
  dup2(stderr_pipe[1], STDERR_FILENO);
40
  close(stderr_pipe[1]);
41
#endif
42
43
245
  PG_TRY();
44
245
  {
45
245
    result.tree = raw_parser(input, RAW_PARSE_DEFAULT);
46
47
#ifndef DEBUG
48
    // Save stderr for result
49
    read(stderr_pipe[0], stderr_buffer, STDERR_BUFFER_LEN);
50
#endif
51
52
245
    result.stderr_buffer = strdup(stderr_buffer);
53
245
  }
54
245
  PG_CATCH();
55
0
  {
56
0
    ErrorData* error_data;
57
0
    PgQueryError* error;
58
59
0
    MemoryContextSwitchTo(parse_context);
60
0
    error_data = CopyErrorData();
61
62
    // Note: This is intentionally malloc so exiting the memory context doesn't free this
63
0
    error = malloc(sizeof(PgQueryError));
64
0
    error->message   = strdup(error_data->message);
65
0
    error->filename  = strdup(error_data->filename);
66
0
    error->funcname  = strdup(error_data->funcname);
67
0
    error->context   = NULL;
68
0
    error->lineno    = error_data->lineno;
69
0
    error->cursorpos = error_data->cursorpos;
70
71
0
    result.error = error;
72
0
    FlushErrorState();
73
0
  }
74
0
  PG_END_TRY();
75
76
#ifndef DEBUG
77
  // Restore stderr, close pipe
78
  dup2(stderr_global, STDERR_FILENO);
79
  close(stderr_pipe[0]);
80
  close(stderr_global);
81
#endif
82
83
245
  return result;
84
245
}
85
86
PgQueryParseResult pg_query_parse(const char* input)
87
245
{
88
245
  MemoryContext ctx = NULL;
89
245
  PgQueryInternalParsetreeAndError parsetree_and_error;
90
245
  PgQueryParseResult result = {0};
91
245
  char *tree_json = NULL;
92
93
245
  ctx = pg_query_enter_memory_context();
94
95
245
  parsetree_and_error = pg_query_raw_parse(input);
96
97
  // These are all malloc-ed and will survive exiting the memory context, the caller is responsible to free them now
98
245
  result.stderr_buffer = parsetree_and_error.stderr_buffer;
99
245
  result.error = parsetree_and_error.error;
100
101
245
  tree_json = pg_query_nodes_to_json(parsetree_and_error.tree);
102
245
  result.parse_tree = strdup(tree_json);
103
245
  pfree(tree_json);
104
105
245
  pg_query_exit_memory_context(ctx);
106
107
245
  return result;
108
245
}
109
110
PgQueryProtobufParseResult pg_query_parse_protobuf(const char* input)
111
0
{
112
0
  MemoryContext ctx = NULL;
113
0
  PgQueryInternalParsetreeAndError parsetree_and_error;
114
0
  PgQueryProtobufParseResult result = {};
115
116
0
  ctx = pg_query_enter_memory_context();
117
118
0
  parsetree_and_error = pg_query_raw_parse(input);
119
120
  // These are all malloc-ed and will survive exiting the memory context, the caller is responsible to free them now
121
0
  result.stderr_buffer = parsetree_and_error.stderr_buffer;
122
0
  result.error = parsetree_and_error.error;
123
0
  result.parse_tree = pg_query_nodes_to_protobuf(parsetree_and_error.tree);
124
125
0
  pg_query_exit_memory_context(ctx);
126
127
0
  return result;
128
0
}
129
130
void pg_query_free_parse_result(PgQueryParseResult result)
131
245
{
132
245
  if (result.error) {
133
140
    pg_query_free_error(result.error);
134
140
  }
135
136
245
  free(result.parse_tree);
137
245
  free(result.stderr_buffer);
138
245
}
139
140
void pg_query_free_protobuf_parse_result(PgQueryProtobufParseResult result)
141
0
{
142
0
  if (result.error) {
143
0
    pg_query_free_error(result.error);
144
0
  }
145
146
0
  free(result.parse_tree.data);
147
0
  free(result.stderr_buffer);
148
0
}