Skip to content

Commit 0c00a94

Browse files
feat(clp-s): Add boilerplate for SQL parsing. (#504)
Co-authored-by: Lin Zhihao <[email protected]>
1 parent 09bab5a commit 0c00a94

File tree

11 files changed

+193
-30
lines changed

11 files changed

+193
-30
lines changed

components/core/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ set(SOURCE_FILES_unitTest
605605
tests/test-Stopwatch.cpp
606606
tests/test-StreamingCompression.cpp
607607
tests/test-string_utils.cpp
608+
tests/test-sql.cpp
608609
tests/test-TimestampPattern.cpp
609610
tests/test-utf8_utils.cpp
610611
tests/test-Utils.cpp
@@ -627,6 +628,7 @@ target_link_libraries(unitTest
627628
${MONGOCXX_TARGET}
628629
simdjson
629630
spdlog::spdlog
631+
sql
630632
OpenSSL::Crypto
631633
${sqlite_LIBRARY_DEPENDENCIES}
632634
${STD_FS_LIBS}

components/core/src/clp_s/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_subdirectory(search/kql)
2+
add_subdirectory(search/sql)
23

34
set(
45
CLP_SOURCES
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#ifndef CLP_S_SEARCH_ANTLRCOMMON_ERRORLISTENER_HPP
2+
#define CLP_S_SEARCH_ANTLRCOMMON_ERRORLISTENER_HPP
3+
4+
#include <cstddef>
5+
#include <exception>
6+
#include <string>
7+
#include <string_view>
8+
9+
#include <antlr4-runtime.h>
10+
11+
namespace clp_s::search::antlr_common {
12+
class ErrorListener : public antlr4::BaseErrorListener {
13+
public:
14+
auto syntaxError(
15+
[[maybe_unused]] antlr4::Recognizer* recognizer,
16+
[[maybe_unused]] antlr4::Token* offending_symbol,
17+
[[maybe_unused]] size_t line,
18+
[[maybe_unused]] size_t char_position_in_line,
19+
std::string const& msg,
20+
[[maybe_unused]] std::exception_ptr e
21+
) -> void override {
22+
m_error = true;
23+
m_error_message = msg;
24+
}
25+
26+
[[nodiscard]] auto error() const -> bool { return m_error; }
27+
28+
[[nodiscard]] auto message() const -> std::string_view { return m_error_message; }
29+
30+
private:
31+
bool m_error{false};
32+
std::string m_error_message;
33+
};
34+
} // namespace clp_s::search::antlr_common
35+
36+
#endif // CLP_S_SEARCH_ANTLRCOMMON_ERRORLISTENER_HPP

components/core/src/clp_s/search/kql/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ ANTLR_TARGET(
88
add_library(
99
kql
1010
../../Utils.hpp
11+
../antlr_common/ErrorListener.hpp
1112
../AndExpr.hpp
1213
../BooleanLiteral.hpp
1314
../ColumnDescriptor.hpp
@@ -26,4 +27,3 @@ add_library(
2627
target_compile_features(kql PRIVATE cxx_std_20)
2728
target_include_directories(kql PRIVATE ${ANTLR_KqlParser_OUTPUT_DIR})
2829
target_link_libraries(kql PRIVATE antlr4_static Boost::filesystem)
29-

components/core/src/clp_s/search/kql/kql.cpp

+7-29
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,9 @@
66
#include <antlr4-runtime.h>
77
#include <spdlog/spdlog.h>
88

9-
#include "KqlBaseVisitor.h"
10-
#include "KqlLexer.h"
11-
#include "KqlParser.h"
12-
// If redlining may want to add ${workspaceFolder}/build/**
13-
// to include path for vscode C/C++ utils
14-
159
#include "../../Utils.hpp"
1610
#include "../AndExpr.hpp"
11+
#include "../antlr_common/ErrorListener.hpp"
1712
#include "../BooleanLiteral.hpp"
1813
#include "../ColumnDescriptor.hpp"
1914
#include "../DateLiteral.hpp"
@@ -23,34 +18,16 @@
2318
#include "../NullLiteral.hpp"
2419
#include "../OrExpr.hpp"
2520
#include "../StringLiteral.hpp"
21+
#include "KqlBaseVisitor.h"
22+
#include "KqlLexer.h"
23+
#include "KqlParser.h"
2624

2725
using namespace antlr4;
2826
using namespace kql;
27+
using clp_s::search::antlr_common::ErrorListener;
2928

3029
namespace clp_s::search::kql {
31-
class ErrorListener : public BaseErrorListener {
32-
public:
33-
void syntaxError(
34-
Recognizer* recognizer,
35-
Token* offending_symbol,
36-
size_t line,
37-
size_t char_position_in_line,
38-
std::string const& msg,
39-
std::exception_ptr e
40-
) override {
41-
m_error = true;
42-
m_error_message = msg;
43-
}
44-
45-
bool error() const { return m_error; }
46-
47-
std::string const& message() const { return m_error_message; }
48-
49-
private:
50-
bool m_error{false};
51-
std::string m_error_message;
52-
};
53-
30+
namespace {
5431
class ParseTreeVisitor : public KqlBaseVisitor {
5532
private:
5633
static void
@@ -236,6 +213,7 @@ class ParseTreeVisitor : public KqlBaseVisitor {
236213
return base;
237214
}
238215
};
216+
} // namespace
239217

240218
std::shared_ptr<Expression> parse_kql_expression(std::istream& in) {
241219
ErrorListener lexer_error_listener;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
ANTLR_TARGET(
2+
SqlParser
3+
Sql.g4
4+
LEXER PARSER VISITOR
5+
PACKAGE sql
6+
)
7+
8+
add_library(
9+
sql
10+
../../Utils.hpp
11+
../antlr_common/ErrorListener.hpp
12+
../AndExpr.hpp
13+
../BooleanLiteral.hpp
14+
../ColumnDescriptor.hpp
15+
../DateLiteral.hpp
16+
../EmptyExpr.hpp
17+
../Expression.hpp
18+
../FilterExpr.hpp
19+
../Integral.hpp
20+
../NullLiteral.hpp
21+
../OrExpr.hpp
22+
../StringLiteral.hpp
23+
${ANTLR_SqlParser_CXX_OUTPUTS}
24+
sql.cpp
25+
sql.hpp
26+
)
27+
target_compile_features(sql PRIVATE cxx_std_20)
28+
target_include_directories(sql PRIVATE ${ANTLR_SqlParser_OUTPUT_DIR})
29+
target_link_libraries(sql PRIVATE antlr4_static Boost::filesystem)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Boilerplate for work in progress SQL grammar.
2+
grammar Sql;
3+
4+
start: EOF ;
5+
6+
SPACE: [ \t\r\n] -> skip ;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include <any>
2+
#include <iostream>
3+
#include <memory>
4+
5+
#include <antlr4-runtime.h>
6+
#include <spdlog/spdlog.h>
7+
8+
#include "../antlr_common/ErrorListener.hpp"
9+
#include "../EmptyExpr.hpp"
10+
#include "../Expression.hpp"
11+
#include "SqlBaseVisitor.h"
12+
#include "SqlLexer.h"
13+
#include "SqlParser.h"
14+
15+
using antlr4::ANTLRInputStream;
16+
using antlr4::CommonTokenStream;
17+
using clp_s::search::antlr_common::ErrorListener;
18+
using sql::SqlBaseVisitor;
19+
using sql::SqlLexer;
20+
using sql::SqlParser;
21+
22+
namespace clp_s::search::sql {
23+
namespace {
24+
class ParseTreeVisitor : public SqlBaseVisitor {
25+
public:
26+
[[nodiscard]] auto visitStart([[maybe_unused]] SqlParser::StartContext* ctx)
27+
-> std::any override {
28+
return EmptyExpr::create();
29+
}
30+
};
31+
} // namespace
32+
33+
auto parse_sql_expression(std::istream& in) -> std::shared_ptr<Expression> {
34+
ErrorListener lexer_error_listener;
35+
ErrorListener parser_error_listener;
36+
37+
ANTLRInputStream input{in};
38+
SqlLexer lexer{&input};
39+
lexer.removeErrorListeners();
40+
lexer.addErrorListener(&lexer_error_listener);
41+
CommonTokenStream tokens{&lexer};
42+
SqlParser parser(&tokens);
43+
parser.removeErrorListeners();
44+
parser.addErrorListener(&parser_error_listener);
45+
SqlParser::StartContext* tree{parser.start()};
46+
47+
if (lexer_error_listener.error()) {
48+
SPDLOG_ERROR("Lexer error: {}", lexer_error_listener.message());
49+
return nullptr;
50+
}
51+
if (parser_error_listener.error()) {
52+
SPDLOG_ERROR("Parser error: {}", parser_error_listener.message());
53+
return nullptr;
54+
}
55+
56+
ParseTreeVisitor visitor;
57+
try {
58+
return std::any_cast<std::shared_ptr<Expression>>(visitor.visitStart(tree));
59+
} catch (std::exception const& e) {
60+
return nullptr;
61+
}
62+
}
63+
} // namespace clp_s::search::sql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef CLP_S_SEARCH_SQL_SQL_HPP
2+
#define CLP_S_SEARCH_SQL_SQL_HPP
3+
4+
#include <istream>
5+
#include <memory>
6+
7+
#include "../Expression.hpp"
8+
9+
namespace clp_s::search::sql {
10+
/**
11+
* Parses an SQL expression from the given stream to generate a search AST.
12+
* @param in Input stream containing an SQL expression followed by EOF
13+
* @return a search AST on success, nullptr otherwise
14+
*/
15+
[[nodiscard]] auto parse_sql_expression(std::istream& in) -> std::shared_ptr<Expression>;
16+
} // namespace clp_s::search::sql
17+
18+
#endif // CLP_S_SEARCH_SQL_SQL_HPP

components/core/tests/LogSuppressor.hpp

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
#ifndef TESTS_LOGSUPPRESSOR_HPP
2+
#define TESTS_LOGSUPPRESSOR_HPP
3+
4+
#include <spdlog/spdlog.h>
5+
16
/**
27
* A class that suppresses logs so long as it's instantiated.
38
*/
@@ -19,3 +24,5 @@ class LogSuppressor {
1924
private:
2025
spdlog::level::level_enum m_previous_logging_level;
2126
};
27+
28+
#endif // TESTS_LOGSUPPRESSOR_HPP

components/core/tests/test-sql.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <memory>
2+
#include <sstream>
3+
4+
#include <Catch2/single_include/catch2/catch.hpp>
5+
6+
#include "../src/clp_s/search/EmptyExpr.hpp"
7+
#include "../src/clp_s/search/sql/sql.hpp"
8+
#include "LogSuppressor.hpp"
9+
10+
using clp_s::search::EmptyExpr;
11+
using clp_s::search::sql::parse_sql_expression;
12+
using std::stringstream;
13+
14+
TEST_CASE("Test parsing SQL", "[SQL]") {
15+
// Suppress logging
16+
LogSuppressor const suppressor;
17+
18+
SECTION("Stub accepts empty string") {
19+
stringstream empty_string{""};
20+
auto filter = std::dynamic_pointer_cast<EmptyExpr>(parse_sql_expression(empty_string));
21+
REQUIRE((nullptr != filter));
22+
}
23+
}

0 commit comments

Comments
 (0)