hogql-parser 1.3.2__tar.gz → 1.3.4__tar.gz
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.
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/PKG-INFO +1 -1
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/hogql_parser.egg-info/PKG-INFO +1 -1
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/parser_python.cpp +7 -10
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/pyproject.toml +2 -2
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/setup.py +1 -1
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/string.cpp +52 -22
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/HogQLLexer.cpp +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/HogQLParser.cpp +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/HogQLParserBaseVisitor.cpp +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/HogQLParserVisitor.cpp +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/README.md +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/error.cpp +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/hogql_parser-stubs/__init__.pyi +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/hogql_parser.egg-info/SOURCES.txt +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/hogql_parser.egg-info/dependency_links.txt +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/hogql_parser.egg-info/top_level.txt +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/json.cpp +0 -0
- {hogql_parser-1.3.2 → hogql_parser-1.3.4}/setup.cfg +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#define PY_SSIZE_T_CLEAN
|
|
2
2
|
#include <Python.h>
|
|
3
|
-
#include <boost/algorithm/string.hpp>
|
|
4
3
|
#include <string>
|
|
5
4
|
|
|
6
5
|
#include "HogQLLexer.h"
|
|
@@ -1406,7 +1405,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
1406
1405
|
tokens.push_back("ASOF");
|
|
1407
1406
|
}
|
|
1408
1407
|
tokens.push_back("INNER");
|
|
1409
|
-
return
|
|
1408
|
+
return join(tokens, " ");
|
|
1410
1409
|
}
|
|
1411
1410
|
|
|
1412
1411
|
VISIT(JoinOpLeftRight) {
|
|
@@ -1435,7 +1434,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
1435
1434
|
if (ctx->ASOF()) {
|
|
1436
1435
|
tokens.push_back("ASOF");
|
|
1437
1436
|
}
|
|
1438
|
-
return
|
|
1437
|
+
return join(tokens, " ");
|
|
1439
1438
|
}
|
|
1440
1439
|
|
|
1441
1440
|
VISIT(JoinOpFull) {
|
|
@@ -1452,7 +1451,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
1452
1451
|
if (ctx->ANY()) {
|
|
1453
1452
|
tokens.push_back("ANY");
|
|
1454
1453
|
}
|
|
1455
|
-
return
|
|
1454
|
+
return join(tokens, " ");
|
|
1456
1455
|
}
|
|
1457
1456
|
|
|
1458
1457
|
VISIT_UNSUPPORTED(JoinOpCross)
|
|
@@ -1669,8 +1668,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
1669
1668
|
}
|
|
1670
1669
|
PyObject* expr = visitAsPyObject(ctx->columnExpr());
|
|
1671
1670
|
|
|
1672
|
-
if (find(RESERVED_KEYWORDS.begin(), RESERVED_KEYWORDS.end(),
|
|
1673
|
-
RESERVED_KEYWORDS.end()) {
|
|
1671
|
+
if (find(RESERVED_KEYWORDS.begin(), RESERVED_KEYWORDS.end(), to_lower_copy(alias)) != RESERVED_KEYWORDS.end()) {
|
|
1674
1672
|
Py_DECREF(expr);
|
|
1675
1673
|
throw SyntaxError("\"" + alias + "\" cannot be an alias or identifier, as it's a reserved keyword");
|
|
1676
1674
|
}
|
|
@@ -2465,7 +2463,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
2465
2463
|
|
|
2466
2464
|
if (table.size() == 0 && nested.size() > 0) {
|
|
2467
2465
|
string text = ctx->getText();
|
|
2468
|
-
|
|
2466
|
+
to_lower(text);
|
|
2469
2467
|
if (!text.compare("true")) {
|
|
2470
2468
|
RETURN_NEW_AST_NODE("Constant", "{s:O}", "value", Py_True);
|
|
2471
2469
|
}
|
|
@@ -2493,8 +2491,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
2493
2491
|
VISIT(TableExprAlias) {
|
|
2494
2492
|
auto alias_ctx = ctx->alias();
|
|
2495
2493
|
string alias = any_cast<string>(alias_ctx ? visit(alias_ctx) : visit(ctx->identifier()));
|
|
2496
|
-
if (find(RESERVED_KEYWORDS.begin(), RESERVED_KEYWORDS.end(),
|
|
2497
|
-
RESERVED_KEYWORDS.end()) {
|
|
2494
|
+
if (find(RESERVED_KEYWORDS.begin(), RESERVED_KEYWORDS.end(), to_lower_copy(alias)) != RESERVED_KEYWORDS.end()) {
|
|
2498
2495
|
throw SyntaxError("ALIAS is a reserved keyword");
|
|
2499
2496
|
}
|
|
2500
2497
|
PyObject* py_alias = PyUnicode_FromStringAndSize(alias.data(), alias.size());
|
|
@@ -2563,7 +2560,7 @@ class HogQLParseTreeConverter : public HogQLParserBaseVisitor {
|
|
|
2563
2560
|
|
|
2564
2561
|
VISIT(NumberLiteral) {
|
|
2565
2562
|
string text = ctx->getText();
|
|
2566
|
-
|
|
2563
|
+
to_lower(text);
|
|
2567
2564
|
if (text.find(".") != string::npos || text.find("e") != string::npos || !text.compare("-inf") ||
|
|
2568
2565
|
!text.compare("inf") || !text.compare("nan")) {
|
|
2569
2566
|
PyObject* py_text = PyUnicode_FromStringAndSize(text.data(), text.size());
|
|
@@ -13,13 +13,13 @@ build-frontend = "build" # This is the successor to building with pip
|
|
|
13
13
|
|
|
14
14
|
[tool.cibuildwheel.macos]
|
|
15
15
|
before-build = [
|
|
16
|
-
"brew install
|
|
16
|
+
"brew install antlr4-cpp-runtime",
|
|
17
17
|
]
|
|
18
18
|
|
|
19
19
|
[tool.cibuildwheel.linux]
|
|
20
20
|
before-all = [
|
|
21
21
|
# manylinux_2_28 is based on AlmaLinux 8, which uses Fedora's dnf as its package manager
|
|
22
|
-
"dnf install -y
|
|
22
|
+
"dnf install -y unzip cmake curl uuid pkg-config",
|
|
23
23
|
# update cmake for antlr
|
|
24
24
|
"dnf install -y epel-release",
|
|
25
25
|
"dnf install -y cmake3",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#include <
|
|
1
|
+
#include <cctype>
|
|
2
2
|
|
|
3
3
|
#include "error.h"
|
|
4
4
|
#include "string.h"
|
|
@@ -7,15 +7,15 @@ using namespace std;
|
|
|
7
7
|
|
|
8
8
|
string replace_common_escape_characters(string text) {
|
|
9
9
|
// Copied from clickhouse_driver/util/escape.py
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
replace_all(text, "\\a", "\a");
|
|
11
|
+
replace_all(text, "\\b", "\b");
|
|
12
|
+
replace_all(text, "\\f", "\f");
|
|
13
|
+
replace_all(text, "\\n", "\n");
|
|
14
|
+
replace_all(text, "\\r", "\r");
|
|
15
|
+
replace_all(text, "\\t", "\t");
|
|
16
|
+
replace_all(text, "\\v", "\v");
|
|
17
|
+
replace_all(text, "\\0", ""); // NUL characters are ignored
|
|
18
|
+
replace_all(text, "\\\\", "\\");
|
|
19
19
|
|
|
20
20
|
return text;
|
|
21
21
|
}
|
|
@@ -29,27 +29,26 @@ string parse_string_literal_text(string text) {
|
|
|
29
29
|
const char last_char = text.back();
|
|
30
30
|
if (first_char == '\'' && last_char == '\'') {
|
|
31
31
|
text = text.substr(1, original_text_size - 2);
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
replace_all(text, "''", "'");
|
|
33
|
+
replace_all(text, "\\'", "'");
|
|
34
34
|
} else if (first_char == '"' && last_char == '"') {
|
|
35
35
|
text = text.substr(1, original_text_size - 2);
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
replace_all(text, "\"\"", "\"");
|
|
37
|
+
replace_all(text, "\\\"", "\"");
|
|
38
38
|
} else if (first_char == '`' && last_char == '`') {
|
|
39
39
|
text = text.substr(1, original_text_size - 2);
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
replace_all(text, "``", "`");
|
|
41
|
+
replace_all(text, "\\`", "`");
|
|
42
42
|
} else if (first_char == '{' && last_char == '}') {
|
|
43
43
|
text = text.substr(1, original_text_size - 2);
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
replace_all(text, "{{", "{");
|
|
45
|
+
replace_all(text, "\\{", "{");
|
|
46
46
|
} else {
|
|
47
47
|
throw SyntaxError("Invalid string literal, must start and end with the same quote type: " + text);
|
|
48
48
|
}
|
|
49
49
|
return replace_common_escape_characters(text);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
53
52
|
string parse_string_literal_ctx(antlr4::tree::TerminalNode* node) {
|
|
54
53
|
string text = node->getText();
|
|
55
54
|
try {
|
|
@@ -65,10 +64,10 @@ string parse_string_text_ctx(antlr4::tree::TerminalNode* node, bool escape_quote
|
|
|
65
64
|
string text = node->getText();
|
|
66
65
|
try {
|
|
67
66
|
if (escape_quotes) {
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
replace_all(text, "''", "'");
|
|
68
|
+
replace_all(text, "\\'", "'");
|
|
70
69
|
}
|
|
71
|
-
|
|
70
|
+
replace_all(text, "\\{", "{");
|
|
72
71
|
return replace_common_escape_characters(text);
|
|
73
72
|
} catch (SyntaxError& e) {
|
|
74
73
|
throw SyntaxError(e.what(), node->getSymbol()->getStartIndex(), node->getSymbol()->getStopIndex() + 1);
|
|
@@ -76,3 +75,34 @@ string parse_string_text_ctx(antlr4::tree::TerminalNode* node, bool escape_quote
|
|
|
76
75
|
throw ParsingError(e.what(), node->getSymbol()->getStartIndex(), node->getSymbol()->getStopIndex() + 1);
|
|
77
76
|
}
|
|
78
77
|
}
|
|
78
|
+
|
|
79
|
+
string join(const vector<string>& tokens, const string& sep) {
|
|
80
|
+
if (tokens.empty()) return "";
|
|
81
|
+
string result;
|
|
82
|
+
for (size_t i = 0; i < tokens.size(); ++i) {
|
|
83
|
+
if (i > 0) result += sep;
|
|
84
|
+
result += tokens[i];
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
void to_lower(string& s) {
|
|
90
|
+
for (char& c : s) {
|
|
91
|
+
c = std::tolower(static_cast<unsigned char>(c));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
string to_lower_copy(const string& s) {
|
|
96
|
+
string result = s;
|
|
97
|
+
to_lower(result);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
void replace_all(string& str, const string& from, const string& to) {
|
|
102
|
+
if (from.empty()) return;
|
|
103
|
+
size_t pos = 0;
|
|
104
|
+
while ((pos = str.find(from, pos)) != string::npos) {
|
|
105
|
+
str.replace(pos, from.length(), to);
|
|
106
|
+
pos += to.length();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|