OmniSciDB  085a039ca4
 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 2017 MapD Technologies, 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 
17 /*
18  * File: ParserWrapper.cpp
19  * Author: michael
20  *
21  * Created on Feb 23, 2016, 9:33 AM
22  */
23 
24 #include "ParserWrapper.h"
25 #include "Shared/measure.h"
26 
27 #include <boost/algorithm/string.hpp>
28 
29 using namespace std;
30 
31 const std::vector<std::string> ParserWrapper::ddl_cmd = {"ARCHIVE",
32  "ALTER",
33  "COPY",
34  "CREATE",
35  "DROP",
36  "DUMP",
37  "GRANT",
38  "KILL",
39  "OPTIMIZE",
40  "REFRESH",
41  "RENAME",
42  "RESTORE",
43  "REVOKE",
44  "SHOW",
45  "TRUNCATE",
46  "REASSIGN",
47  "VALIDATE",
48  "CLEAR"};
49 
50 const std::vector<std::string> ParserWrapper::update_dml_cmd = {
51  "INSERT",
52  "DELETE",
53  "UPDATE",
54  "UPSERT",
55 };
56 
57 namespace {
58 
59 void validate_no_leading_comments(const std::string& query_str) {
60  if (boost::starts_with(query_str, "--") || boost::starts_with(query_str, "//") ||
61  boost::starts_with(query_str, "/*")) {
62  throw std::runtime_error(
63  "SQL statements starting with comments are currently not allowed.");
64  }
65 }
66 
67 const std::string explain_str = {"explain"};
68 const std::string calcite_explain_str = {"explain calcite"};
69 const std::string optimized_explain_str = {"explain optimized"};
70 const std::string plan_explain_str = {"explain plan"};
71 const std::string optimize_str = {"optimize"};
72 const std::string validate_str = {"validate"};
73 
74 } // namespace
75 
76 ParserWrapper::ParserWrapper(std::string query_string) {
77  validate_no_leading_comments(query_string);
78 
79  // init explain_type_ and actual_info_
80  initExplainType(query_string);
81 
82  query_type_ = QueryType::Read;
83  for (std::string ddl : ddl_cmd) {
84  if (boost::istarts_with(query_string, ddl)) {
85  query_type_ = QueryType::SchemaWrite;
86  is_ddl_ = true;
87 
88  if (ddl == "CREATE") {
89  boost::regex ctas_regex{
90  R"(CREATE\s+(TEMPORARY\s+|\s*)+TABLE.*(\"|\s)AS(\(|\s)+(SELECT|WITH).*)",
91  boost::regex::extended | boost::regex::icase};
92  if (boost::regex_match(query_string, ctas_regex)) {
93  is_ctas = true;
94  }
95  } else if (ddl == "COPY") {
96  is_copy = true;
97  // now check if it is COPY TO
98  boost::regex copy_to{R"(COPY\s*\(([^#])(.+)\)\s+TO\s+.*)",
99  boost::regex::extended | boost::regex::icase};
100  if (boost::regex_match(query_string, copy_to)) {
101  query_type_ = QueryType::Read;
102  is_copy_to = true;
103  } else {
104  query_type_ = QueryType::Write;
105  }
106  } else if (ddl == "SHOW") {
107  query_type_ = QueryType::SchemaRead;
108 
109  } else if (ddl == "KILL") {
110  query_type_ = QueryType::Unknown;
111  } else if (ddl == "VALIDATE") {
112  query_type_ = QueryType::Unknown;
113  // needs to execute in a different context from other DDL
114  is_validate = true;
115  } else if (ddl == "ALTER") {
116  boost::regex alter_system_regex{R"(ALTER\s+(SYSTEM).*)",
117  boost::regex::extended | boost::regex::icase};
118  if (boost::regex_match(query_string, alter_system_regex)) {
119  query_type_ = QueryType::Unknown;
120  }
121  } else if (ddl == "ARCHIVE" || ddl == "DUMP") {
122  query_type_ = QueryType::SchemaRead;
123  }
124  return;
125  }
126  }
127 
128  for (int i = 0; i < update_dml_cmd.size(); i++) {
129  is_update_dml = boost::istarts_with(query_string, ParserWrapper::update_dml_cmd[i]);
130  if (is_update_dml) {
131  query_type_ = QueryType::Write;
132  dml_type_ = (DMLType)(i);
133  break;
134  }
135  }
136 
137  if (dml_type_ == DMLType::Insert) {
138  boost::regex itas_regex{R"(INSERT\s+INTO\s+.*(\s+|\(|\")SELECT(\s|\(|\").*)",
139  boost::regex::extended | boost::regex::icase};
140  if (boost::regex_match(query_string, itas_regex)) {
141  is_itas = true;
142  return;
143  }
144  }
145 }
146 
148 
149 void ParserWrapper::initExplainType(std::string query_string) {
150  // sets explain_type_ and caches a trimmed actual_query_
151  explain_type_ = ParserWrapper::ExplainType::None;
152 
153  if (boost::istarts_with(query_string, calcite_explain_str)) {
154  actual_query_ = boost::trim_copy(query_string.substr(calcite_explain_str.size()));
155  ParserWrapper inner{actual_query_};
156  if (inner.isDdl() || inner.is_update_dml) {
157  explain_type_ = ExplainType::Other;
158  } else {
159  explain_type_ = ExplainType::Calcite;
160  }
161 
162  } else if (boost::istarts_with(query_string, optimized_explain_str)) {
163  actual_query_ = boost::trim_copy(query_string.substr(optimized_explain_str.size()));
164  ParserWrapper inner{actual_query_};
165  if (inner.isDdl() || inner.is_update_dml) {
166  explain_type_ = ExplainType::Other;
167  } else {
168  explain_type_ = ExplainType::OptimizedIR;
169  }
170 
171  } else if (boost::istarts_with(query_string, plan_explain_str)) {
172  actual_query_ = boost::trim_copy(query_string.substr(plan_explain_str.size()));
173  ParserWrapper inner{actual_query_};
174  if (inner.isDdl() || inner.is_update_dml) {
175  explain_type_ = ExplainType::Other;
176  } else {
177  explain_type_ = ExplainType::ExecutionPlan;
178  }
179 
180  } else if (boost::istarts_with(query_string, explain_str)) {
181  actual_query_ = boost::trim_copy(query_string.substr(explain_str.size()));
182  ParserWrapper inner{actual_query_};
183  if (inner.isDdl() || inner.is_update_dml) {
184  explain_type_ = ExplainType::Other;
185  } else {
186  explain_type_ = ExplainType::IR;
187  }
188  }
189 }
190 
192  return {explain_type_ == ExplainType::IR,
193  explain_type_ == ExplainType::OptimizedIR,
194  explain_type_ == ExplainType::ExecutionPlan,
195  explain_type_ == ExplainType::Calcite};
196 }
Classes used to wrap parser calls for calcite redirection.
virtual ~ParserWrapper()
void validate_no_leading_comments(const std::string &query_str)
ExplainInfo getExplainInfo() const
void initExplainType(std::string query_string)
static const std::vector< std::string > ddl_cmd
static const std::vector< std::string > update_dml_cmd
ParserWrapper(std::string query_string)