summaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Databases/MySQL/tryQuoteUnrecognizedTokens.cpp
diff options
context:
space:
mode:
authorvitalyisaev <[email protected]>2023-11-14 09:58:56 +0300
committervitalyisaev <[email protected]>2023-11-14 10:20:20 +0300
commitc2b2dfd9827a400a8495e172a56343462e3ceb82 (patch)
treecd4e4f597d01bede4c82dffeb2d780d0a9046bd0 /contrib/clickhouse/src/Databases/MySQL/tryQuoteUnrecognizedTokens.cpp
parentd4ae8f119e67808cb0cf776ba6e0cf95296f2df7 (diff)
YQ Connector: move tests from yql to ydb (OSS)
Перенос папки с тестами на Коннектор из папки yql в папку ydb (синхронизируется с github).
Diffstat (limited to 'contrib/clickhouse/src/Databases/MySQL/tryQuoteUnrecognizedTokens.cpp')
-rw-r--r--contrib/clickhouse/src/Databases/MySQL/tryQuoteUnrecognizedTokens.cpp96
1 files changed, 96 insertions, 0 deletions
diff --git a/contrib/clickhouse/src/Databases/MySQL/tryQuoteUnrecognizedTokens.cpp b/contrib/clickhouse/src/Databases/MySQL/tryQuoteUnrecognizedTokens.cpp
new file mode 100644
index 00000000000..cd4603ddaec
--- /dev/null
+++ b/contrib/clickhouse/src/Databases/MySQL/tryQuoteUnrecognizedTokens.cpp
@@ -0,0 +1,96 @@
+#include <Databases/MySQL/tryQuoteUnrecognizedTokens.h>
+#include <Parsers/CommonParsers.h>
+#include <Common/quoteString.h>
+
+namespace DB
+{
+
+/// Checks if there are no any tokens (like whitespaces) between current and previous pos
+static bool noWhitespaces(const char * to, const char * from)
+{
+ return static_cast<size_t>(from - to) == 0;
+}
+
+/// Checks if the token should be quoted too together with unrecognized
+static bool isWordOrNumber(TokenType type)
+{
+ return type == TokenType::BareWord || type == TokenType::Number;
+}
+
+static void quoteLiteral(
+ IParser::Pos & pos,
+ IParser::Pos & pos_prev,
+ const char *& pos_unrecognized,
+ const char *& copy_from,
+ String & rewritten_query)
+{
+ /// Copy also whitespaces if any
+ const auto * end =
+ isWordOrNumber(pos->type) && noWhitespaces(pos_prev->end, pos->begin)
+ ? pos->end
+ : pos_prev->end;
+ String literal(pos_unrecognized, static_cast<size_t>(end - pos_unrecognized));
+ rewritten_query.append(copy_from, pos_unrecognized - copy_from).append(backQuoteMySQL(literal));
+ copy_from = end;
+}
+
+bool tryQuoteUnrecognizedTokens(const String & query, String & res)
+{
+ Tokens tokens(query.data(), query.data() + query.size());
+ IParser::Pos pos(tokens, 0);
+ Expected expected;
+ String rewritten_query;
+ const char * copy_from = query.data();
+ auto pos_prev = pos;
+ const char * pos_unrecognized = nullptr;
+ for (;pos->type != TokenType::EndOfStream; ++pos)
+ {
+ /// Commit quotes if any whitespaces found or the token is not a word
+ bool commit = !noWhitespaces(pos_prev->end, pos->begin) || (pos->type != TokenType::Error && !isWordOrNumber(pos->type));
+ if (pos_unrecognized && commit)
+ {
+ quoteLiteral(
+ pos,
+ pos_prev,
+ pos_unrecognized,
+ copy_from,
+ rewritten_query);
+ pos_unrecognized = nullptr;
+ }
+ if (pos->type == TokenType::Error)
+ {
+ /// Find first appearance of the error token
+ if (!pos_unrecognized)
+ {
+ pos_unrecognized =
+ isWordOrNumber(pos_prev->type) && noWhitespaces(pos_prev->end, pos->begin)
+ ? pos_prev->begin
+ : pos->begin;
+ }
+ }
+ pos_prev = pos;
+ }
+
+ /// There was EndOfStream but not committed unrecognized token
+ if (pos_unrecognized)
+ {
+ quoteLiteral(
+ pos,
+ pos_prev,
+ pos_unrecognized,
+ copy_from,
+ rewritten_query);
+ pos_unrecognized = nullptr;
+ }
+
+ /// If no Errors found
+ if (copy_from == query.data())
+ return false;
+
+ auto size = static_cast<size_t>(pos->end - copy_from);
+ rewritten_query.append(copy_from, size);
+ res = rewritten_query;
+ return true;
+}
+
+}