pg_query 1.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +162 -40
- data/README.md +80 -69
- data/Rakefile +85 -4
- data/ext/pg_query/extconf.rb +4 -32
- data/ext/pg_query/guc-file.c +0 -0
- data/ext/pg_query/pg_query.c +104 -0
- data/ext/pg_query/pg_query.pb-c.c +37628 -0
- data/ext/pg_query/pg_query_deparse.c +9953 -0
- data/ext/pg_query/pg_query_fingerprint.c +292 -0
- data/ext/pg_query/pg_query_fingerprint.h +8 -0
- data/ext/pg_query/pg_query_internal.h +24 -0
- data/ext/pg_query/pg_query_json_plpgsql.c +738 -0
- data/ext/pg_query/pg_query_json_plpgsql.h +9 -0
- data/ext/pg_query/pg_query_normalize.c +437 -0
- data/ext/pg_query/pg_query_outfuncs.h +10 -0
- data/ext/pg_query/pg_query_outfuncs_json.c +297 -0
- data/ext/pg_query/pg_query_outfuncs_protobuf.c +237 -0
- data/ext/pg_query/pg_query_parse.c +148 -0
- data/ext/pg_query/pg_query_parse_plpgsql.c +460 -0
- data/ext/pg_query/pg_query_readfuncs.h +11 -0
- data/ext/pg_query/pg_query_readfuncs_protobuf.c +142 -0
- data/ext/pg_query/pg_query_ruby.c +108 -12
- data/ext/pg_query/pg_query_scan.c +173 -0
- data/ext/pg_query/pg_query_split.c +221 -0
- data/ext/pg_query/protobuf-c.c +3660 -0
- data/ext/pg_query/src_backend_catalog_namespace.c +1051 -0
- data/ext/pg_query/src_backend_catalog_pg_proc.c +142 -0
- data/ext/pg_query/src_backend_commands_define.c +117 -0
- data/ext/pg_query/src_backend_libpq_pqcomm.c +651 -0
- data/ext/pg_query/src_backend_nodes_bitmapset.c +513 -0
- data/ext/pg_query/src_backend_nodes_copyfuncs.c +6013 -0
- data/ext/pg_query/src_backend_nodes_equalfuncs.c +4003 -0
- data/ext/pg_query/src_backend_nodes_extensible.c +99 -0
- data/ext/pg_query/src_backend_nodes_list.c +922 -0
- data/ext/pg_query/src_backend_nodes_makefuncs.c +417 -0
- data/ext/pg_query/src_backend_nodes_nodeFuncs.c +1363 -0
- data/ext/pg_query/src_backend_nodes_value.c +84 -0
- data/ext/pg_query/src_backend_parser_gram.c +47456 -0
- data/ext/pg_query/src_backend_parser_parse_expr.c +313 -0
- data/ext/pg_query/src_backend_parser_parser.c +497 -0
- data/ext/pg_query/src_backend_parser_scan.c +7091 -0
- data/ext/pg_query/src_backend_parser_scansup.c +160 -0
- data/ext/pg_query/src_backend_postmaster_postmaster.c +2230 -0
- data/ext/pg_query/src_backend_storage_ipc_ipc.c +192 -0
- data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +370 -0
- data/ext/pg_query/src_backend_tcop_postgres.c +776 -0
- data/ext/pg_query/src_backend_utils_adt_datum.c +326 -0
- data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +98 -0
- data/ext/pg_query/src_backend_utils_adt_format_type.c +136 -0
- data/ext/pg_query/src_backend_utils_adt_ruleutils.c +1683 -0
- data/ext/pg_query/src_backend_utils_error_assert.c +74 -0
- data/ext/pg_query/src_backend_utils_error_elog.c +1748 -0
- data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +570 -0
- data/ext/pg_query/src_backend_utils_hash_dynahash.c +1086 -0
- data/ext/pg_query/src_backend_utils_init_globals.c +168 -0
- data/ext/pg_query/src_backend_utils_mb_mbutils.c +839 -0
- data/ext/pg_query/src_backend_utils_misc_guc.c +1831 -0
- data/ext/pg_query/src_backend_utils_mmgr_aset.c +1560 -0
- data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +1006 -0
- data/ext/pg_query/src_common_encnames.c +158 -0
- data/ext/pg_query/src_common_keywords.c +39 -0
- data/ext/pg_query/src_common_kwlist_d.h +1081 -0
- data/ext/pg_query/src_common_kwlookup.c +91 -0
- data/ext/pg_query/src_common_psprintf.c +158 -0
- data/ext/pg_query/src_common_string.c +86 -0
- data/ext/pg_query/src_common_stringinfo.c +336 -0
- data/ext/pg_query/src_common_wchar.c +1651 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +1133 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +877 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +6533 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +107 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +123 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +671 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +255 -0
- data/ext/pg_query/src_port_erand48.c +127 -0
- data/ext/pg_query/src_port_pg_bitutils.c +246 -0
- data/ext/pg_query/src_port_pgsleep.c +69 -0
- data/ext/pg_query/src_port_pgstrcasecmp.c +83 -0
- data/ext/pg_query/src_port_qsort.c +240 -0
- data/ext/pg_query/src_port_random.c +31 -0
- data/ext/pg_query/src_port_snprintf.c +1449 -0
- data/ext/pg_query/src_port_strerror.c +324 -0
- data/ext/pg_query/src_port_strnlen.c +39 -0
- data/ext/pg_query/xxhash.c +43 -0
- data/lib/pg_query.rb +7 -4
- data/lib/pg_query/constants.rb +21 -0
- data/lib/pg_query/deparse.rb +16 -991
- data/lib/pg_query/filter_columns.rb +86 -85
- data/lib/pg_query/fingerprint.rb +122 -87
- data/lib/pg_query/json_field_names.rb +1402 -0
- data/lib/pg_query/node.rb +31 -0
- data/lib/pg_query/param_refs.rb +42 -37
- data/lib/pg_query/parse.rb +220 -200
- data/lib/pg_query/parse_error.rb +1 -1
- data/lib/pg_query/pg_query_pb.rb +3211 -0
- data/lib/pg_query/scan.rb +23 -0
- data/lib/pg_query/treewalker.rb +24 -40
- data/lib/pg_query/truncate.rb +64 -43
- data/lib/pg_query/version.rb +2 -2
- metadata +102 -11
- data/ext/pg_query/pg_query_ruby.h +0 -10
- data/lib/pg_query/deep_dup.rb +0 -16
- data/lib/pg_query/deparse/alter_table.rb +0 -42
- data/lib/pg_query/deparse/interval.rb +0 -105
- data/lib/pg_query/legacy_parsetree.rb +0 -109
- data/lib/pg_query/node_types.rb +0 -282
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#include "pg_query_readfuncs.h"
|
|
2
|
+
|
|
3
|
+
#include "nodes/nodes.h"
|
|
4
|
+
#include "nodes/parsenodes.h"
|
|
5
|
+
#include "nodes/pg_list.h"
|
|
6
|
+
|
|
7
|
+
#include "protobuf/pg_query.pb-c.h"
|
|
8
|
+
|
|
9
|
+
#define OUT_TYPE(typename, typename_c) PgQuery__##typename_c*
|
|
10
|
+
|
|
11
|
+
#define READ_COND(typename, typename_c, typename_underscore, typename_underscore_upcase, typename_cast, outname) \
|
|
12
|
+
case PG_QUERY__NODE__NODE_##typename_underscore_upcase: \
|
|
13
|
+
return (Node *) _read##typename_c(msg->outname);
|
|
14
|
+
|
|
15
|
+
#define READ_INT_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;
|
|
16
|
+
#define READ_UINT_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;
|
|
17
|
+
#define READ_LONG_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;
|
|
18
|
+
#define READ_FLOAT_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;
|
|
19
|
+
#define READ_BOOL_FIELD(outname, outname_json, fldname) node->fldname = msg->outname;
|
|
20
|
+
|
|
21
|
+
#define READ_CHAR_FIELD(outname, outname_json, fldname) \
|
|
22
|
+
if (msg->outname != NULL && strlen(msg->outname) > 0) { \
|
|
23
|
+
node->fldname = msg->outname[0]; \
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#define READ_STRING_FIELD(outname, outname_json, fldname) \
|
|
27
|
+
if (msg->outname != NULL && strlen(msg->outname) > 0) { \
|
|
28
|
+
node->fldname = pstrdup(msg->outname); \
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#define READ_ENUM_FIELD(typename, outname, outname_json, fldname) \
|
|
32
|
+
node->fldname = _intToEnum##typename(msg->outname);
|
|
33
|
+
|
|
34
|
+
#define READ_LIST_FIELD(outname, outname_json, fldname) \
|
|
35
|
+
{ \
|
|
36
|
+
if (msg->n_##outname > 0) \
|
|
37
|
+
node->fldname = list_make1(_readNode(msg->outname[0])); \
|
|
38
|
+
for (int i = 1; i < msg->n_##outname; i++) \
|
|
39
|
+
node->fldname = lappend(node->fldname, _readNode(msg->outname[i])); \
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#define READ_BITMAPSET_FIELD(outname, outname_json, fldname) // FIXME
|
|
43
|
+
|
|
44
|
+
#define READ_NODE_FIELD(outname, outname_json, fldname) \
|
|
45
|
+
node->fldname = *_readNode(msg->outname);
|
|
46
|
+
|
|
47
|
+
#define READ_NODE_PTR_FIELD(outname, outname_json, fldname) \
|
|
48
|
+
if (msg->outname != NULL) { \
|
|
49
|
+
node->fldname = _readNode(msg->outname); \
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#define READ_EXPR_PTR_FIELD(outname, outname_json, fldname) \
|
|
53
|
+
if (msg->outname != NULL) { \
|
|
54
|
+
node->fldname = (Expr *) _readNode(msg->outname); \
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#define READ_VALUE_FIELD(outname, outname_json, fldname) \
|
|
58
|
+
if (msg->outname != NULL) { \
|
|
59
|
+
node->fldname = *((Value *) _readNode(msg->outname)); \
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#define READ_VALUE_PTR_FIELD(outname, outname_json, fldname) \
|
|
63
|
+
if (msg->outname != NULL) { \
|
|
64
|
+
node->fldname = (Value *) _readNode(msg->outname); \
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#define READ_SPECIFIC_NODE_FIELD(typename, typename_underscore, outname, outname_json, fldname) \
|
|
68
|
+
node->fldname = *_read##typename(msg->outname);
|
|
69
|
+
|
|
70
|
+
#define READ_SPECIFIC_NODE_PTR_FIELD(typename, typename_underscore, outname, outname_json, fldname) \
|
|
71
|
+
if (msg->outname != NULL) { \
|
|
72
|
+
node->fldname = _read##typename(msg->outname); \
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static Node * _readNode(PgQuery__Node *msg);
|
|
76
|
+
|
|
77
|
+
#include "pg_query_enum_defs.c"
|
|
78
|
+
#include "pg_query_readfuncs_defs.c"
|
|
79
|
+
|
|
80
|
+
static List * _readList(PgQuery__List *msg)
|
|
81
|
+
{
|
|
82
|
+
List *node = NULL;
|
|
83
|
+
if (msg->n_items > 0)
|
|
84
|
+
node = list_make1(_readNode(msg->items[0]));
|
|
85
|
+
for (int i = 1; i < msg->n_items; i++)
|
|
86
|
+
node = lappend(node, _readNode(msg->items[i]));
|
|
87
|
+
return node;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static Node * _readNode(PgQuery__Node *msg)
|
|
91
|
+
{
|
|
92
|
+
switch (msg->node_case)
|
|
93
|
+
{
|
|
94
|
+
#include "pg_query_readfuncs_conds.c"
|
|
95
|
+
|
|
96
|
+
case PG_QUERY__NODE__NODE_INTEGER:
|
|
97
|
+
return (Node *) makeInteger(msg->integer->ival);
|
|
98
|
+
case PG_QUERY__NODE__NODE_FLOAT:
|
|
99
|
+
return (Node *) makeFloat(pstrdup(msg->float_->str));
|
|
100
|
+
case PG_QUERY__NODE__NODE_STRING:
|
|
101
|
+
return (Node *) makeString(pstrdup(msg->string->str));
|
|
102
|
+
case PG_QUERY__NODE__NODE_BIT_STRING:
|
|
103
|
+
return (Node *) makeBitString(pstrdup(msg->bit_string->str));
|
|
104
|
+
case PG_QUERY__NODE__NODE_NULL:
|
|
105
|
+
{
|
|
106
|
+
Value *v = makeNode(Value);
|
|
107
|
+
v->type = T_Null;
|
|
108
|
+
return (Node *) v;
|
|
109
|
+
}
|
|
110
|
+
case PG_QUERY__NODE__NODE_LIST:
|
|
111
|
+
return (Node *) _readList(msg->list);
|
|
112
|
+
case PG_QUERY__NODE__NODE__NOT_SET:
|
|
113
|
+
return NULL;
|
|
114
|
+
default:
|
|
115
|
+
elog(ERROR, "unsupported protobuf node type: %d",
|
|
116
|
+
(int) msg->node_case);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
List * pg_query_protobuf_to_nodes(PgQueryProtobuf protobuf)
|
|
121
|
+
{
|
|
122
|
+
PgQuery__ParseResult *result = NULL;
|
|
123
|
+
List * list = NULL;
|
|
124
|
+
size_t i = 0;
|
|
125
|
+
|
|
126
|
+
result = pg_query__parse_result__unpack(NULL, protobuf.len, (const uint8_t *) protobuf.data);
|
|
127
|
+
|
|
128
|
+
// TODO: Handle this by returning an error instead
|
|
129
|
+
Assert(result != NULL);
|
|
130
|
+
|
|
131
|
+
// TODO: Handle this by returning an error instead
|
|
132
|
+
Assert(result->version == PG_VERSION_NUM);
|
|
133
|
+
|
|
134
|
+
if (result->n_stmts > 0)
|
|
135
|
+
list = list_make1(_readRawStmt(result->stmts[0]));
|
|
136
|
+
for (i = 1; i < result->n_stmts; i++)
|
|
137
|
+
list = lappend(list, _readRawStmt(result->stmts[i]));
|
|
138
|
+
|
|
139
|
+
pg_query__parse_result__free_unpacked(result, NULL);
|
|
140
|
+
|
|
141
|
+
return list;
|
|
142
|
+
}
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
#include "
|
|
1
|
+
#include "pg_query.h"
|
|
2
|
+
#include "xxhash/xxhash.h"
|
|
3
|
+
#include <ruby.h>
|
|
2
4
|
|
|
3
|
-
void raise_ruby_parse_error(
|
|
5
|
+
void raise_ruby_parse_error(PgQueryProtobufParseResult result);
|
|
4
6
|
void raise_ruby_normalize_error(PgQueryNormalizeResult result);
|
|
5
7
|
void raise_ruby_fingerprint_error(PgQueryFingerprintResult result);
|
|
8
|
+
void raise_ruby_scan_error(PgQueryScanResult result);
|
|
6
9
|
|
|
7
|
-
VALUE
|
|
10
|
+
VALUE pg_query_ruby_parse_protobuf(VALUE self, VALUE input);
|
|
11
|
+
VALUE pg_query_ruby_deparse_protobuf(VALUE self, VALUE input);
|
|
8
12
|
VALUE pg_query_ruby_normalize(VALUE self, VALUE input);
|
|
9
13
|
VALUE pg_query_ruby_fingerprint(VALUE self, VALUE input);
|
|
14
|
+
VALUE pg_query_ruby_scan(VALUE self, VALUE input);
|
|
15
|
+
VALUE pg_query_ruby_hash_xxh3_64(VALUE self, VALUE input, VALUE seed);
|
|
10
16
|
|
|
11
17
|
void Init_pg_query(void)
|
|
12
18
|
{
|
|
@@ -14,12 +20,18 @@ void Init_pg_query(void)
|
|
|
14
20
|
|
|
15
21
|
cPgQuery = rb_const_get(rb_cObject, rb_intern("PgQuery"));
|
|
16
22
|
|
|
17
|
-
rb_define_singleton_method(cPgQuery, "
|
|
23
|
+
rb_define_singleton_method(cPgQuery, "parse_protobuf", pg_query_ruby_parse_protobuf, 1);
|
|
24
|
+
rb_define_singleton_method(cPgQuery, "deparse_protobuf", pg_query_ruby_deparse_protobuf, 1);
|
|
18
25
|
rb_define_singleton_method(cPgQuery, "normalize", pg_query_ruby_normalize, 1);
|
|
19
26
|
rb_define_singleton_method(cPgQuery, "fingerprint", pg_query_ruby_fingerprint, 1);
|
|
27
|
+
rb_define_singleton_method(cPgQuery, "_raw_scan", pg_query_ruby_scan, 1);
|
|
28
|
+
rb_define_singleton_method(cPgQuery, "hash_xxh3_64", pg_query_ruby_hash_xxh3_64, 2);
|
|
29
|
+
rb_define_const(cPgQuery, "PG_VERSION", rb_str_new2(PG_VERSION));
|
|
30
|
+
rb_define_const(cPgQuery, "PG_MAJORVERSION", rb_str_new2(PG_MAJORVERSION));
|
|
31
|
+
rb_define_const(cPgQuery, "PG_VERSION_NUM", INT2NUM(PG_VERSION_NUM));
|
|
20
32
|
}
|
|
21
33
|
|
|
22
|
-
void raise_ruby_parse_error(
|
|
34
|
+
void raise_ruby_parse_error(PgQueryProtobufParseResult result)
|
|
23
35
|
{
|
|
24
36
|
VALUE cPgQuery, cParseError;
|
|
25
37
|
VALUE args[4];
|
|
@@ -32,7 +44,25 @@ void raise_ruby_parse_error(PgQueryParseResult result)
|
|
|
32
44
|
args[2] = INT2NUM(result.error->lineno);
|
|
33
45
|
args[3] = INT2NUM(result.error->cursorpos);
|
|
34
46
|
|
|
35
|
-
|
|
47
|
+
pg_query_free_protobuf_parse_result(result);
|
|
48
|
+
|
|
49
|
+
rb_exc_raise(rb_class_new_instance(4, args, cParseError));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void raise_ruby_deparse_error(PgQueryDeparseResult result)
|
|
53
|
+
{
|
|
54
|
+
VALUE cPgQuery, cParseError;
|
|
55
|
+
VALUE args[4];
|
|
56
|
+
|
|
57
|
+
cPgQuery = rb_const_get(rb_cObject, rb_intern("PgQuery"));
|
|
58
|
+
cParseError = rb_const_get_at(cPgQuery, rb_intern("ParseError"));
|
|
59
|
+
|
|
60
|
+
args[0] = rb_str_new2(result.error->message);
|
|
61
|
+
args[1] = rb_str_new2(result.error->filename);
|
|
62
|
+
args[2] = INT2NUM(result.error->lineno);
|
|
63
|
+
args[3] = INT2NUM(result.error->cursorpos);
|
|
64
|
+
|
|
65
|
+
pg_query_free_deparse_result(result);
|
|
36
66
|
|
|
37
67
|
rb_exc_raise(rb_class_new_instance(4, args, cParseError));
|
|
38
68
|
}
|
|
@@ -73,21 +103,60 @@ void raise_ruby_fingerprint_error(PgQueryFingerprintResult result)
|
|
|
73
103
|
rb_exc_raise(rb_class_new_instance(4, args, cParseError));
|
|
74
104
|
}
|
|
75
105
|
|
|
76
|
-
|
|
106
|
+
void raise_ruby_scan_error(PgQueryScanResult result)
|
|
107
|
+
{
|
|
108
|
+
VALUE cPgQuery, cScanError;
|
|
109
|
+
VALUE args[4];
|
|
110
|
+
|
|
111
|
+
cPgQuery = rb_const_get(rb_cObject, rb_intern("PgQuery"));
|
|
112
|
+
cScanError = rb_const_get_at(cPgQuery, rb_intern("ScanError"));
|
|
113
|
+
|
|
114
|
+
args[0] = rb_str_new2(result.error->message);
|
|
115
|
+
args[1] = rb_str_new2(result.error->filename);
|
|
116
|
+
args[2] = INT2NUM(result.error->lineno);
|
|
117
|
+
args[3] = INT2NUM(result.error->cursorpos);
|
|
118
|
+
|
|
119
|
+
pg_query_free_scan_result(result);
|
|
120
|
+
|
|
121
|
+
rb_exc_raise(rb_class_new_instance(4, args, cScanError));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
VALUE pg_query_ruby_parse_protobuf(VALUE self, VALUE input)
|
|
77
125
|
{
|
|
78
126
|
Check_Type(input, T_STRING);
|
|
79
127
|
|
|
80
128
|
VALUE output;
|
|
81
|
-
|
|
129
|
+
PgQueryProtobufParseResult result = pg_query_parse_protobuf(StringValueCStr(input));
|
|
82
130
|
|
|
83
131
|
if (result.error) raise_ruby_parse_error(result);
|
|
84
132
|
|
|
85
133
|
output = rb_ary_new();
|
|
86
134
|
|
|
87
|
-
rb_ary_push(output,
|
|
135
|
+
rb_ary_push(output, rb_str_new(result.parse_tree.data, result.parse_tree.len));
|
|
88
136
|
rb_ary_push(output, rb_str_new2(result.stderr_buffer));
|
|
89
137
|
|
|
90
|
-
|
|
138
|
+
pg_query_free_protobuf_parse_result(result);
|
|
139
|
+
|
|
140
|
+
return output;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
VALUE pg_query_ruby_deparse_protobuf(VALUE self, VALUE input)
|
|
144
|
+
{
|
|
145
|
+
Check_Type(input, T_STRING);
|
|
146
|
+
|
|
147
|
+
VALUE output;
|
|
148
|
+
PgQueryProtobuf pbuf = {0};
|
|
149
|
+
PgQueryDeparseResult result = {0};
|
|
150
|
+
|
|
151
|
+
pbuf.data = StringValuePtr(input);
|
|
152
|
+
pbuf.len = RSTRING_LEN(input);
|
|
153
|
+
result = pg_query_deparse_protobuf(pbuf);
|
|
154
|
+
|
|
155
|
+
if (result.error) raise_ruby_deparse_error(result);
|
|
156
|
+
|
|
157
|
+
output = rb_str_new2(result.query);
|
|
158
|
+
|
|
159
|
+
pg_query_free_deparse_result(result);
|
|
91
160
|
|
|
92
161
|
return output;
|
|
93
162
|
}
|
|
@@ -117,8 +186,8 @@ VALUE pg_query_ruby_fingerprint(VALUE self, VALUE input)
|
|
|
117
186
|
|
|
118
187
|
if (result.error) raise_ruby_fingerprint_error(result);
|
|
119
188
|
|
|
120
|
-
if (result.
|
|
121
|
-
output = rb_str_new2(result.
|
|
189
|
+
if (result.fingerprint_str) {
|
|
190
|
+
output = rb_str_new2(result.fingerprint_str);
|
|
122
191
|
} else {
|
|
123
192
|
output = Qnil;
|
|
124
193
|
}
|
|
@@ -127,3 +196,30 @@ VALUE pg_query_ruby_fingerprint(VALUE self, VALUE input)
|
|
|
127
196
|
|
|
128
197
|
return output;
|
|
129
198
|
}
|
|
199
|
+
|
|
200
|
+
VALUE pg_query_ruby_scan(VALUE self, VALUE input)
|
|
201
|
+
{
|
|
202
|
+
Check_Type(input, T_STRING);
|
|
203
|
+
|
|
204
|
+
VALUE output;
|
|
205
|
+
PgQueryScanResult result = pg_query_scan(StringValueCStr(input));
|
|
206
|
+
|
|
207
|
+
if (result.error) raise_ruby_scan_error(result);
|
|
208
|
+
|
|
209
|
+
output = rb_ary_new();
|
|
210
|
+
|
|
211
|
+
rb_ary_push(output, rb_str_new(result.pbuf.data, result.pbuf.len));
|
|
212
|
+
rb_ary_push(output, rb_str_new2(result.stderr_buffer));
|
|
213
|
+
|
|
214
|
+
pg_query_free_scan_result(result);
|
|
215
|
+
|
|
216
|
+
return output;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
VALUE pg_query_ruby_hash_xxh3_64(VALUE self, VALUE input, VALUE seed)
|
|
220
|
+
{
|
|
221
|
+
Check_Type(input, T_STRING);
|
|
222
|
+
Check_Type(seed, T_FIXNUM);
|
|
223
|
+
|
|
224
|
+
return ULONG2NUM(XXH3_64bits_withSeed(StringValuePtr(input), RSTRING_LEN(input), NUM2ULONG(seed)));
|
|
225
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#include "pg_query.h"
|
|
2
|
+
#include "pg_query_internal.h"
|
|
3
|
+
|
|
4
|
+
#include "parser/gramparse.h"
|
|
5
|
+
#include "lib/stringinfo.h"
|
|
6
|
+
|
|
7
|
+
#include "protobuf/pg_query.pb-c.h"
|
|
8
|
+
|
|
9
|
+
#include <unistd.h>
|
|
10
|
+
#include <fcntl.h>
|
|
11
|
+
|
|
12
|
+
/* This is ugly. We need to access yyleng outside of scan.l, and casting yyscanner
|
|
13
|
+
to this internal struct seemed like one way to do it... */
|
|
14
|
+
struct yyguts_t
|
|
15
|
+
{
|
|
16
|
+
void *yyextra_r;
|
|
17
|
+
FILE *yyin_r, *yyout_r;
|
|
18
|
+
size_t yy_buffer_stack_top; /**< index of top of stack. */
|
|
19
|
+
size_t yy_buffer_stack_max; /**< capacity of stack. */
|
|
20
|
+
struct yy_buffer_state *yy_buffer_stack; /**< Stack as an array. */
|
|
21
|
+
char yy_hold_char;
|
|
22
|
+
size_t yy_n_chars;
|
|
23
|
+
size_t yyleng_r;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
PgQueryScanResult pg_query_scan(const char* input)
|
|
27
|
+
{
|
|
28
|
+
MemoryContext ctx = NULL;
|
|
29
|
+
PgQueryScanResult result = {0};
|
|
30
|
+
core_yyscan_t yyscanner;
|
|
31
|
+
core_yy_extra_type yyextra;
|
|
32
|
+
core_YYSTYPE yylval;
|
|
33
|
+
YYLTYPE yylloc;
|
|
34
|
+
PgQuery__ScanResult scan_result = PG_QUERY__SCAN_RESULT__INIT;
|
|
35
|
+
PgQuery__ScanToken **output_tokens;
|
|
36
|
+
size_t token_count = 0;
|
|
37
|
+
size_t i;
|
|
38
|
+
|
|
39
|
+
ctx = pg_query_enter_memory_context();
|
|
40
|
+
|
|
41
|
+
MemoryContext parse_context = CurrentMemoryContext;
|
|
42
|
+
|
|
43
|
+
char stderr_buffer[STDERR_BUFFER_LEN + 1] = {0};
|
|
44
|
+
#ifndef DEBUG
|
|
45
|
+
int stderr_global;
|
|
46
|
+
int stderr_pipe[2];
|
|
47
|
+
#endif
|
|
48
|
+
|
|
49
|
+
#ifndef DEBUG
|
|
50
|
+
// Setup pipe for stderr redirection
|
|
51
|
+
if (pipe(stderr_pipe) != 0) {
|
|
52
|
+
PgQueryError* error = malloc(sizeof(PgQueryError));
|
|
53
|
+
|
|
54
|
+
error->message = strdup("Failed to open pipe, too many open file descriptors")
|
|
55
|
+
|
|
56
|
+
result.error = error;
|
|
57
|
+
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fcntl(stderr_pipe[0], F_SETFL, fcntl(stderr_pipe[0], F_GETFL) | O_NONBLOCK);
|
|
62
|
+
|
|
63
|
+
// Redirect stderr to the pipe
|
|
64
|
+
stderr_global = dup(STDERR_FILENO);
|
|
65
|
+
dup2(stderr_pipe[1], STDERR_FILENO);
|
|
66
|
+
close(stderr_pipe[1]);
|
|
67
|
+
#endif
|
|
68
|
+
|
|
69
|
+
PG_TRY();
|
|
70
|
+
{
|
|
71
|
+
// Really this is stupid, we only run twice so we can pre-allocate the output array correctly
|
|
72
|
+
yyscanner = scanner_init(input, &yyextra, &ScanKeywords, ScanKeywordTokens);
|
|
73
|
+
for (;; token_count++)
|
|
74
|
+
{
|
|
75
|
+
if (core_yylex(&yylval, &yylloc, yyscanner) == 0) break;
|
|
76
|
+
}
|
|
77
|
+
scanner_finish(yyscanner);
|
|
78
|
+
|
|
79
|
+
output_tokens = malloc(sizeof(PgQuery__ScanToken *) * token_count);
|
|
80
|
+
|
|
81
|
+
/* initialize the flex scanner --- should match raw_parser() */
|
|
82
|
+
yyscanner = scanner_init(input, &yyextra, &ScanKeywords, ScanKeywordTokens);
|
|
83
|
+
|
|
84
|
+
/* Lex tokens */
|
|
85
|
+
for (i = 0; ; i++)
|
|
86
|
+
{
|
|
87
|
+
int tok;
|
|
88
|
+
int keyword;
|
|
89
|
+
|
|
90
|
+
tok = core_yylex(&yylval, &yylloc, yyscanner);
|
|
91
|
+
if (tok == 0) break;
|
|
92
|
+
|
|
93
|
+
output_tokens[i] = malloc(sizeof(PgQuery__ScanToken));
|
|
94
|
+
pg_query__scan_token__init(output_tokens[i]);
|
|
95
|
+
output_tokens[i]->start = yylloc;
|
|
96
|
+
if (tok == SCONST || tok == BCONST || tok == XCONST || tok == IDENT || tok == C_COMMENT) {
|
|
97
|
+
output_tokens[i]->end = yyextra.yyllocend;
|
|
98
|
+
} else {
|
|
99
|
+
output_tokens[i]->end = yylloc + ((struct yyguts_t*) yyscanner)->yyleng_r;
|
|
100
|
+
}
|
|
101
|
+
output_tokens[i]->token = tok;
|
|
102
|
+
|
|
103
|
+
switch (tok) {
|
|
104
|
+
#define PG_KEYWORD(a,b,c) case b: output_tokens[i]->keyword_kind = c + 1; break;
|
|
105
|
+
#include "parser/kwlist.h"
|
|
106
|
+
default: output_tokens[i]->keyword_kind = 0;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
scanner_finish(yyscanner);
|
|
111
|
+
|
|
112
|
+
scan_result.version = PG_VERSION_NUM;
|
|
113
|
+
scan_result.n_tokens = token_count;
|
|
114
|
+
scan_result.tokens = output_tokens;
|
|
115
|
+
result.pbuf.len = pg_query__scan_result__get_packed_size(&scan_result);
|
|
116
|
+
result.pbuf.data = malloc(result.pbuf.len);
|
|
117
|
+
pg_query__scan_result__pack(&scan_result, (void*) result.pbuf.data);
|
|
118
|
+
|
|
119
|
+
for (i = 0; i < token_count; i++) {
|
|
120
|
+
free(output_tokens[i]);
|
|
121
|
+
}
|
|
122
|
+
free(output_tokens);
|
|
123
|
+
|
|
124
|
+
#ifndef DEBUG
|
|
125
|
+
// Save stderr for result
|
|
126
|
+
read(stderr_pipe[0], stderr_buffer, STDERR_BUFFER_LEN);
|
|
127
|
+
#endif
|
|
128
|
+
|
|
129
|
+
result.stderr_buffer = strdup(stderr_buffer);
|
|
130
|
+
}
|
|
131
|
+
PG_CATCH();
|
|
132
|
+
{
|
|
133
|
+
ErrorData* error_data;
|
|
134
|
+
PgQueryError* error;
|
|
135
|
+
|
|
136
|
+
MemoryContextSwitchTo(parse_context);
|
|
137
|
+
error_data = CopyErrorData();
|
|
138
|
+
|
|
139
|
+
// Note: This is intentionally malloc so exiting the memory context doesn't free this
|
|
140
|
+
error = malloc(sizeof(PgQueryError));
|
|
141
|
+
error->message = strdup(error_data->message);
|
|
142
|
+
error->filename = strdup(error_data->filename);
|
|
143
|
+
error->funcname = strdup(error_data->funcname);
|
|
144
|
+
error->context = NULL;
|
|
145
|
+
error->lineno = error_data->lineno;
|
|
146
|
+
error->cursorpos = error_data->cursorpos;
|
|
147
|
+
|
|
148
|
+
result.error = error;
|
|
149
|
+
FlushErrorState();
|
|
150
|
+
}
|
|
151
|
+
PG_END_TRY();
|
|
152
|
+
|
|
153
|
+
#ifndef DEBUG
|
|
154
|
+
// Restore stderr, close pipe
|
|
155
|
+
dup2(stderr_global, STDERR_FILENO);
|
|
156
|
+
close(stderr_pipe[0]);
|
|
157
|
+
close(stderr_global);
|
|
158
|
+
#endif
|
|
159
|
+
|
|
160
|
+
pg_query_exit_memory_context(ctx);
|
|
161
|
+
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
void pg_query_free_scan_result(PgQueryScanResult result)
|
|
166
|
+
{
|
|
167
|
+
if (result.error) {
|
|
168
|
+
pg_query_free_error(result.error);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
free(result.pbuf.data);
|
|
172
|
+
free(result.stderr_buffer);
|
|
173
|
+
}
|