OmniSciDB  c07336695a
CommandFunctors.h
Go to the documentation of this file.
1 #ifndef COMMANDFUNCTORS_H
2 #define COMMANDFUNCTORS_H
3 
5 #include "ThriftOps.h"
6 
7 #include "gen-cpp/MapD.h"
8 
9 #include "ClientContext.h" // Provides us with default class
10 #include "RegexSupport.h"
11 
12 #include <rapidjson/document.h>
13 #include <fstream>
14 #include <iostream>
15 #include <type_traits>
16 
18 #include "MapDServer.h"
19 
20 #include <boost/algorithm/string.hpp>
21 #include <boost/algorithm/string/join.hpp>
22 #include <boost/algorithm/string/predicate.hpp>
23 #include <boost/algorithm/string/trim.hpp>
24 #include <boost/preprocessor/facilities/overload.hpp>
25 
26 #include "Shared/base64.h"
27 
28 template <typename CONTEXT_OP_POLICY>
30  public:
31  using ThriftService = typename CONTEXT_OP_POLICY::ThriftServiceType;
32  using ContextType = typename CONTEXT_OP_POLICY::ContextType;
33 
34  static void get_all_roles(ContextType& context) {
35  context.role_names.clear();
36  thrift_op<kGET_ROLES>(context, [](ContextType& lambda_context) {
37  for (auto role_name : lambda_context.role_names) {
38  std::cout << role_name << std::endl;
39  }
40  });
41  }
42 
43  static void get_status(ContextType& context, std::ostream& output_stream = std::cout) {
44  auto success_op = [&output_stream](ContextType& lambda_context) {
45  time_t t = (time_t)lambda_context.cluster_status[0].start_time;
46  std::tm* tm_ptr = gmtime(&t);
47  char buf[12] = {0};
48  strftime(buf, 11, "%F", tm_ptr);
49  std::string server_version = lambda_context.cluster_status[0].version;
50 
51  output_stream << "The Server Version Number : "
52  << lambda_context.cluster_status[0].version << std::endl;
53  output_stream << "The Server Start Time : " << buf << " : " << tm_ptr->tm_hour
54  << ":" << tm_ptr->tm_min << ":" << tm_ptr->tm_sec << std::endl;
55  output_stream << "The Server edition : " << server_version << std::endl;
56 
57  if (lambda_context.cluster_status.size() > 1) {
58  output_stream << "The Number of Leaves : "
59  << lambda_context.cluster_status.size() - 1 << std::endl;
60  for (auto leaf = lambda_context.cluster_status.begin() + 1;
61  leaf != lambda_context.cluster_status.end();
62  ++leaf) {
63  t = (time_t)leaf->start_time;
64  buf[11] = 0;
65  std::tm* tm_ptr = gmtime(&t);
66  strftime(buf, 11, "%F", tm_ptr);
67  output_stream << "--------------------------------------------------"
68  << std::endl;
69  output_stream << "Name of Leaf : " << leaf->host_name
70  << std::endl;
71  if (server_version.compare(leaf->version) != 0) {
72  output_stream << "The Leaf Version Number : " << leaf->version
73  << std::endl;
74  std::cerr << "Version number mismatch!" << std::endl;
75  }
76  output_stream << "The Leaf Start Time : " << buf << " : "
77  << tm_ptr->tm_hour << ":" << tm_ptr->tm_min << ":"
78  << tm_ptr->tm_sec << std::endl;
79  }
80  }
81  };
82  thrift_op<kGET_SERVER_STATUS>(context, success_op);
83  }
84 
85  static void get_all_roles_for_user(ContextType& context) {
86  context.role_names.clear();
87  thrift_op<kGET_ROLES_FOR_USER>(
88  context, context.privs_user_name.c_str(), [](ContextType& lambda_context) {
89  if (lambda_context.role_names.size() == 0) {
90  std::cout << "No roles are granted to "
91  << lambda_context.privs_user_name.c_str() << std::endl;
92  } else {
93  for (auto role_name : lambda_context.role_names) {
94  std::cout << role_name << std::endl;
95  }
96  }
97  });
98  }
99 
100  static void get_dashboards(ContextType& context) {
101  context.dash_names.clear();
102  thrift_op<kGET_DASHBOARDS>(context, [](ContextType& lambda_context) {
103  if (lambda_context.dash_names.size() == 0) {
104  std::cout << "No dashboards to display." << std::endl;
105  } else {
106  std::cout << "Dashboard ID | Dashboard Name | Owner" << std::endl;
107  for (auto p : lambda_context.dash_names) {
108  std::cout << p.dashboard_id << " | " << p.dashboard_name << " | "
109  << p.dashboard_owner << std::endl;
110  }
111  }
112  });
113  }
114 };
115 
119 };
120 
121 template <typename CONTEXT_OPS_TYPE, typename TAG_TYPE = CmdDeterminant>
122 class CmdBase : public TAG_TYPE {
123  public:
124  static_assert(std::is_base_of<CmdDeterminant, TAG_TYPE>::value,
125  "TAG_TYPE must be derived from CmdDeterminant");
126 
127  using ContextOps = CONTEXT_OPS_TYPE;
128  using ContextType = typename ContextOps::ContextType;
129 
130  CmdBase(ContextType& context) : m_stashed_context_ref(context) {}
131 
132  protected:
133  ContextType& cmdContext() { return m_stashed_context_ref; }
134 
136 };
137 
139  public:
140  static bool replace(std::string& str, const std::string& from, const std::string& to) {
141  size_t start_pos = str.find(from);
142  if (start_pos == std::string::npos) {
143  return false;
144  }
145  str.replace(start_pos, from.length(), to);
146  return true;
147  }
148 };
149 
150 // The StandardCommand macro removes boilerplate that needs to be written
151 // for creating functors that perform commands (usually operations on a client
152 // context)
153 
154 #define StandardCommand_3(CommandName, CommandOperations, CommandTag) \
155  template <typename CONTEXT_OP_POLICY = DefaultContextOpPolicy, \
156  template <typename> class CONTEXT_OPS_TYPE = ContextOperations, \
157  typename COMMAND_TAG_TYPE = CommandTag> \
158  class CommandName##Cmd \
159  : public CmdBase<CONTEXT_OPS_TYPE<CONTEXT_OP_POLICY>, COMMAND_TAG_TYPE>, \
160  public CmdStringUtilities { \
161  public: \
162  using Super = CmdBase<CONTEXT_OPS_TYPE<CONTEXT_OP_POLICY>, COMMAND_TAG_TYPE>; \
163  using ContextOps = typename Super::ContextOps; \
164  using ContextType = typename Super::ContextType; \
165  CommandName##Cmd(typename Super::ContextType& c) : Super(c) {} \
166  using Super::cmdContext; \
167  template <typename PARAMETERS> \
168  void operator()(PARAMETERS const& p, std::ostream& output_stream = std::cout) { \
169  do { \
170  CommandOperations; \
171  } while (0); \
172  } \
173  }
174 
175 #define StandardCommand_2(CommandName, CommandOperations) \
176  StandardCommand_3(CommandName, CommandOperations, CmdDeterminant)
177 #define StandardCommand(...) BOOST_PP_OVERLOAD(StandardCommand_, __VA_ARGS__)(__VA_ARGS__)
178 
179 //
180 // Standard Command Definitions
181 //
182 
183 StandardCommand(Status, { ContextOps::get_status(cmdContext(), output_stream); });
184 
185 StandardCommand(CopyGeo, {
186  std::cout << "Error: The \\copygeo command is deprecated. Use: COPY <table> FROM "
187  "'<file>' WITH (geo='true');"
188  << std::endl;
189 });
190 
191 StandardCommand(RoleList, {
192  cmdContext().privs_user_name.clear();
193  cmdContext().privs_user_name = p[1]; // User name is the first parameter
194  ContextOps::get_all_roles_for_user(cmdContext());
195 });
196 
197 StandardCommand(Roles, ContextOps::get_all_roles(cmdContext()));
198 
200  ListUsers,
201  { returned_list_regex<kGET_USERS>(p, cmdContext(), output_stream); },
204  ListTables,
205  { returned_list_regex<kGET_PHYSICAL_TABLES>(p, cmdContext(), output_stream); },
208  ListViews,
209  { returned_list_regex<kGET_VIEWS>(p, cmdContext(), output_stream); },
211 
212 StandardCommand(Help, {
213  std::cout << "\\u [regex] List all users, optionally matching regex.\n";
214  std::cout << "\\l List all databases.\n";
215  std::cout << "\\t [regex] List all tables, optionally matching regex.\n";
216  std::cout << "\\v [regex] List all views, optionally matching regex.\n";
217  std::cout << "\\d <table> List all columns of a table or a view.\n";
218  std::cout << "\\c <database> <user> <password>.\n";
219  std::cout
220  << "\\db [database|...] Switch database. Use ... to switch to your default.\n";
221  std::cout << "\\dash List all dashboards accessible by user.\n";
222  std::cout << "\\o <table> Return a memory optimized schema based on current data "
223  "distribution in table.\n";
224  std::cout << "\\gpu Execute in GPU mode's.\n";
225  std::cout << "\\cpu Execute in CPU mode's.\n";
226  std::cout << "\\multiline Set multi-line command line mode.\n";
227  std::cout << "\\singleline Set single-line command line mode.\n";
228  std::cout << "\\historylen <number> Set history buffer size (default 100).\n";
229  std::cout << "\\timing Print timing information.\n";
230  std::cout << "\\notiming Do not print timing information.\n";
231  std::cout << "\\memory_summary Print memory usage summary.\n";
232  std::cout << "\\version Print OmniSci Server version.\n";
233  std::cout << "\\copy <file path> <table> Copy data from file to table.\n";
234  std::cout << "\\status Get status of the server and the leaf nodes.\n";
235  std::cout << "\\export_dashboard <dashboard name> <filename> <optional: dashboard "
236  "owner name> Exports a dashboard to a "
237  "file.\n";
238  std::cout << "\\import_dashboard <dashboard name> <filename> Imports a dashboard from "
239  "a file\n";
240  std::cout << "\\roles Reports all roles.\n";
241  std::cout << "\\role_list <userName> Reports all roles granted to user.\n";
242  std::cout << "\\privileges {<roleName>|<userName>} Reports all database objects "
243  "privileges granted to role or "
244  "user.\n";
245  std::cout << "\\object_privileges {database|table} <object_name> Reports all "
246  "privileges granted to an object for all "
247  "roles and users.\n";
248  std::cout << "\\detect {parquet} <file_name|s3_details> Reads a sample of the "
249  "specified file and returns a CREATE TABLE statement\n";
250  std::cout << "\\clear_cpu Releases CPU memory held by OmniSci server Data Manager\n";
251  std::cout << "\\clear_gpu Releases GPU memory held by OmniSci server Data Manager\n";
252 
253  std::cout << "\\q Quit.\n";
254  std::cout.flush();
255 });
256 
257 StandardCommand(ListDatabases, {
258  thrift_op<kGET_DATABASES>(cmdContext(), [&](ContextType& lambda_context) {
259  output_stream << "Database | Owner" << std::endl;
260  for (auto p : lambda_context.dbinfos_return) {
261  output_stream << p.db_name << " | " << p.db_owner << '\n';
262  }
263  output_stream.flush();
264  });
265 });
266 
267 StandardCommand(ConnectToDB, {
268  if (cmdContext().session != INVALID_SESSION_ID) {
269  thrift_op<kDISCONNECT>(cmdContext(), [&](ContextType& lambda_context) {
270  output_stream << "Disconnected from database " << cmdContext().db_name << std::endl;
271  });
272  }
273 
274  cmdContext().db_name = p[1];
275  cmdContext().user_name = p[2];
276  cmdContext().passwd = p[3];
277 
278  thrift_op<kCONNECT>(cmdContext(), [&](ContextType& lambda_context) {
279  output_stream << "User " << lambda_context.user_name << " connected to database "
280  << lambda_context.db_name << std::endl;
281  });
282 });
283 
284 StandardCommand(SwitchDatabase, {
285  if (p.size() == 2) {
286  if (p[1] == std::string("...")) {
287  cmdContext().db_name.clear();
288  } else {
289  cmdContext().db_name = p[1];
290  }
291  thrift_op<kSWITCH_DATABASE>(cmdContext(), [&](ContextType& lambda_context) {
292  output_stream << "User " << lambda_context.user_name << " switched to database "
293  << lambda_context.db_name << std::endl;
294  });
295  } else if (p.size() == 1) {
296  thrift_op<kREPORT_DATABASE>(cmdContext(), [&](ContextType& lambda_context) {
297  output_stream << "User " << lambda_context.user_name << " is using database "
298  << lambda_context.db_name << std::endl;
299  });
300  }
301 });
302 
303 StandardCommand(ListColumns, {
304  decltype(p[1])& table_name(p[1]);
305 
306  auto unserialize_key_metainfo =
307  [](const std::string key_metainfo) -> std::vector<std::string> {
308  std::vector<std::string> keys_with_spec;
309  rapidjson::Document document;
310  document.Parse(key_metainfo.c_str());
311  CHECK(!document.HasParseError());
312  CHECK(document.IsArray());
313  for (auto it = document.Begin(); it != document.End(); ++it) {
314  const auto& key_with_spec_json = *it;
315  CHECK(key_with_spec_json.IsObject());
316  const std::string type = key_with_spec_json["type"].GetString();
317  const std::string name = key_with_spec_json["name"].GetString();
318  auto key_with_spec = type + " (" + name + ")";
319  if (type == "SHARED DICTIONARY") {
320  key_with_spec += " REFERENCES ";
321  const std::string foreign_table = key_with_spec_json["foreign_table"].GetString();
322  const std::string foreign_column =
323  key_with_spec_json["foreign_column"].GetString();
324  key_with_spec += foreign_table + "(" + foreign_column + ")";
325  } else {
326  CHECK(type == "SHARD KEY");
327  }
328  keys_with_spec.push_back(key_with_spec);
329  }
330  return keys_with_spec;
331  };
332 
333  auto on_success_lambda = [&](ContextType& context) {
334  const auto table_details = context.table_details;
335  if (table_details.view_sql.empty()) {
336  std::string temp_holder(" ");
337  if (table_details.is_temporary) {
338  temp_holder = " TEMPORARY ";
339  }
340  output_stream << "CREATE" + temp_holder + "TABLE " + table_name + " (\n";
341  } else {
342  output_stream << "CREATE VIEW " + table_name + " AS " + table_details.view_sql
343  << "\n";
344  output_stream << "\n"
345  << "View columns:"
346  << "\n\n";
347  }
348  std::string comma_or_blank("");
349  for (TColumnType p : table_details.row_desc) {
350  if (p.is_system) {
351  continue;
352  }
353  std::string encoding = "";
354  if (p.col_type.type == TDatumType::STR) {
355  encoding = (p.col_type.encoding == 0
356  ? " ENCODING NONE"
357  : " ENCODING " + thrift_to_encoding_name(p.col_type) + "(" +
358  std::to_string(p.col_type.comp_param) + ")");
359  } else if (p.col_type.type == TDatumType::POINT ||
360  p.col_type.type == TDatumType::LINESTRING ||
361  p.col_type.type == TDatumType::POLYGON ||
362  p.col_type.type == TDatumType::MULTIPOLYGON) {
363  if (p.col_type.scale == 4326) {
364  encoding = (p.col_type.encoding == 0
365  ? " ENCODING NONE"
366  : " ENCODING " + thrift_to_encoding_name(p.col_type) + "(" +
367  std::to_string(p.col_type.comp_param) + ")");
368  }
369  } else {
370  encoding = (p.col_type.encoding == 0
371  ? ""
372  : " ENCODING " + thrift_to_encoding_name(p.col_type) + "(" +
373  std::to_string(p.col_type.comp_param) + ")");
374  }
375  output_stream << comma_or_blank << p.col_name << " " << thrift_to_name(p.col_type)
376  << (p.col_type.nullable ? "" : " NOT NULL") << encoding;
377  comma_or_blank = ",\n";
378  }
379  if (table_details.view_sql.empty()) {
380  const auto keys_with_spec = unserialize_key_metainfo(table_details.key_metainfo);
381  for (const auto& key_with_spec : keys_with_spec) {
382  output_stream << ",\n" << key_with_spec;
383  }
384  // push final ")\n";
385  output_stream << ")\n";
386  comma_or_blank = "";
387  std::string frag = "";
388  std::string page = "";
389  std::string row = "";
390  std::string partition_detail = "";
391  if (DEFAULT_FRAGMENT_ROWS != table_details.fragment_size) {
392  frag = "FRAGMENT_SIZE = " + std::to_string(table_details.fragment_size);
393  comma_or_blank = ", ";
394  }
395  if (table_details.shard_count) {
396  auto shard_count = table_details.shard_count;
397  if (context.cluster_status.size() > 1) {
398  size_t leaf_count = 0;
399  for (const auto& node : context.cluster_status) {
400  leaf_count += node.role == TRole::type::LEAF ? 1 : 0;
401  }
402  shard_count *= leaf_count;
403  }
404  frag += comma_or_blank + "SHARD_COUNT = " + std::to_string(shard_count);
405  comma_or_blank = ", ";
406  }
407  if (DEFAULT_PAGE_SIZE != table_details.page_size) {
408  page = comma_or_blank + "PAGE_SIZE = " + std::to_string(table_details.page_size);
409  comma_or_blank = ", ";
410  }
411  if (DEFAULT_MAX_ROWS != table_details.max_rows) {
412  row = comma_or_blank + "MAX_ROWS = " + std::to_string(table_details.max_rows);
413  comma_or_blank = ", ";
414  }
415  if (table_details.partition_detail != TPartitionDetail::DEFAULT) {
416  partition_detail = comma_or_blank + "PARTITIONS = ";
417  switch (table_details.partition_detail) {
418  case TPartitionDetail::REPLICATED:
419  partition_detail += "'REPLICATED'";
420  break;
421  case TPartitionDetail::SHARDED:
422  partition_detail += "'SHARDED'";
423  break;
424  default:
425  partition_detail += "'OTHER'";
426  break;
427  }
428  }
429  std::string with = frag + page + row + partition_detail;
430  if (with.length() > 0) {
431  output_stream << "WITH (" << with << ")\n";
432  }
433  } else {
434  output_stream << "\n";
435  }
436  };
437 
438  thrift_op<kGET_TABLE_DETAILS>(cmdContext(), table_name.c_str(), on_success_lambda);
439 });
440 
441 StandardCommand(ExportDashboard, {
442  decltype(p[1])& dashboard_name(p[1]);
443  decltype(p[2])& filename(p[2]);
444 
445  cmdContext().view_name = dashboard_name;
446  cmdContext().dashboard_owner = p.size() == 4 ? p[3] : "";
447 
448  thrift_op<kGET_DASHBOARDS>(
449  cmdContext(),
450  [&](ContextType& lambda_context) {
451  if (lambda_context.dash_names.size() == 0) {
452  output_stream << "No dashboards exist." << std::endl;
453  return;
454  }
455  std::vector<TDashboard> dashboards;
456  for (auto& dash : lambda_context.dash_names) {
457  if (dash.dashboard_name == lambda_context.view_name) {
458  dashboards.push_back(dash);
459  }
460  }
461  if (dashboards.size() == 0) {
462  output_stream << "Dashboard " + lambda_context.view_name + " does not exist"
463  << std::endl;
464  return;
465  }
466  int view_id;
467  if (dashboards.size() > 1 && p.size() == 3) {
468  output_stream
469  << "Multiple dashboards with name '" + lambda_context.view_name +
470  "' exist. To help disambiguate identical dashboards please try "
471  "\\export_dashboard <dash_name> <exportfile> <dash_owner>."
472  << std::endl;
473  return;
474  } else if (dashboards.size() > 1 && p.size() == 4) {
475  bool found = false;
476  for (auto& dash : dashboards) {
477  if (dash.dashboard_owner == lambda_context.dashboard_owner) {
478  view_id = dash.dashboard_id;
479  found = true;
480  }
481  }
482  if (!found) {
483  output_stream << "No dashboard with owner name '" +
484  lambda_context.dashboard_owner + "' found."
485  << std::endl;
486  return;
487  }
488  } else {
489  view_id = dashboards[0].dashboard_id;
490  }
491  cmdContext().dash_id = view_id;
492  thrift_op<kGET_DASHBOARD>(cmdContext(), [&](ContextType& lambda_context) {
493  output_stream << "Exporting dashboard "
494  << lambda_context.dash_return.dashboard_name << " to file "
495  << filename << std::endl; // create file and dump string to it
496  std::ofstream dashfile;
497  dashfile.open(filename);
498  if (dashfile.is_open()) {
499  dashfile << lambda_context.dash_return.dashboard_name << std::endl;
500  dashfile << lambda_context.dash_return.dashboard_metadata << std::endl;
501  dashfile << mapd::decode_base64(lambda_context.dash_return.dashboard_state);
502  dashfile.close();
503  } else {
504  output_stream << "Could not open file `" << filename << "`" << std::endl;
505  }
506  });
507  },
508  [&](ContextType&) { output_stream << "Failed to export dashboard." << std::endl; });
509 });
510 
511 StandardCommand(ImportDashboard, {
512  decltype(p[1])& dashboard_name(p[1]);
513  decltype(p[2])& filename(p[2]);
514 
515  cmdContext().view_name = dashboard_name;
516  // context.view_metadata = std::string("{\"table\":\"") + table_name +
517  // std::string("\",\"version\":\"v2\"}");
518  cmdContext().view_state = "";
519  cmdContext().view_metadata = "";
520  // read file to get view state
521  std::ifstream dashfile;
522  std::string state;
523  std::string old_name;
524  dashfile.open(filename);
525  if (dashfile.is_open()) {
526  std::getline(dashfile, old_name);
527  std::getline(dashfile, cmdContext().view_metadata);
528  std::getline(dashfile, state);
529  dashfile.close();
530  } else {
531  output_stream << "Could not open file `" << filename << "`" << std::endl;
532  return;
533  }
534 
535  if (!replace(state,
536  std::string("\"title\":\"" + old_name + "\","),
537  std::string("\"title\":\"" + cmdContext().view_name + "\","))) {
538  output_stream << "Failed to update title." << std::endl;
539  return;
540  }
541 
542  cmdContext().view_state = mapd::encode_base64(state);
543 
544  output_stream << "Importing dashboard " << cmdContext().view_name << " from file "
545  << filename << std::endl;
546  thrift_op<kIMPORT_DASHBOARD>(cmdContext(), DoNothing(), [&](ContextType&) {
547  output_stream << "Failed to import dashboard." << std::endl;
548  });
549 });
550 
551 StandardCommand(GetOptimizedSchema, {
552  decltype(p[1])& table_name(p[1]);
553 
554  auto get_row_count = [](const TQueryResult& query_result) -> size_t {
555  CHECK(!query_result.row_set.row_desc.empty());
556  if (query_result.row_set.columns.empty()) {
557  return 0;
558  }
559  CHECK_EQ(query_result.row_set.columns.size(), query_result.row_set.row_desc.size());
560  return query_result.row_set.columns.front().nulls.size();
561  };
562 
563  // runs a simple single integer value query and returns that single int value returned
564  auto run_query = [get_row_count](ContextType& context, std::string query) -> int {
565  thrift_op<kSQL>(context, query.c_str());
566  CHECK(get_row_count(context.query_return));
567  // std::cerr << "return value is " <<
568  // context.query_return.row_set.columns[0].data.int_col[0];
569  return context.query_return.row_set.columns[0].data.int_col[0];
570  };
571 
572  auto get_optimal_size = [run_query](ClientContext& context,
573  std::string table_name,
574  std::string col_name,
575  int col_type) -> int {
576  switch (col_type) {
577  case TDatumType::STR: {
578  int strings = run_query(
579  context, "select count(distinct " + col_name + ") from " + table_name + ";");
580  if (strings < pow(2, 8)) {
581  return 8;
582  } else {
583  if (strings < pow(2, 16)) {
584  return 16;
585  } else {
586  return 32;
587  }
588  }
589  }
590  case TDatumType::TIME: {
591  return 32;
592  }
593  case TDatumType::DATE:
594  case TDatumType::TIMESTAMP: {
595  return run_query(context,
596  "select case when (extract( epoch from mn) > -2147483648 and "
597  "extract (epoch from mx) < "
598  "2147483647) then 32 else 0 end from (select min(" +
599  col_name + ") mn, max(" + col_name + ") mx from " +
600  table_name + " );");
601  }
602  case TDatumType::BIGINT: {
603  return run_query(context,
604  "select case when (mn > -128 and mx < 127) then 8 else case "
605  "when (mn > -32768 and mx < 32767) "
606  "then 16 else case when (mn > -2147483648 and mx < 2147483647) "
607  "then 32 else 0 end end end from "
608  "(select min(" +
609  col_name + ") mn, max(" + col_name + ") mx from " +
610  table_name + " );");
611  }
612  case TDatumType::INT: {
613  return run_query(context,
614  "select case when (mn > -128 and mx < 127) then 8 else case "
615  "when (mn > -32768 and mx < 32767) "
616  "then 16 else 0 end end from "
617  "(select min(" +
618  col_name + ") mn, max(" + col_name + ") mx from " +
619  table_name + " );");
620  }
621  }
622  return 0;
623  };
624 
625  auto on_success_lambda = [&](ContextType& context) {
626  const auto table_details = context.table_details;
627  if (table_details.view_sql.empty()) {
628  output_stream << "CREATE TABLE " + table_name + " (\n";
629  } else {
630  std::cerr << "Can't optimize a view, only the underlying tables\n";
631  return;
632  }
633  std::string comma_or_blank("");
634  for (TColumnType p : table_details.row_desc) {
635  std::string encoding = "";
636  if (p.col_type.type == TDatumType::STR) {
637  encoding = (p.col_type.encoding == 0
638  ? " ENCODING NONE"
639  : " ENCODING " + thrift_to_encoding_name(p.col_type) + "(" +
640  std::to_string(get_optimal_size(
641  context, table_name, p.col_name, p.col_type.type)) +
642  ")");
643  } else if (p.col_type.type == TDatumType::POINT ||
644  p.col_type.type == TDatumType::LINESTRING ||
645  p.col_type.type == TDatumType::POLYGON ||
646  p.col_type.type == TDatumType::MULTIPOLYGON) {
647  if (p.col_type.scale == 4326) {
648  encoding = (p.col_type.encoding == 0
649  ? " ENCODING NONE"
650  : " ENCODING " + thrift_to_encoding_name(p.col_type) + "(" +
651  std::to_string(p.col_type.comp_param) + ")");
652  }
653  } else {
654  int opt_size = get_optimal_size(context, table_name, p.col_name, p.col_type.type);
655  encoding =
656  (opt_size == 0 ? "" : " ENCODING FIXED(" + std::to_string(opt_size) + ")");
657  }
658  output_stream << comma_or_blank << p.col_name << " " << thrift_to_name(p.col_type)
659  << (p.col_type.nullable ? "" : " NOT NULL") << encoding;
660  comma_or_blank = ",\n";
661  }
662  // push final "\n";
663  if (table_details.view_sql.empty()) {
664  output_stream << ")\n";
665  comma_or_blank = "";
666  std::string frag = "";
667  std::string page = "";
668  std::string row = "";
669  if (DEFAULT_FRAGMENT_ROWS != table_details.fragment_size) {
670  frag = " FRAGMENT_SIZE = " + std::to_string(table_details.fragment_size);
671  comma_or_blank = ",";
672  }
673  if (DEFAULT_PAGE_SIZE != table_details.page_size) {
674  page = comma_or_blank + " PAGE_SIZE = " + std::to_string(table_details.page_size);
675  comma_or_blank = ",";
676  }
677  if (DEFAULT_MAX_ROWS != table_details.max_rows) {
678  row = comma_or_blank + " MAX_ROWS = " + std::to_string(table_details.max_rows);
679  }
680  std::string with = frag + page + row;
681  if (with.length() > 0) {
682  output_stream << "WITH (" << with << ")\n";
683  }
684  } else {
685  output_stream << "\n";
686  }
687  };
688 
689  thrift_op<kGET_TABLE_DETAILS>(cmdContext(), table_name.c_str(), on_success_lambda);
690 });
691 
692 StandardCommand(ListDashboards, ContextOps::get_dashboards(cmdContext()));
693 
694 #endif
static bool replace(std::string &str, const std::string &from, const std::string &to)
#define CHECK_EQ(x, y)
Definition: Logger.h:195
#define StandardCommand(...)
typename ContextOps::ContextType ContextType
CmdBase(ContextType &context)
#define DEFAULT_MAX_ROWS
TTableDetails table_details
#define INVALID_SESSION_ID
static void get_all_roles_for_user(ContextType &context)
size_t get_row_count(const TQueryResult &query_result)
Definition: omnisql.cpp:211
std::string to_string(char const *&&v)
static void get_status(ContextType &context, std::ostream &output_stream=std::cout)
MetaClientContext< MapDClient &, TTransport & > ClientContext
Definition: ClientContext.h:6
CONTEXT_OPS_TYPE ContextOps
#define DEFAULT_PAGE_SIZE
static void get_all_roles(ContextType &context)
std::string decode_base64(const std::string &val, bool trim_nulls)
Definition: base64.h:26
std::string thrift_to_encoding_name(const TTypeInfo &ti)
std::string thrift_to_name(const TTypeInfo &ti)
typename CONTEXT_OP_POLICY::ThriftServiceType ThriftService
std::shared_ptr< ResultSet > run_query(const std::string &query_str)
#define DEFAULT_FRAGMENT_ROWS
#define CHECK(condition)
Definition: Logger.h:187
typename CONTEXT_OP_POLICY::ContextType ContextType
ContextType & m_stashed_context_ref
ThriftService
Definition: ThriftService.h:4
TSessionId session
static void get_dashboards(ContextType &context)
ContextType & cmdContext()
static std::string encode_base64(const std::string &val)
Definition: base64.h:44