OmniSciDB  04ee39c94c
UdfTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019 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 <gtest/gtest.h>
18 #include <boost/filesystem.hpp>
19 #include <boost/filesystem/operations.hpp>
20 #include <csignal>
21 #include <exception>
22 #include <memory>
23 #include <vector>
24 #include "Catalog/Catalog.h"
25 #include "Catalog/DBObject.h"
26 #include "DataMgr/DataMgr.h"
27 #include "QueryEngine/Execute.h"
29 #include "QueryEngine/ResultSet.h"
32 #include "Shared/Logger.h"
33 #include "Shared/MapDParameters.h"
34 #include "TestHelpers.h"
35 
36 #ifndef BASE_PATH
37 #define BASE_PATH "./tmp"
38 #endif
39 
40 using namespace Catalog_Namespace;
41 using namespace TestHelpers;
42 
44 
45 #define SKIP_NO_GPU() \
46  if (skip_tests(dt)) { \
47  CHECK(dt == ExecutorDeviceType::GPU); \
48  LOG(WARNING) << "GPU not available, skipping GPU tests"; \
49  continue; \
50  }
51 
52 namespace {
53 
54 std::shared_ptr<Calcite> g_calcite = nullptr;
55 std::string udf_file_name_base("../../Tests/Udf/udf_sample");
56 
57 std::shared_ptr<ResultSet> run_multiple_agg(const std::string& query_str,
58  const ExecutorDeviceType device_type,
59  const bool allow_loop_joins) {
60  return QR::get()->runSQL(query_str, device_type, true, allow_loop_joins);
61 }
62 
63 std::shared_ptr<ResultSet> run_multiple_agg(const std::string& query_str,
64  const ExecutorDeviceType device_type) {
65  return run_multiple_agg(query_str, device_type, true);
66 }
67 
68 TargetValue run_simple_agg(const std::string& query_str,
69  const ExecutorDeviceType device_type,
70  const bool allow_loop_joins = true) {
71  auto rows = run_multiple_agg(query_str, device_type, allow_loop_joins);
72  auto crt_row = rows->getNextRow(true, true);
73  CHECK_EQ(size_t(1), crt_row.size());
74  return crt_row[0];
75 }
76 
77 std::string get_udf_filename() {
78  return udf_file_name_base + ".cpp";
79 }
80 
81 std::string get_udf_cpu_ir_filename() {
82  return udf_file_name_base + "_cpu.bc";
83 }
84 
85 std::string get_udf_gpu_ir_filename() {
86  return udf_file_name_base + "_gpu.bc";
87 }
88 
89 std::string get_udf_ast_filename() {
90  return udf_file_name_base + ".ast";
91 }
92 
93 bool skip_tests(const ExecutorDeviceType device_type) {
94 #ifdef HAVE_CUDA
95  return device_type == ExecutorDeviceType::GPU && !QR::get()->gpusPresent();
96 #else
97  return device_type == ExecutorDeviceType::GPU;
98 #endif
99 }
100 
101 inline void run_ddl_statement(const std::string& query) {
102  QR::get()->runDDLStatement(query);
103 }
104 
105 class SQLTestEnv : public ::testing::Environment {
106  public:
107  void SetUp() override {
108  boost::filesystem::path udf_file((get_udf_filename()));
109  if (!boost::filesystem::exists(udf_file)) {
110  throw std::runtime_error("udf file: " + udf_file.string() + " does not exist");
111  }
112 
113  UdfCompiler compiler(udf_file.string());
114  auto compile_result = compiler.compileUdf();
115  EXPECT_EQ(compile_result, 0);
116 
117  QR::init(BASE_PATH, compiler.getAstFileName());
118 
119  g_calcite = QR::get()->getCalcite();
120  }
121 
122  void TearDown() override {
123  boost::filesystem::path cpu_ir_file(get_udf_cpu_ir_filename());
124  if (boost::filesystem::exists(cpu_ir_file)) {
125  boost::filesystem::remove(cpu_ir_file);
126  }
127 
128  boost::filesystem::path gpu_ir_file(get_udf_gpu_ir_filename());
129  if (boost::filesystem::exists(gpu_ir_file)) {
130  boost::filesystem::remove(gpu_ir_file);
131  }
132 
133  boost::filesystem::path udf_ast_file(get_udf_ast_filename());
134  if (boost::filesystem::exists(udf_ast_file)) {
135  boost::filesystem::remove(udf_ast_file);
136  }
137 
138  QR::reset();
139  }
140 };
141 } // namespace
142 
143 class UDFCompilerTest : public ::testing::Test {
144  protected:
145  UDFCompilerTest() : udf_file_(boost::filesystem::path(get_udf_filename())) {
146  if (!boost::filesystem::exists(udf_file_)) {
147  throw std::runtime_error("udf file: " + udf_file_.string() + " does not exist");
148  }
149 
150  setup_objects();
151  }
152 
153  ~UDFCompilerTest() override { remove_objects(); }
154 
155  void SetUp() override {}
156 
157  void TearDown() override {}
158 
159  void setup_objects() {}
160 
161  void remove_objects() {}
162 
163  std::string getUdfFileName() const { return udf_file_.string(); }
164 
165  private:
166  boost::filesystem::path udf_file_;
167 };
168 
169 TEST_F(UDFCompilerTest, CompileTest) {
170  UdfCompiler compiler(getUdfFileName());
171  auto compile_result = compiler.compileUdf();
172 
173  EXPECT_EQ(compile_result, 0);
174  // TODO cannot test invalid file path because the compileUdf function uses
175  // LOG(FATAL) which stops the process and does not return
176 }
177 
178 TEST_F(UDFCompilerTest, CalciteRegistration) {
179  UdfCompiler compiler(getUdfFileName());
180  auto compile_result = compiler.compileUdf();
181 
182  ASSERT_EQ(compile_result, 0);
183 
184  ASSERT_TRUE(g_calcite != nullptr);
185 
186  auto signature = ExtensionFunctionsWhitelist::get_udf("udf_truerange");
187  ASSERT_NE(signature, nullptr);
188 
189  auto signature2 = ExtensionFunctionsWhitelist::get_udf("udf_truehigh");
190  ASSERT_NE(signature2, nullptr);
191 
192  auto signature3 = ExtensionFunctionsWhitelist::get_udf("udf_truelow");
193  ASSERT_NE(signature3, nullptr);
194 
195  auto signature4 = ExtensionFunctionsWhitelist::get_udf("udf_range");
196  ASSERT_NE(signature4, nullptr);
197 
198  auto signature5 = ExtensionFunctionsWhitelist::get_udf("udf_range_int");
199  ASSERT_NE(signature5, nullptr);
200 
201  auto signature6 = ExtensionFunctionsWhitelist::get_udf("udf_range_integer");
202  ASSERT_EQ(signature6, nullptr);
203 }
204 
206  UdfCompiler compiler(getUdfFileName());
207  auto compile_result = compiler.compileUdf();
208 
209  ASSERT_EQ(compile_result, 0);
210 
211  run_ddl_statement("DROP TABLE IF EXISTS stocks;");
213  "CREATE TABLE stocks(symbol text, open_p int, high_p int, "
214  "low_p int, close_p int, entry_d DATE);");
215 
216  std::string insert1(
217  "INSERT into stocks VALUES ('NVDA', '178', '178', '171', '173', '2019-05-07');");
218  EXPECT_NO_THROW(run_multiple_agg(insert1, ExecutorDeviceType::CPU));
219 
220  std::string insert2(
221  "INSERT into stocks VALUES ('NVDA', '175', '181', '174', '178', '2019-05-06');");
222  EXPECT_NO_THROW(run_multiple_agg(insert2, ExecutorDeviceType::CPU));
223 
224  std::string insert3(
225  "INSERT into stocks VALUES ('NVDA', '183', '184', '181', '183', '2019-05-03');");
226  EXPECT_NO_THROW(run_multiple_agg(insert3, ExecutorDeviceType::CPU));
227 
229  SKIP_NO_GPU();
230  ASSERT_EQ(7,
231  v<int64_t>(run_simple_agg("SELECT udf_range_int(high_p, low_p) from stocks "
232  "where entry_d = '2019-05-06';",
233  dt)));
234  ASSERT_EQ(3,
235  v<int64_t>(run_simple_agg("SELECT udf_range_int(high_p, low_p) from stocks "
236  "where entry_d = '2019-05-03';",
237  dt)));
238  }
239 
240  EXPECT_THROW(run_simple_agg("SELECT udf_range_integer(high_p, low_p) from stocks where "
241  "entry_d = '2019-05-06';",
243  std::exception);
244 
245  run_ddl_statement("DROP TABLE stocks;");
246 }
247 
248 int main(int argc, char** argv) {
250  ::testing::InitGoogleTest(&argc, argv);
251  ::testing::AddGlobalTestEnvironment(new SQLTestEnv);
252 
253  int err{0};
254  try {
255  err = RUN_ALL_TESTS();
256  } catch (const std::exception& e) {
257  LOG(ERROR) << e.what();
258  }
259  return err;
260 }
std::shared_ptr< Calcite > getCalcite() const
#define CHECK_EQ(x, y)
Definition: Logger.h:195
boost::filesystem::path udf_file_
Definition: UdfTest.cpp:166
void TearDown() override
Definition: UdfTest.cpp:157
void setup_objects()
Definition: UdfTest.cpp:159
ExecutorDeviceType
#define LOG(tag)
Definition: Logger.h:182
External interface for parsing AST and bitcode files.
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)
void remove_objects()
Definition: UdfTest.cpp:161
This file contains the class specification and related data structures for Catalog.
TEST_F(UDFCompilerTest, CompileTest)
Definition: UdfTest.cpp:169
static std::vector< ExtensionFunction > * get_udf(const std::string &name)
std::string getUdfFileName() const
Definition: UdfTest.cpp:163
int main(int argc, char **argv)
Definition: UdfTest.cpp:248
virtual void runDDLStatement(const std::string &)
std::shared_ptr< Calcite > g_calcite
Definition: UdfTest.cpp:54
static QueryRunner * get()
Definition: QueryRunner.h:115
int compileUdf()
std::string get_udf_cpu_ir_filename()
Definition: UdfTest.cpp:81
void SetUp() override
Definition: UdfTest.cpp:155
void init_logger_stderr_only(int argc, char const *const *argv)
Definition: TestHelpers.h:194
std::string get_udf_gpu_ir_filename()
Definition: UdfTest.cpp:85
std::string udf_file_name_base("../../Tests/Udf/udf_sample")
TargetValue run_simple_agg(const std::string &query_str, const ExecutorDeviceType device_type, const bool allow_loop_joins=true)
Definition: UdfTest.cpp:68
bool skip_tests(const ExecutorDeviceType device_type)
Definition: UdfTest.cpp:93
std::string get_udf_ast_filename()
Definition: UdfTest.cpp:89
#define SKIP_NO_GPU()
Definition: UdfTest.cpp:45
Basic constructors and methods of the row set interface.
~UDFCompilerTest() override
Definition: UdfTest.cpp:153
boost::variant< ScalarTargetValue, ArrayTargetValue, GeoTargetValue, GeoTargetValuePtr > TargetValue
Definition: TargetValue.h:167
void run_ddl_statement(std::string ddl)
#define BASE_PATH
Definition: UdfTest.cpp:37
TQueryResult run_multiple_agg(std::string sql)