OmniSciDB  2e3a973ef4
DdlCommandExecutor.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 OmniSci, 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 #include "DdlCommandExecutor.h"
18 
19 #include <boost/algorithm/string/predicate.hpp>
20 
21 #include "Catalog/Catalog.h"
22 #include "Catalog/SysCatalog.h"
26 #include "LockMgr/LockMgr.h"
27 #include "Parser/ParserNode.h"
28 #include "Shared/StringTransform.h"
29 
30 extern bool g_enable_fsi;
31 
32 bool DdlCommand::isDefaultServer(const std::string& server_name) {
33  return boost::iequals(server_name.substr(0, 7), "omnisci");
34 }
35 
36 namespace {
37 void set_headers(TQueryResult& _return, const std::vector<std::string>& headers) {
38  TRowDescriptor row_descriptor;
39  for (const auto& header : headers) {
40  TColumnType column_type{};
41  column_type.col_name = header;
42  column_type.col_type.type = TDatumType::type::STR;
43  row_descriptor.push_back(column_type);
44 
45  _return.row_set.columns.emplace_back();
46  }
47  _return.row_set.row_desc = row_descriptor;
48  _return.row_set.is_columnar = true;
49 }
50 
51 void add_row(TQueryResult& _return, const std::vector<std::string>& row) {
52  for (size_t i = 0; i < row.size(); i++) {
53  _return.row_set.columns[i].data.str_col.emplace_back(row[i]);
54  _return.row_set.columns[i].nulls.emplace_back(false);
55  }
56 }
57 } // namespace
58 
60  const std::string& ddl_statement,
61  std::shared_ptr<Catalog_Namespace::SessionInfo const> session_ptr)
62  : session_ptr_(session_ptr) {
63  CHECK(!ddl_statement.empty());
64  ddl_query_.Parse(ddl_statement);
65  CHECK(ddl_query_.IsObject());
66  CHECK(ddl_query_.HasMember("payload"));
67  CHECK(ddl_query_["payload"].IsObject());
68  const auto& payload = ddl_query_["payload"].GetObject();
69  CHECK(payload.HasMember("command"));
70  CHECK(payload["command"].IsString());
71 }
72 
73 void DdlCommandExecutor::execute(TQueryResult& _return) {
74  const auto& payload = ddl_query_["payload"].GetObject();
75  const auto& ddl_command = std::string_view(payload["command"].GetString());
76  if (ddl_command == "CREATE_SERVER") {
77  CreateForeignServerCommand{payload, session_ptr_}.execute(_return);
78  } else if (ddl_command == "DROP_SERVER") {
79  DropForeignServerCommand{payload, session_ptr_}.execute(_return);
80  } else if (ddl_command == "CREATE_FOREIGN_TABLE") {
81  CreateForeignTableCommand{payload, session_ptr_}.execute(_return);
82  } else if (ddl_command == "DROP_FOREIGN_TABLE") {
83  DropForeignTableCommand{payload, session_ptr_}.execute(_return);
84  } else if (ddl_command == "SHOW_TABLES") {
85  ShowTablesCommand{payload, session_ptr_}.execute(_return);
86  } else if (ddl_command == "SHOW_DATABASES") {
87  ShowDatabasesCommand{payload, session_ptr_}.execute(_return);
88  } else if (ddl_command == "SHOW_SERVERS") {
89  ShowForeignServersCommand{payload, session_ptr_}.execute(_return);
90  } else if (ddl_command == "ALTER_SERVER") {
91  AlterForeignServerCommand{payload, session_ptr_}.execute(_return);
92  } else if (ddl_command == "REFRESH_FOREIGN_TABLES") {
93  RefreshForeignTablesCommand{payload, session_ptr_}.execute(_return);
94  } else if (ddl_command == "SHOW_QUERIES") {
95  std::cout << "SHOW QUERIES DDL is not ready yet!\n";
96  } else if (ddl_command == "KILL_QUERY") {
97  CHECK(payload.HasMember("querySession"));
98  const std::string& querySessionPayload = payload["querySession"].GetString();
99  auto querySession = querySessionPayload.substr(1, 8);
100  CHECK_EQ(querySession.length(),
101  (unsigned long)8); // public_session_id's length + two quotes
102  std::cout << "TRY TO KILL QUERY " << querySession
103  << " BUT KILL QUERY DDL is not ready yet!\n";
104  } else {
105  throw std::runtime_error("Unsupported DDL command");
106  }
107 }
108 
110  const auto& payload = ddl_query_["payload"].GetObject();
111  const auto& ddl_command = std::string_view(payload["command"].GetString());
112  return (ddl_command == "SHOW_USER_SESSIONS");
113 }
114 
116  const auto& payload = ddl_query_["payload"].GetObject();
117  const auto& ddl_command = std::string_view(payload["command"].GetString());
118  return (ddl_command == "SHOW_QUERIES");
119 }
120 
122  const auto& payload = ddl_query_["payload"].GetObject();
123  const auto& ddl_command = std::string_view(payload["command"].GetString());
124  return (ddl_command == "KILL_QUERY");
125 }
126 
128  // caller should check whether DDL indicates KillQuery request
129  // i.e., use isKillQuery() before calling this function
130  const auto& payload = ddl_query_["payload"].GetObject();
131  CHECK(isKillQuery());
132  CHECK(payload.HasMember("querySession"));
133  const std::string& query_session = payload["querySession"].GetString();
134  // regex matcher for public_session: start_time{3}-session_id{4} (Example:819-4RDo)
135  boost::regex session_id_regex{R"([0-9]{3}-[a-zA-Z0-9]{4})",
136  boost::regex::extended | boost::regex::icase};
137  if (!boost::regex_match(query_session, session_id_regex)) {
138  throw std::runtime_error(
139  "Please provide the correct session ID of the query that you want to interrupt.");
140  }
141  return query_session;
142 }
143 
145  const rapidjson::Value& ddl_payload,
146  std::shared_ptr<Catalog_Namespace::SessionInfo const> session_ptr)
147  : DdlCommand(ddl_payload, session_ptr) {
148  CHECK(ddl_payload.HasMember("serverName"));
149  CHECK(ddl_payload["serverName"].IsString());
150  CHECK(ddl_payload.HasMember("dataWrapper"));
151  CHECK(ddl_payload["dataWrapper"].IsString());
152  CHECK(ddl_payload.HasMember("options"));
153  CHECK(ddl_payload["options"].IsObject());
154  CHECK(ddl_payload.HasMember("ifNotExists"));
155  CHECK(ddl_payload["ifNotExists"].IsBool());
156 }
157 
158 void CreateForeignServerCommand::execute(TQueryResult& _return) {
159  std::string server_name = ddl_payload_["serverName"].GetString();
160  if (isDefaultServer(server_name)) {
161  throw std::runtime_error{"Server names cannot start with \"omnisci\"."};
162  }
163  bool if_not_exists = ddl_payload_["ifNotExists"].GetBool();
164  if (session_ptr_->getCatalog().getForeignServer(server_name)) {
165  if (if_not_exists) {
166  return;
167  } else {
168  throw std::runtime_error{"A foreign server with name \"" + server_name +
169  "\" already exists."};
170  }
171  }
172  // check access privileges
173  if (!session_ptr_->checkDBAccessPrivileges(DBObjectType::ServerDBObjectType,
175  throw std::runtime_error("Server " + std::string(server_name) +
176  " will not be created. User has no create privileges.");
177  }
178 
179  auto& current_user = session_ptr_->get_currentUser();
180  auto foreign_server = std::make_unique<foreign_storage::ForeignServer>();
181  foreign_server->data_wrapper_type = to_upper(ddl_payload_["dataWrapper"].GetString());
182  foreign_server->name = server_name;
183  foreign_server->user_id = current_user.userId;
184  foreign_server->populateOptionsMap(ddl_payload_["options"]);
185  foreign_server->validate();
186 
187  auto& catalog = session_ptr_->getCatalog();
188  catalog.createForeignServer(std::move(foreign_server),
189  ddl_payload_["ifNotExists"].GetBool());
191  current_user, server_name, ServerDBObjectType, catalog);
192 }
193 
195  const rapidjson::Value& ddl_payload,
196  std::shared_ptr<const Catalog_Namespace::SessionInfo> session_ptr)
197  : DdlCommand(ddl_payload, session_ptr) {
198  CHECK(ddl_payload.HasMember("serverName"));
199  CHECK(ddl_payload["serverName"].IsString());
200  CHECK(ddl_payload.HasMember("alterType"));
201  CHECK(ddl_payload["alterType"].IsString());
202  if (ddl_payload["alterType"] == "SET_OPTIONS") {
203  CHECK(ddl_payload.HasMember("options"));
204  CHECK(ddl_payload["options"].IsObject());
205  } else if (ddl_payload["alterType"] == "SET_DATA_WRAPPER") {
206  CHECK(ddl_payload.HasMember("dataWrapper"));
207  CHECK(ddl_payload["dataWrapper"].IsString());
208  } else if (ddl_payload["alterType"] == "RENAME_SERVER") {
209  CHECK(ddl_payload.HasMember("newServerName"));
210  CHECK(ddl_payload["newServerName"].IsString());
211  } else if (ddl_payload["alterType"] == "CHANGE_OWNER") {
212  CHECK(ddl_payload.HasMember("newOwner"));
213  CHECK(ddl_payload["newOwner"].IsString());
214  } else {
215  UNREACHABLE(); // not-implemented alterType
216  }
217 }
218 
219 void AlterForeignServerCommand::execute(TQueryResult& _return) {
220  std::string server_name = ddl_payload_["serverName"].GetString();
221  if (isDefaultServer(server_name)) {
222  throw std::runtime_error{"OmniSci default servers cannot be altered."};
223  }
224  if (!session_ptr_->getCatalog().getForeignServer(server_name)) {
225  throw std::runtime_error{"Foreign server with name \"" + server_name +
226  "\" does not exist and can not be altered."};
227  }
228  if (!hasAlterServerPrivileges()) {
229  throw std::runtime_error("Server " + server_name +
230  " can not be altered. User has no ALTER SERVER privileges.");
231  }
232  std::string alter_type = ddl_payload_["alterType"].GetString();
233  if (alter_type == "CHANGE_OWNER") {
235  } else if (alter_type == "SET_DATA_WRAPPER") {
237  } else if (alter_type == "SET_OPTIONS") {
239  } else if (alter_type == "RENAME_SERVER") {
241  }
242 }
243 
245  std::string server_name = ddl_payload_["serverName"].GetString();
246  std::string new_owner = ddl_payload_["newOwner"].GetString();
247  auto& sys_cat = Catalog_Namespace::SysCatalog::instance();
248  if (!session_ptr_->get_currentUser().isSuper) {
249  throw std::runtime_error(
250  "Only a super user can change a foreign server's owner. "
251  "Current user is not a super-user. "
252  "Foreign server with name \"" +
253  server_name + "\" will not have owner changed.");
254  }
255  Catalog_Namespace::UserMetadata user, original_owner;
256  if (!sys_cat.getMetadataForUser(new_owner, user)) {
257  throw std::runtime_error("User with username \"" + new_owner + "\" does not exist. " +
258  "Foreign server with name \"" + server_name +
259  "\" can not have owner changed.");
260  }
261  auto& cat = session_ptr_->getCatalog();
262  // get original owner metadata
263  bool original_owner_exists = sys_cat.getMetadataForUserById(
264  cat.getForeignServer(server_name)->user_id, original_owner);
265  // update catalog
266  cat.changeForeignServerOwner(server_name, user.userId);
267  try {
268  // update permissions
269  DBObject db_object(server_name, DBObjectType::ServerDBObjectType);
270  sys_cat.changeDBObjectOwnership(
271  user, original_owner, db_object, cat, original_owner_exists);
272  } catch (const std::runtime_error& e) {
273  // update permissions failed, revert catalog update
274  cat.changeForeignServerOwner(server_name, original_owner.userId);
275  throw;
276  }
277 }
278 
280  std::string server_name = ddl_payload_["serverName"].GetString();
281  std::string new_server_name = ddl_payload_["newServerName"].GetString();
282  if (isDefaultServer(new_server_name)) {
283  throw std::runtime_error{"OmniSci prefix can not be used for new name of server."};
284  }
285  auto& cat = session_ptr_->getCatalog();
286  // check for a conflicting server
287  if (cat.getForeignServer(new_server_name)) {
288  throw std::runtime_error("Foreign server with name \"" + server_name +
289  "\" can not be renamed to \"" + new_server_name + "\"." +
290  "Foreign server with name \"" + new_server_name +
291  "\" exists.");
292  }
293  // update catalog
294  cat.renameForeignServer(server_name, new_server_name);
295  try {
296  // migrate object privileges
297  auto& sys_cat = Catalog_Namespace::SysCatalog::instance();
298  sys_cat.renameDBObject(server_name,
299  new_server_name,
301  cat.getForeignServer(new_server_name)->id,
302  cat);
303  } catch (const std::runtime_error& e) {
304  // permission migration failed, revert catalog update
305  cat.renameForeignServer(new_server_name, server_name);
306  throw;
307  }
308 }
309 
311  std::string server_name = ddl_payload_["serverName"].GetString();
312  auto& cat = session_ptr_->getCatalog();
313  // update catalog
314  const auto foreign_server = cat.getForeignServer(server_name);
316  opt.populateOptionsMap(foreign_server->getOptionsAsJsonString());
317  opt.populateOptionsMap(ddl_payload_["options"]);
318  cat.setForeignServerOptions(server_name, opt.getOptionsAsJsonString());
319 }
320 
322  std::string server_name = ddl_payload_["serverName"].GetString();
323  std::string data_wrapper = ddl_payload_["dataWrapper"].GetString();
324  auto& cat = session_ptr_->getCatalog();
325  // update catalog
326  cat.setForeignServerDataWrapper(server_name, data_wrapper);
327 }
328 
330  // TODO: implement `GRANT/REVOKE ALTER_SERVER` DDL commands
331  std::string server_name = ddl_payload_["serverName"].GetString();
332  return session_ptr_->checkDBAccessPrivileges(
334 }
335 
337  const rapidjson::Value& ddl_payload,
338  std::shared_ptr<Catalog_Namespace::SessionInfo const> session_ptr)
339  : DdlCommand(ddl_payload, session_ptr) {
340  CHECK(ddl_payload.HasMember("serverName"));
341  CHECK(ddl_payload["serverName"].IsString());
342  CHECK(ddl_payload.HasMember("ifExists"));
343  CHECK(ddl_payload["ifExists"].IsBool());
344 }
345 
346 void DropForeignServerCommand::execute(TQueryResult& _return) {
347  std::string server_name = ddl_payload_["serverName"].GetString();
348  if (isDefaultServer(server_name)) {
349  throw std::runtime_error{"OmniSci default servers cannot be dropped."};
350  }
351  bool if_exists = ddl_payload_["ifExists"].GetBool();
352  if (!session_ptr_->getCatalog().getForeignServer(server_name)) {
353  if (if_exists) {
354  return;
355  } else {
356  throw std::runtime_error{"Foreign server with name \"" + server_name +
357  "\" does not exist."};
358  }
359  }
360  // check access privileges
361  if (!session_ptr_->checkDBAccessPrivileges(
363  throw std::runtime_error("Server " + server_name +
364  " will not be dropped. User has no DROP SERVER privileges.");
365  }
367  DBObject(server_name, ServerDBObjectType), session_ptr_->get_catalog_ptr().get());
368  session_ptr_->getCatalog().dropForeignServer(ddl_payload_["serverName"].GetString());
369 }
370 
371 SQLTypes JsonColumnSqlType::getSqlType(const rapidjson::Value& data_type) {
372  CHECK(data_type.IsObject());
373  CHECK(data_type.HasMember("type"));
374  CHECK(data_type["type"].IsString());
375 
376  std::string type = data_type["type"].GetString();
377  if (boost::iequals(type, "ARRAY")) {
378  CHECK(data_type.HasMember("array"));
379  CHECK(data_type["array"].IsObject());
380 
381  const auto& array = data_type["array"].GetObject();
382  CHECK(array.HasMember("elementType"));
383  CHECK(array["elementType"].IsString());
384  type = array["elementType"].GetString();
385  }
386  return getSqlType(type);
387 }
388 
390  if (boost::iequals(type, "BIGINT")) {
391  return kBIGINT;
392  }
393  if (boost::iequals(type, "BOOLEAN")) {
394  return kBOOLEAN;
395  }
396  if (boost::iequals(type, "DATE")) {
397  return kDATE;
398  }
399  if (boost::iequals(type, "DECIMAL")) {
400  return kDECIMAL;
401  }
402  if (boost::iequals(type, "DOUBLE")) {
403  return kDOUBLE;
404  }
405  if (boost::iequals(type, "FLOAT")) {
406  return kFLOAT;
407  }
408  if (boost::iequals(type, "INTEGER")) {
409  return kINT;
410  }
411  if (boost::iequals(type, "LINESTRING")) {
412  return kLINESTRING;
413  }
414  if (boost::iequals(type, "MULTIPOLYGON")) {
415  return kMULTIPOLYGON;
416  }
417  if (boost::iequals(type, "POINT")) {
418  return kPOINT;
419  }
420  if (boost::iequals(type, "POLYGON")) {
421  return kPOLYGON;
422  }
423  if (boost::iequals(type, "SMALLINT")) {
424  return kSMALLINT;
425  }
426  if (boost::iequals(type, "TEXT")) {
427  return kTEXT;
428  }
429  if (boost::iequals(type, "TIME")) {
430  return kTIME;
431  }
432  if (boost::iequals(type, "TIMESTAMP")) {
433  return kTIMESTAMP;
434  }
435  if (boost::iequals(type, "TINYINT")) {
436  return kTINYINT;
437  }
438 
439  throw std::runtime_error{"Unsupported type \"" + type + "\" specified."};
440 }
441 
442 int JsonColumnSqlType::getParam1(const rapidjson::Value& data_type) {
443  int param1 = -1;
444  CHECK(data_type.IsObject());
445  if (data_type.HasMember("precision") && !data_type["precision"].IsNull()) {
446  CHECK(data_type["precision"].IsInt());
447  param1 = data_type["precision"].GetInt();
448  } else if (auto type = getSqlType(data_type); IS_GEO(type)) {
449  param1 = static_cast<int>(kGEOMETRY);
450  }
451  return param1;
452 }
453 
454 int JsonColumnSqlType::getParam2(const rapidjson::Value& data_type) {
455  int param2 = 0;
456  CHECK(data_type.IsObject());
457  if (data_type.HasMember("scale") && !data_type["scale"].IsNull()) {
458  CHECK(data_type["scale"].IsInt());
459  param2 = data_type["scale"].GetInt();
460  } else if (auto type = getSqlType(data_type); IS_GEO(type) &&
461  data_type.HasMember("coordinateSystem") &&
462  !data_type["coordinateSystem"].IsNull()) {
463  CHECK(data_type["coordinateSystem"].IsInt());
464  param2 = data_type["coordinateSystem"].GetInt();
465  }
466  return param2;
467 }
468 
469 bool JsonColumnSqlType::isArray(const rapidjson::Value& data_type) {
470  CHECK(data_type.IsObject());
471  CHECK(data_type.HasMember("type"));
472  CHECK(data_type["type"].IsString());
473  return boost::iequals(data_type["type"].GetString(), "ARRAY");
474 }
475 
476 int JsonColumnSqlType::getArraySize(const rapidjson::Value& data_type) {
477  int size = -1;
478  if (isArray(data_type)) {
479  CHECK(data_type.HasMember("array"));
480  CHECK(data_type["array"].IsObject());
481 
482  const auto& array = data_type["array"].GetObject();
483  if (array.HasMember("size") && !array["size"].IsNull()) {
484  CHECK(array["size"].IsInt());
485  size = array["size"].GetInt();
486  }
487  }
488  return size;
489 }
490 
491 std::string* JsonColumnEncoding::getEncodingName(const rapidjson::Value& data_type) {
492  CHECK(data_type.IsObject());
493  CHECK(data_type.HasMember("encoding"));
494  CHECK(data_type["encoding"].IsObject());
495 
496  const auto& encoding = data_type["encoding"].GetObject();
497  CHECK(encoding.HasMember("type"));
498  CHECK(encoding["type"].IsString());
499  return new std::string(encoding["type"].GetString());
500 }
501 
502 int JsonColumnEncoding::getEncodingParam(const rapidjson::Value& data_type) {
503  CHECK(data_type.IsObject());
504  CHECK(data_type.HasMember("encoding"));
505  CHECK(data_type["encoding"].IsObject());
506 
507  int encoding_size = 0;
508  const auto& encoding = data_type["encoding"].GetObject();
509  if (encoding.HasMember("size") && !encoding["size"].IsNull()) {
510  CHECK(encoding["size"].IsInt());
511  encoding_size = encoding["size"].GetInt();
512  }
513  return encoding_size;
514 }
515 
517  const rapidjson::Value& ddl_payload,
518  std::shared_ptr<Catalog_Namespace::SessionInfo const> session_ptr)
519  : DdlCommand(ddl_payload, session_ptr) {
520  CHECK(ddl_payload.HasMember("serverName"));
521  CHECK(ddl_payload["serverName"].IsString());
522  CHECK(ddl_payload.HasMember("tableName"));
523  CHECK(ddl_payload["tableName"].IsString());
524  CHECK(ddl_payload.HasMember("ifNotExists"));
525  CHECK(ddl_payload["ifNotExists"].IsBool());
526  CHECK(ddl_payload.HasMember("columns"));
527  CHECK(ddl_payload["columns"].IsArray());
528 }
529 
530 void CreateForeignTableCommand::execute(TQueryResult& _return) {
531  auto& catalog = session_ptr_->getCatalog();
532 
533  const std::string& table_name = ddl_payload_["tableName"].GetString();
534  if (!session_ptr_->checkDBAccessPrivileges(DBObjectType::TableDBObjectType,
536  throw std::runtime_error(
537  "Foreign table \"" + table_name +
538  "\" will not be created. User has no CREATE TABLE privileges.");
539  }
540 
541  bool if_not_exists = ddl_payload_["ifNotExists"].GetBool();
542  if (!catalog.validateNonExistentTableOrView(table_name, if_not_exists)) {
543  return;
544  }
545 
546  foreign_storage::ForeignTable foreign_table{};
547  std::list<ColumnDescriptor> columns{};
548  setColumnDetails(columns);
549  setTableDetails(table_name, foreign_table, columns.size());
550  catalog.createTable(foreign_table, columns, {}, true);
551 
552  // TODO (max): It's transactionally unsafe, should be fixed: we may create object w/o
553  // privileges
555  session_ptr_->get_currentUser(),
556  foreign_table.tableName,
558  catalog);
559 }
560 
561 void CreateForeignTableCommand::setTableDetails(const std::string& table_name,
562  TableDescriptor& td,
563  const size_t column_count) {
564  ddl_utils::set_default_table_attributes(table_name, td, column_count);
565  td.userId = session_ptr_->get_currentUser().userId;
567  td.hasDeletedCol = false;
568  td.keyMetainfo = "[]";
569  td.fragments = "";
570  td.partitions = "";
571 
572  auto& foreign_table = dynamic_cast<foreign_storage::ForeignTable&>(td);
573  const std::string server_name = ddl_payload_["serverName"].GetString();
574  foreign_table.foreign_server = session_ptr_->getCatalog().getForeignServer(server_name);
575  if (!foreign_table.foreign_server) {
576  throw std::runtime_error{"Foreign server with name \"" + server_name +
577  "\" does not exist."};
578  }
579 
580  if (ddl_payload_.HasMember("options") && !ddl_payload_["options"].IsNull()) {
581  CHECK(ddl_payload_["options"].IsObject());
582  foreign_table.populateOptionsMap(ddl_payload_["options"]);
583  setRefreshOptions(foreign_table);
584 
585  std::vector<std::string_view> supported_data_wrapper_options;
586  if (foreign_table.foreign_server->data_wrapper_type ==
589  supported_data_wrapper_options =
591  } else if (foreign_table.foreign_server->data_wrapper_type ==
594  supported_data_wrapper_options =
596  }
597  foreign_table.validate(supported_data_wrapper_options);
598  }
599 
600  if (const auto it = foreign_table.options.find("FRAGMENT_SIZE");
601  it != foreign_table.options.end()) {
602  foreign_table.maxFragRows = std::stoi(it->second);
603  }
604 }
605 
607  foreign_storage::ForeignTable& foreign_table) {
608  auto refresh_timing_entry =
610  if (refresh_timing_entry == foreign_table.options.end()) {
613  } else {
615  to_upper(refresh_timing_entry->second);
616  }
617 
618  auto update_type_entry =
620  if (update_type_entry == foreign_table.options.end()) {
623  } else {
625  to_upper(update_type_entry->second);
626  }
627 }
628 
629 void CreateForeignTableCommand::setColumnDetails(std::list<ColumnDescriptor>& columns) {
630  std::unordered_set<std::string> column_names{};
631  for (auto& column_def : ddl_payload_["columns"].GetArray()) {
632  CHECK(column_def.IsObject());
633  CHECK(column_def.HasMember("name"));
634  CHECK(column_def["name"].IsString());
635  const std::string& column_name = column_def["name"].GetString();
636 
637  CHECK(column_def.HasMember("dataType"));
638  CHECK(column_def["dataType"].IsObject());
639 
640  JsonColumnSqlType sql_type{column_def["dataType"]};
641  const auto& data_type = column_def["dataType"].GetObject();
642  CHECK(data_type.HasMember("notNull"));
643  CHECK(data_type["notNull"].IsBool());
644 
645  std::unique_ptr<JsonColumnEncoding> encoding;
646  if (data_type.HasMember("encoding") && !data_type["encoding"].IsNull()) {
647  CHECK(data_type["encoding"].IsObject());
648  encoding = std::make_unique<JsonColumnEncoding>(column_def["dataType"]);
649  }
650 
651  ColumnDescriptor cd;
652  ddl_utils::validate_non_duplicate_column(column_name, column_names);
655  column_name, cd, &sql_type, data_type["notNull"].GetBool(), encoding.get());
656  columns.emplace_back(cd);
657  }
658 }
659 
661  const rapidjson::Value& ddl_payload,
662  std::shared_ptr<Catalog_Namespace::SessionInfo const> session_ptr)
663  : DdlCommand(ddl_payload, session_ptr) {
664  CHECK(ddl_payload.HasMember("tableName"));
665  CHECK(ddl_payload["tableName"].IsString());
666  CHECK(ddl_payload.HasMember("ifExists"));
667  CHECK(ddl_payload["ifExists"].IsBool());
668 }
669 
670 void DropForeignTableCommand::execute(TQueryResult& _return) {
671  auto& catalog = session_ptr_->getCatalog();
672  const std::string& table_name = ddl_payload_["tableName"].GetString();
673  const TableDescriptor* td{nullptr};
674  std::unique_ptr<lockmgr::TableSchemaLockContainer<lockmgr::WriteLock>> td_with_lock;
675 
676  try {
677  td_with_lock =
678  std::make_unique<lockmgr::TableSchemaLockContainer<lockmgr::WriteLock>>(
680  catalog, table_name, false));
681  td = (*td_with_lock)();
682  } catch (const std::runtime_error& e) {
683  if (ddl_payload_["ifExists"].GetBool()) {
684  return;
685  } else {
686  throw e;
687  }
688  }
689 
690  CHECK(td);
691  CHECK(td_with_lock);
692 
693  if (!session_ptr_->checkDBAccessPrivileges(
695  throw std::runtime_error(
696  "Foreign table \"" + table_name +
697  "\" will not be dropped. User has no DROP TABLE privileges.");
698  }
699 
701  auto table_data_write_lock =
703  catalog.dropTable(td);
704 }
705 
707  const rapidjson::Value& ddl_payload,
708  std::shared_ptr<Catalog_Namespace::SessionInfo const> session_ptr)
709  : DdlCommand(ddl_payload, session_ptr) {}
710 
711 void ShowTablesCommand::execute(TQueryResult& _return) {
712  // Get all table names in the same way as OmniSql \t command
713  auto cat_ptr = session_ptr_->get_catalog_ptr();
714  auto table_names =
715  cat_ptr->getTableNamesForUser(session_ptr_->get_currentUser(), GET_PHYSICAL_TABLES);
716  set_headers(_return, std::vector<std::string>{"table_name"});
717  // Place table names in query result
718  for (auto& table_name : table_names) {
719  add_row(_return, std::vector<std::string>{table_name});
720  }
721 }
722 
724  const rapidjson::Value& ddl_payload,
725  std::shared_ptr<Catalog_Namespace::SessionInfo const> session_ptr)
726  : DdlCommand(ddl_payload, session_ptr) {}
727 
728 void ShowDatabasesCommand::execute(TQueryResult& _return) {
729  const auto& user = session_ptr_->get_currentUser();
730  const Catalog_Namespace::DBSummaryList db_summaries =
732  set_headers(_return, {"Database", "Owner"});
733  for (const auto& db_summary : db_summaries) {
734  add_row(_return, {db_summary.dbName, db_summary.dbOwnerName});
735  }
736 }
737 
739  const rapidjson::Value& ddl_payload,
740  std::shared_ptr<Catalog_Namespace::SessionInfo const> session_ptr)
741  : DdlCommand(ddl_payload, session_ptr) {
742  if (!g_enable_fsi) {
743  throw std::runtime_error("Unsupported command: SHOW FOREIGN SERVERS");
744  }
745  // Verify that members are valid
746  CHECK(ddl_payload.HasMember("command"));
747  if (ddl_payload.HasMember("filters")) {
748  CHECK(ddl_payload["filters"].IsArray());
749  int num_filters = 0;
750  for (auto const& filter_def : ddl_payload["filters"].GetArray()) {
751  CHECK(filter_def.IsObject());
752  CHECK(filter_def.HasMember("attribute"));
753  CHECK(filter_def["attribute"].IsString());
754  CHECK(filter_def.HasMember("value"));
755  CHECK(filter_def["value"].IsString());
756  CHECK(filter_def.HasMember("operation"));
757  CHECK(filter_def["operation"].IsString());
758  if (num_filters > 0) {
759  CHECK(filter_def.HasMember("chain"));
760  CHECK(filter_def["chain"].IsString());
761  } else {
762  CHECK(!filter_def.HasMember("chain"));
763  }
764  num_filters++;
765  }
766  }
767 }
768 
769 void ShowForeignServersCommand::execute(TQueryResult& _return) {
770  const std::vector<std::string> col_names{
771  "server_name", "data_wrapper", "created_at", "options"};
772 
773  std::vector<const foreign_storage::ForeignServer*> results;
774  const auto& user = session_ptr_->get_currentUser();
775  if (ddl_payload_.HasMember("filters")) {
776  session_ptr_->getCatalog().getForeignServersForUser(
777  &ddl_payload_["filters"], user, results);
778  } else {
779  session_ptr_->getCatalog().getForeignServersForUser(nullptr, user, results);
780  }
781  set_headers(_return, col_names);
782 
783  _return.row_set.row_desc[2].col_type.type = TDatumType::type::TIMESTAMP;
784 
785  for (auto const& server_ptr : results) {
786  _return.row_set.columns[0].data.str_col.emplace_back(server_ptr->name);
787 
788  _return.row_set.columns[1].data.str_col.emplace_back(server_ptr->data_wrapper_type);
789 
790  _return.row_set.columns[2].data.int_col.push_back(server_ptr->creation_time);
791 
792  _return.row_set.columns[3].data.str_col.emplace_back(
793  server_ptr->getOptionsAsJsonString());
794 
795  for (size_t i = 0; i < _return.row_set.columns.size(); i++)
796  _return.row_set.columns[i].nulls.emplace_back(false);
797  }
798 }
799 
801  const rapidjson::Value& ddl_payload,
802  std::shared_ptr<Catalog_Namespace::SessionInfo const> session_ptr)
803  : DdlCommand(ddl_payload, session_ptr) {
804  CHECK(ddl_payload.HasMember("tableNames"));
805  CHECK(ddl_payload["tableNames"].IsArray());
806  for (auto const& tablename_def : ddl_payload["tableNames"].GetArray()) {
807  CHECK(tablename_def.IsString());
808  }
809 }
810 
811 void RefreshForeignTablesCommand::execute(TQueryResult& _return) {
812  bool evict_cached_entries{false};
814  if (ddl_payload_.HasMember("options") && !ddl_payload_["options"].IsNull()) {
815  opt.populateOptionsMap(ddl_payload_["options"]);
816  for (const auto entry : opt.options) {
817  if (entry.first != "EVICT") {
818  throw std::runtime_error{
819  "Invalid option \"" + entry.first +
820  "\" provided for refresh command. Only \"EVICT\" option is supported."};
821  }
822  }
823  CHECK(opt.options.find("EVICT") != opt.options.end());
824 
825  if (boost::iequals(opt.options["EVICT"], "true") ||
826  boost::iequals(opt.options["EVICT"], "false")) {
827  if (boost::iequals(opt.options["EVICT"], "true")) {
828  evict_cached_entries = true;
829  }
830  } else {
831  throw std::runtime_error{
832  "Invalid value \"" + opt.options["EVICT"] +
833  "\" provided for EVICT option. Value must be either \"true\" or \"false\"."};
834  }
835  }
836 
837  auto& cat = session_ptr_->getCatalog();
838  for (const auto& table_name_json : ddl_payload_["tableNames"].GetArray()) {
839  std::string table_name = table_name_json.GetString();
840  foreign_storage::refresh_foreign_table(cat, table_name, evict_cached_entries);
841  }
842 }
#define CHECK_EQ(x, y)
Definition: Logger.h:205
std::string partitions
static int getParam2(const rapidjson::Value &data_type)
std::map< std::string, std::string, std::less<> > options
static const AccessPrivileges DROP_SERVER
Definition: DBObject.h:190
static bool isArray(const rapidjson::Value &data_type)
void execute(TQueryResult &_return) override
Definition: sqltypes.h:51
SQLTypes
Definition: sqltypes.h:40
static std::vector< std::string_view > getSupportedOptions()
std::string getOptionsAsJsonString() const
void execute(TQueryResult &_return) override
static std::vector< std::string_view > getSupportedOptions()
static void validateOptions(const ForeignTable *foreign_table)
static WriteLock getWriteLockForTable(const Catalog_Namespace::Catalog &cat, const std::string &table_name)
Definition: LockMgrImpl.h:155
ShowDatabasesCommand(const rapidjson::Value &ddl_payload, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)
std::string storageType
void revokeDBObjectPrivilegesFromAll(DBObject object, Catalog *catalog)
void setRefreshOptions(foreign_storage::ForeignTable &foreign_table)
void execute(TQueryResult &_return) override
AlterForeignServerCommand(const rapidjson::Value &ddl_payload, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)
#define UNREACHABLE()
Definition: Logger.h:241
void populateOptionsMap(const rapidjson::Value &ddl_options)
std::string fragments
DropForeignServerCommand(const rapidjson::Value &ddl_payload, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)
static int getEncodingParam(const rapidjson::Value &data_type)
DropForeignTableCommand(const rapidjson::Value &ddl_payload, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)
static int getArraySize(const rapidjson::Value &data_type)
void refresh_foreign_table(Catalog_Namespace::Catalog &catalog, const std::string &table_name, const bool evict_cached_entries)
static constexpr const char * MANUAL_REFRESH_TIMING_TYPE
Definition: ForeignTable.h:36
void createDBObject(const UserMetadata &user, const std::string &objectName, DBObjectType type, const Catalog_Namespace::Catalog &catalog, int32_t objectId=-1)
void validate_non_duplicate_column(const std::string &column_name, std::unordered_set< std::string > &upper_column_names)
Definition: DdlUtils.cpp:520
ShowTablesCommand(const rapidjson::Value &ddl_payload, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)
static const AccessPrivileges ALTER_SERVER
Definition: DBObject.h:191
This file contains the class specification and related data structures for Catalog.
void execute(TQueryResult &_return) override
const std::string getTargetQuerySessionToKill()
static SysCatalog & instance()
Definition: SysCatalog.h:286
This file contains the class specification and related data structures for SysCatalog.
std::string cat(Ts &&... args)
Classes representing a parse tree.
void execute(TQueryResult &_return) override
void setColumnDetails(std::list< ColumnDescriptor > &columns)
static constexpr const char * REFRESH_UPDATE_TYPE_KEY
Definition: ForeignTable.h:32
static const AccessPrivileges DROP_TABLE
Definition: DBObject.h:160
RefreshForeignTablesCommand(const rapidjson::Value &ddl_payload, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)
CreateForeignTableCommand(const rapidjson::Value &ddl_payload, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)
DBSummaryList getDatabaseListForUser(const UserMetadata &user)
void execute(TQueryResult &_return) override
bool g_enable_fsi
Definition: Catalog.cpp:91
static const AccessPrivileges CREATE_SERVER
Definition: DBObject.h:189
void validate_non_reserved_keyword(const std::string &column_name)
Definition: DdlUtils.cpp:529
specifies the content in-memory of a row in the column metadata table
CreateForeignServerCommand(const rapidjson::Value &ddl_payload, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)
void set_headers(TQueryResult &_return, const std::vector< std::string > &headers)
static const AccessPrivileges CREATE_TABLE
Definition: DBObject.h:159
std::string keyMetainfo
void set_default_table_attributes(const std::string &table_name, TableDescriptor &td, const int32_t column_count)
Definition: DdlUtils.cpp:506
void add_row(TQueryResult &_return, const std::vector< std::string > &row)
std::string to_upper(const std::string &str)
void set_column_descriptor(const std::string &column_name, ColumnDescriptor &cd, SqlType *column_type, const bool not_null, const Encoding *encoding)
Definition: DdlUtils.cpp:492
void execute(TQueryResult &_return)
Definition: sqltypes.h:54
Definition: sqltypes.h:55
std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr_
void execute(TQueryResult &_return) override
void validate_drop_table_type(const TableDescriptor *td, const TableType expected_table_type)
Definition: DdlUtils.cpp:537
static constexpr const char * ALL_REFRESH_UPDATE_TYPE
Definition: ForeignTable.h:33
void setTableDetails(const std::string &table_name, TableDescriptor &td, const size_t column_count)
rapidjson::Document ddl_query_
static constexpr const char * REFRESH_TIMING_TYPE_KEY
Definition: ForeignTable.h:29
#define CHECK(condition)
Definition: Logger.h:197
static constexpr char const * CSV
Definition: ForeignServer.h:35
static std::string * getEncodingName(const rapidjson::Value &data_type)
void execute(TQueryResult &_return) override
static SQLTypes getSqlType(const rapidjson::Value &data_type)
bool isDefaultServer(const std::string &server_name)
void execute(TQueryResult &_return) override
const rapidjson::Value & ddl_payload_
static void validateOptions(const ForeignTable *foreign_table)
std::list< DBSummary > DBSummaryList
Definition: SysCatalog.h:118
Definition: sqltypes.h:47
std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr_
DdlCommandExecutor(const std::string &ddl_statement, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)
specifies the content in-memory of a row in the table metadata table
static int getParam1(const rapidjson::Value &data_type)
static constexpr char const * FOREIGN_TABLE
#define IS_GEO(T)
Definition: sqltypes.h:174
static constexpr char const * PARQUET
Definition: ForeignServer.h:36
ShowForeignServersCommand(const rapidjson::Value &ddl_payload, std::shared_ptr< Catalog_Namespace::SessionInfo const > session_ptr)