OmniSciDB  f17484ade4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ParserWrapper.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
23 #include "ParserWrapper.h"
24 #include "Shared/measure.h"
25 
26 #include <boost/algorithm/string.hpp>
27 
28 using namespace std;
29 
30 namespace { // anonymous namespace
31 
32 const std::string explain_str = {"explain"};
33 const std::string calcite_explain_str = {"explain calcite"};
34 const std::string optimized_explain_str = {"explain optimized"};
35 const std::string plan_explain_str = {"explain plan"};
36 const std::string plan_explain_detailed_str = {"explain plan detailed"};
37 
38 } // namespace
39 
40 ExplainInfo::ExplainInfo(std::string query_string) {
41  // sets explain_type_ and caches a trimmed actual_query_
42  explain_type_ = ExplainType::None;
43  actual_query_ = "";
44 
45  if (boost::istarts_with(query_string, explain_str)) {
46  if (boost::istarts_with(query_string, calcite_explain_str)) {
47  actual_query_ = boost::trim_copy(query_string.substr(calcite_explain_str.size()));
48  explain_type_ = ExplainType::Calcite;
49  } else if (boost::istarts_with(query_string, optimized_explain_str)) {
50  actual_query_ = boost::trim_copy(query_string.substr(optimized_explain_str.size()));
51  explain_type_ = ExplainType::OptimizedIR;
52  } else if (boost::istarts_with(query_string, plan_explain_str)) {
53  if (boost::istarts_with(query_string, plan_explain_detailed_str)) {
54  actual_query_ =
55  boost::trim_copy(query_string.substr(plan_explain_detailed_str.size()));
56  verbose_ = true;
57  } else {
58  actual_query_ = boost::trim_copy(query_string.substr(plan_explain_str.size()));
59  }
60  explain_type_ = ExplainType::ExecutionPlan;
61  } else {
62  actual_query_ = boost::trim_copy(query_string.substr(explain_str.size()));
63  explain_type_ = ExplainType::IR;
64  }
65  // override condition: ddl, update_dml
66  ParserWrapper inner{actual_query_};
67  if (inner.is_ddl || inner.is_update_dml) {
68  explain_type_ = ExplainType::Other;
69  }
70  }
71 }
72 
73 const std::vector<std::string> ParserWrapper::ddl_cmd = {
74  "ARCHIVE", "ALTER", "COPY", "CREATE", "DROP", "DUMP", "EVALUATE",
75  "GRANT", "KILL", "OPTIMIZE", "REFRESH", "RENAME", "RESTORE", "REVOKE",
76  "SHOW", "TRUNCATE", "REASSIGN", "VALIDATE", "CLEAR", "PAUSE", "RESUME"};
77 
78 const std::vector<std::string> ParserWrapper::update_dml_cmd = {"INSERT",
79  "DELETE",
80  "UPDATE"};
81 
82 namespace {
83 
84 void validate_no_leading_comments(const std::string& query_str) {
85  if (boost::starts_with(query_str, "--") || boost::starts_with(query_str, "//") ||
86  boost::starts_with(query_str, "/*")) {
87  throw std::runtime_error(
88  "SQL statements starting with comments are currently not allowed.");
89  }
90 }
91 
92 const std::string optimize_str = {"optimize"};
93 const std::string validate_str = {"validate"};
94 
95 } // namespace
96 
97 ParserWrapper::ParserWrapper(std::string query_string) {
98  validate_no_leading_comments(query_string);
99 
100  is_other_explain = ExplainInfo(query_string).isOtherExplain();
101 
102  query_type_ = QueryType::Read;
103  for (std::string ddl : ddl_cmd) {
104  if (boost::istarts_with(query_string, ddl)) {
105  query_type_ = QueryType::SchemaWrite;
106  is_ddl = true;
107 
108  if (ddl == "CREATE") {
109  boost::regex ctas_regex{
110  R"(CREATE\s+(TEMPORARY\s+|\s*)+TABLE.*(\"|\s)AS(\(|\s)+(SELECT|WITH).*)",
111  boost::regex::extended | boost::regex::icase};
112  if (boost::regex_match(query_string, ctas_regex)) {
113  is_ctas = true;
114  }
115  } else if (ddl == "COPY") {
116  is_copy = true;
117  // now check if it is COPY TO
118  boost::regex copy_to{R"(COPY\s*\(([^#])(.+)\)\s+TO\s+.*)",
119  boost::regex::extended | boost::regex::icase};
120  if (boost::regex_match(query_string, copy_to)) {
121  query_type_ = QueryType::Read;
122  is_copy_to = true;
123  } else {
124  query_type_ = QueryType::Write;
125  }
126  } else if (ddl == "SHOW") {
127  query_type_ = QueryType::SchemaRead;
128  } else if (ddl == "KILL") {
129  query_type_ = QueryType::Unknown;
130  } else if (ddl == "VALIDATE") {
131  query_type_ = QueryType::Unknown;
132  // needs to execute in a different context from other DDL
133  is_validate = true;
134  } else if (ddl == "ALTER") {
135  boost::regex alter_system_regex{R"(ALTER\s+(SYSTEM|SESSION).*)",
136  boost::regex::extended | boost::regex::icase};
137  if (boost::regex_match(query_string, alter_system_regex)) {
138  query_type_ = QueryType::Unknown;
139  }
140  } else if (ddl == "ARCHIVE" || ddl == "DUMP") {
141  query_type_ = QueryType::SchemaRead;
142  } else if (ddl == "REFRESH") {
143  is_refresh = true;
144  }
145  return;
146  }
147  }
148 
149  for (int i = 0; i < update_dml_cmd.size(); i++) {
150  is_update_dml = boost::istarts_with(query_string, ParserWrapper::update_dml_cmd[i]);
151  if (is_update_dml) {
152  query_type_ = QueryType::Write;
153  dml_type_ = (DMLType)(i);
154  break;
155  }
156  }
157 
158  if (dml_type_ == DMLType::Insert) {
159  boost::regex itas_regex{R"(INSERT\s+INTO\s+.*(\s+|\(|\")SELECT(\s|\(|\").*)",
160  boost::regex::extended | boost::regex::icase};
161  if (boost::regex_match(query_string, itas_regex)) {
162  is_itas = true;
163  return;
164  }
165  }
166 }
167 
Classes used to wrap parser calls for calcite redirection.
virtual ~ParserWrapper()
void validate_no_leading_comments(const std::string &query_str)
bool isOtherExplain() const
Definition: ParserWrapper.h:64
static const std::vector< std::string > ddl_cmd
static const std::vector< std::string > update_dml_cmd
ParserWrapper(std::string query_string)