OmniSciDB  04ee39c94c
AlterColumnTest.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 #include <gtest/gtest.h>
18 
19 #include <boost/algorithm/string.hpp>
20 #include <boost/iterator/counting_iterator.hpp>
21 #include "boost/filesystem.hpp"
22 
23 #include "Catalog/Catalog.h"
25 #include "Import/Importer.h"
26 #include "Parser/parser.h"
27 #include "QueryEngine/ResultSet.h"
29 #include "Shared/UpdelRoll.h"
30 #include "Shared/geo_types.h"
31 #include "Tests/TestHelpers.h"
32 
33 #include <tuple>
34 #ifndef BASE_PATH
35 #define BASE_PATH "./tmp"
36 #endif
37 
38 using namespace Catalog_Namespace;
39 using namespace TestHelpers;
40 
42 
43 namespace {
44 
45 bool g_hoist_literals{true};
46 
47 inline void run_ddl_statement(const std::string& input_str) {
48  QR::get()->runDDLStatement(input_str);
49 }
50 
51 std::shared_ptr<ResultSet> run_query(const std::string& query_str) {
52  return QR::get()->runSQL(query_str, ExecutorDeviceType::CPU, g_hoist_literals, true);
53 }
54 
55 template <typename E = std::runtime_error>
56 bool alter_common(const std::string& table,
57  const std::string& column,
58  const std::string& type,
59  const std::string& comp,
60  const std::string& val,
61  const std::string& val2,
62  const bool expect_throw = false) {
63  std::string alter_query = "alter table " + table + " add column " + column + " " + type;
64  if (val != "") {
65  alter_query += " default " + val;
66  }
67  if (comp != "") {
68  alter_query += " encoding " + comp;
69  }
70 
71  if (expect_throw) {
72  EXPECT_THROW(run_ddl_statement(alter_query + ";"), E);
73  return true;
74  } else {
75  EXPECT_NO_THROW(run_ddl_statement(alter_query + ";"););
76  }
77 
78  if (val2 != "") {
79  std::string query_str = "SELECT " + column + " FROM " + table;
80  auto rows = run_query(query_str + ";");
81  int r_cnt = 0;
82  while (true) {
83  auto crt_row = rows->getNextRow(true, true);
84  if (0 == crt_row.size()) {
85  break;
86  }
87  auto geo = boost::get<std::string>(v<NullableString>(crt_row[0]));
88 #if 1
89  if (geo == val2) {
90  ++r_cnt;
91  }
92 #else
93  // somehow these do not work as advertised ...
94  using namespace Geo_namespace;
95  if (boost::iequals(type, "POINT") && GeoPoint(geo) == GeoPoint(val2))
96  ++r_cnt;
97  else if (boost::iequals(type, "LINESTRING") &&
98  GeoLineString(geo) == GeoLineString(val2))
99  ++r_cnt;
100  else if (boost::iequals(type, "POLYGON") && GeoPolygon(geo) == GeoPolygon(val2))
101  ++r_cnt;
102  else if (boost::iequals(type, "MULTIPOLYGON") &&
103  GeoMultiPolygon(geo) == GeoMultiPolygon(val2))
104  ++r_cnt;
105 #endif
106  }
107  return r_cnt == 100;
108  } else {
109  std::string query_str =
110  "SELECT count(*) FROM " + table + " WHERE " + column +
111  ("" == val || boost::iequals("NULL", val) ? " IS NULL" : (" = " + val));
112  auto rows = run_query(query_str + ";");
113  auto crt_row = rows->getNextRow(true, true);
114  CHECK_EQ(size_t(1), crt_row.size());
115  auto r_cnt = v<int64_t>(crt_row[0]);
116  return r_cnt == 100;
117  }
118 }
119 
120 void import_table_file(const std::string& table, const std::string& file) {
121  const auto query_str = std::string("COPY trips FROM '") +
122  "../../Tests/Import/datafiles/" + file +
123  "' WITH (header='true');";
124 
125  SQLParser parser;
126  std::list<std::unique_ptr<Parser::Stmt>> parse_trees;
127  std::string last_parsed;
128  if (parser.parse(query_str, parse_trees, last_parsed)) {
129  throw std::runtime_error("Failed to parse: " + query_str);
130  }
131  CHECK_EQ(parse_trees.size(), size_t(1));
132 
133  const auto& stmt = parse_trees.front();
134  auto copy_stmt = dynamic_cast<Parser::CopyTableStmt*>(stmt.get());
135  if (!copy_stmt) {
136  throw std::runtime_error("Expected a CopyTableStatment: " + query_str);
137  }
138  QR::get()->runImport(copy_stmt);
139 }
140 
141 // don't use R"()" format; somehow it causes many blank lines
142 // to be output on console. how come?
143 const char* create_table_trips =
144  " CREATE TABLE trips ("
145  " medallion TEXT ENCODING DICT,"
146  " hack_license TEXT ENCODING DICT,"
147  " vendor_id TEXT ENCODING DICT,"
148  " rate_code_id SMALLINT,"
149  " store_and_fwd_flag TEXT ENCODING DICT,"
150  " pickup_datetime TIMESTAMP,"
151  " dropoff_datetime TIMESTAMP,"
152  " passenger_count SMALLINT,"
153  " trip_time_in_secs INTEGER,"
154  " trip_distance FLOAT,"
155  " pickup_longitude DECIMAL(14,7),"
156  " pickup_latitude DECIMAL(14,7),"
157  " dropoff_longitude DOUBLE,"
158  " dropoff_latitude DECIMAL(18,5),"
159  " deleted BOOLEAN"
160  " ) WITH (FRAGMENT_SIZE=50);"; // so 2 fragments here
161 
162 void init_table_data(const std::string& table = "trips",
163  const std::string& create_table_cmd = create_table_trips,
164  const std::string& file = "trip_data_b.txt") {
165  run_ddl_statement("drop table if exists " + table + ";");
166  run_ddl_statement(create_table_cmd);
167  if (file.size()) {
168  import_table_file(table, file);
169  }
170 }
171 
172 class AlterColumnTest : public ::testing::Test {
173  protected:
174  void SetUp() override { ASSERT_NO_THROW(init_table_data();); }
175  void TearDown() override { ASSERT_NO_THROW(run_ddl_statement("drop table trips;");); }
176 };
177 
178 #define MT std::make_tuple
179 std::vector<std::tuple<std::string, std::string, std::string, std::string>> type_vals = {
180  MT("text", "none", "'abc'", ""),
181  MT("text", "dict(8)", "'ijk'", ""),
182  MT("text", "dict(32)", "'xyz'", ""),
183  MT("float", "", "1.25", ""),
184  MT("double", "", "1.25", ""),
185  MT("smallint", "", "123", ""),
186  MT("integer", "", "123", ""),
187  MT("bigint", "", "123", ""),
188  MT("bigint encoding fixed(8)", "", "", ""),
189  MT("bigint encoding fixed(16)", "", "", ""),
190  MT("bigint encoding fixed(32)", "", "", ""),
191  MT("decimal(8)", "", "123", ""),
192  MT("decimal(8,2)", "", "1.23", ""),
193  MT("date", "", "'2011-10-23'", ""),
194  MT("time", "", "'10:23:45'", ""),
195  MT("timestamp", "", "'2011-10-23 10:23:45'", ""),
196  MT("POINT", "", "'POINT (1 2)'", "POINT (1 2)"),
197  MT("LINESTRING", "", "'LINESTRING (1 1,2 2,3 3)'", "LINESTRING (1 1,2 2,3 3)"),
198  MT("POLYGON",
199  "",
200  "'POLYGON((0 0,0 9,9 9,9 0),(1 1,2 2,3 3))'",
201  "POLYGON ((9 0,9 9,0 9,0 0,9 0),(3 3,2 2,1 1,3 3))"),
202  MT("MULTIPOLYGON",
203  "",
204  "'MULTIPOLYGON(((0 0,0 9,9 9,9 0),(1 1,2 2,3 3)))'",
205  "MULTIPOLYGON (((9 0,9 9,0 9,0 0,9 0),(3 3,2 2,1 1,3 3)))"),
206 };
207 #undef MT
208 
209 TEST_F(AlterColumnTest, Add_column_with_default) {
210  int cid = 0;
211  for (const auto& tv : type_vals) {
212  EXPECT_TRUE(alter_common("trips",
213  "x" + std::to_string(++cid),
214  std::get<0>(tv),
215  std::get<1>(tv),
216  std::get<2>(tv),
217  std::get<3>(tv),
218  false));
219  }
220 }
221 
222 TEST_F(AlterColumnTest, Add_column_with_null) {
223  int cid = 0;
224  for (const auto& tv : type_vals) {
225  if (std::get<3>(tv) == "") {
226  EXPECT_TRUE(alter_common("trips",
227  "x" + std::to_string(++cid),
228  std::get<0>(tv),
229  std::get<1>(tv),
230  "",
231  "",
232  false));
233  } else {
234  EXPECT_TRUE(alter_common("trips",
235  "x" + std::to_string(++cid),
236  std::get<0>(tv),
237  std::get<1>(tv),
238  "",
239  std::get<3>(tv),
240  true));
241  }
242  }
243 }
244 
245 TEST(AlterColumnTest2, Drop_after_fail_to_add) {
246  EXPECT_NO_THROW(run_ddl_statement("drop table if exists t;"););
247  EXPECT_NO_THROW(run_ddl_statement("create table t(c1 int);"););
248  EXPECT_NO_THROW(run_query("insert into t values (10);"););
249  EXPECT_THROW(
250  run_ddl_statement("alter table t add column c2 TEXT NOT NULL ENCODING DICT;"),
251  std::runtime_error);
252  EXPECT_NO_THROW(run_ddl_statement("drop table t;"););
253 }
254 
255 } // namespace
256 
257 int main(int argc, char** argv) {
259  testing::InitGoogleTest(&argc, argv);
260 
262 
263  int err{0};
264  try {
265  err = RUN_ALL_TESTS();
266  } catch (const std::exception& e) {
267  LOG(ERROR) << e.what();
268  }
269  QR::reset();
270  return err;
271 }
#define CHECK_EQ(x, y)
Definition: Logger.h:195
std::vector< std::tuple< std::string, std::string, std::string, std::string > > type_vals
#define LOG(tag)
Definition: Logger.h:182
void import_table_file(const std::string &table, const std::string &file)
std::string to_string(char const *&&v)
static QueryRunner * init(const char *db_path, const std::string &udf_filename="", const size_t max_gpu_mem=0, const int reserved_gpu_mem=256<< 20)
Definition: QueryRunner.h:70
virtual std::shared_ptr< ResultSet > runSQL(const std::string &query_str, const ExecutorDeviceType device_type, const bool hoist_literals=true, const bool allow_loop_joins=true)
This file contains the class specification and related data structures for Catalog.
void init_table_data(const std::string &table="trips", const std::string &create_table_cmd=create_table_trips, const std::string &file="trip_data_b.txt")
virtual void runImport(Parser::CopyTableStmt *import_stmt)
virtual void runDDLStatement(const std::string &)
bool alter_common(const std::string &table, const std::string &column, const std::string &type, const std::string &comp, const std::string &val, const std::string &val2, const bool expect_throw=false)
static QueryRunner * get()
Definition: QueryRunner.h:115
int main(int argc, char **argv)
std::shared_ptr< ResultSet > run_query(const std::string &query_str)
void init_logger_stderr_only(int argc, char const *const *argv)
Definition: TestHelpers.h:194
TEST(AlterColumnTest2, Drop_after_fail_to_add)
Basic constructors and methods of the row set interface.
#define MT
TEST_F(AlterColumnTest, Add_column_with_null)
void run_ddl_statement(std::string ddl)
#define BASE_PATH