OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NumGeometries.h
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, 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 #pragma once
18 
20 
21 namespace spatial_type {
22 
23 class NumGeometries : public Codegen {
24  public:
25  NumGeometries(const Analyzer::GeoOperator* geo_operator) : Codegen(geo_operator) {}
26 
27  size_t size() const final { return 1; }
28 
29  SQLTypeInfo getNullType() const final { return SQLTypeInfo(kINT); }
30 
31  const SQLTypeInfo getOperandTypeInfo(const size_t index) {
32  CHECK_EQ(index, size_t(0));
33  const auto operand = operator_->getOperand(0);
34  auto col_var = dynamic_cast<const Analyzer::ColumnVar*>(operand);
35  if (!col_var) {
36  throw std::runtime_error(getName() +
37  " requires a geo column as its input argument.");
38  }
39  return col_var->get_type_info();
40  }
41 
42  const Analyzer::Expr* getOperand(const size_t index) final {
43  CHECK_EQ(index, size_t(0));
44  if (operand_owned_) {
45  return operand_owned_.get();
46  }
47 
48  const auto operand = operator_->getOperand(0);
49  auto col_var = dynamic_cast<const Analyzer::ColumnVar*>(operand);
50  if (!col_var) {
51  throw std::runtime_error(getName() +
52  " requires a geo column as its input argument.");
53  }
54 
55  const auto& geo_ti = col_var->get_type_info();
56  if (!geo_ti.is_geometry()) {
57  throw std::runtime_error(getName() +
58  " requires a geo column as its input argument.");
59  }
60  is_nullable_ = !geo_ti.get_notnull();
61 
62  auto const geo_type = geo_ti.get_type();
63  int column_offset{};
64  switch (geo_type) {
65  case kMULTIPOLYGON:
66  column_offset = 3; // poly_rings
67  break;
68  case kMULTILINESTRING:
69  column_offset = 2; // ring_sizes
70  break;
71  case kMULTIPOINT:
72  column_offset = 1; // points
73  break;
74  case kPOINT:
75  case kLINESTRING:
76  case kPOLYGON:
77  column_offset = 1; // nothing to count, but allow through
78  break;
79  default:
80  UNREACHABLE();
81  }
82 
83  // create a new operand which is just the column to count, and codegen it
84  const auto column_id = col_var->getColumnKey().column_id + column_offset;
85  shared::ColumnKey column_key{col_var->getTableKey(), column_id};
86  const auto cd = get_column_descriptor(column_key);
87  CHECK(cd);
88 
89  operand_owned_ = std::make_unique<Analyzer::ColumnVar>(
90  cd->columnType, column_key, col_var->get_rte_idx());
91  return operand_owned_.get();
92  }
93 
94  // returns arguments lvs and null lv
95  std::tuple<std::vector<llvm::Value*>, llvm::Value*> codegenLoads(
96  const std::vector<llvm::Value*>& arg_lvs,
97  const std::vector<llvm::Value*>& pos_lvs,
98  CgenState* cgen_state) final {
99  CHECK_EQ(pos_lvs.size(), size());
100  CHECK_EQ(arg_lvs.size(), size_t(1));
101 
102  const auto& oper_ti = getOperandTypeInfo(0);
103  auto const is_multi_geo = IS_GEO_MULTI(oper_ti.get_type());
104 
105  // non-MULTI non-nullable geo, just return 1 (no function call)
106  if (!isNullable() && !is_multi_geo) {
107  auto* const one = cgen_state->llInt(1);
108  return {{one}, one};
109  }
110 
111  // will be a function call, the first two arguments
112  std::string fn_name("array_size");
113  auto& argument_lv = arg_lvs.front();
114  std::vector<llvm::Value*> array_size_args = {argument_lv, pos_lvs.front()};
115 
116  if (is_multi_geo) {
117  // MULTI geo, fetch and append element log size argument
118  const auto& elem_ti = getOperand(0)->get_type_info().get_elem_type();
119  uint32_t elem_log_sz_value{};
120  if (oper_ti.get_type() == kMULTIPOINT) {
121  // we must have been passed the coords column
122  CHECK(elem_ti.get_type() == kTINYINT);
123  // we want to return the number of points (two coords),
124  // so divide by either 8 (compressed) or 16 (uncompressed)
125  if (oper_ti.get_compression() == kENCODING_GEOINT) {
126  // number of INT pairs
127  elem_log_sz_value = 3;
128  } else {
129  // number of DOUBLE pairs
130  elem_log_sz_value = 4;
131  }
132  } else {
133  // some other count (ring_sizes or poly_sizes)
134  elem_log_sz_value = log2_bytes(elem_ti.get_logical_size());
135  }
136  array_size_args.push_back(cgen_state->llInt(elem_log_sz_value));
137  } else {
138  // non-MULTI but nullable geo, return 1 or NULL
139  fn_name += "_1";
140  }
141 
142  // nullable, add NULL value
143  if (isNullable()) {
144  fn_name += "_nullable";
145  array_size_args.push_back(cgen_state->inlineIntNull(getTypeInfo()));
146  }
147 
148  const auto total_num_geometries_lv = cgen_state->emitExternalCall(
149  fn_name, get_int_type(32, cgen_state->context_), array_size_args);
150 
151  return {{total_num_geometries_lv}, total_num_geometries_lv};
152  }
153 
154  std::vector<llvm::Value*> codegen(const std::vector<llvm::Value*>& args,
155  CodeGenerator::NullCheckCodegen* nullcheck_codegen,
156  CgenState* cgen_state,
157  const CompilationOptions& co) final {
158  CHECK_EQ(args.size(), size_t(1));
159  if (isNullable()) {
160  CHECK(nullcheck_codegen);
161  return {nullcheck_codegen->finalize(cgen_state->inlineIntNull(getTypeInfo()),
162  args.front())};
163  }
164  return {args.front()};
165  }
166 
167  protected:
168  std::unique_ptr<Analyzer::ColumnVar> operand_owned_;
169 };
170 
171 } // namespace spatial_type
#define CHECK_EQ(x, y)
Definition: Logger.h:301
NumGeometries(const Analyzer::GeoOperator *geo_operator)
Definition: NumGeometries.h:25
#define UNREACHABLE()
Definition: Logger.h:338
SQLTypeInfo getNullType() const final
Definition: NumGeometries.h:29
std::unique_ptr< Analyzer::ColumnVar > operand_owned_
llvm::Type * get_int_type(const int width, llvm::LLVMContext &context)
auto getTypeInfo() const
Definition: Codegen.h:34
const ColumnDescriptor * get_column_descriptor(const shared::ColumnKey &column_key)
Definition: Execute.h:213
const Analyzer::Expr * getOperand(const size_t index) final
Definition: NumGeometries.h:42
auto isNullable() const
Definition: Codegen.h:32
const SQLTypeInfo & get_type_info() const
Definition: Analyzer.h:79
std::tuple< std::vector< llvm::Value * >, llvm::Value * > codegenLoads(const std::vector< llvm::Value * > &arg_lvs, const std::vector< llvm::Value * > &pos_lvs, CgenState *cgen_state) final
Definition: NumGeometries.h:95
const Analyzer::GeoOperator * operator_
Definition: Codegen.h:67
#define CHECK(condition)
Definition: Logger.h:291
const SQLTypeInfo getOperandTypeInfo(const size_t index)
Definition: NumGeometries.h:31
std::string getName() const
Definition: Codegen.h:36
std::vector< llvm::Value * > codegen(const std::vector< llvm::Value * > &args, CodeGenerator::NullCheckCodegen *nullcheck_codegen, CgenState *cgen_state, const CompilationOptions &co) final
Analyzer::Expr * getOperand(const size_t index) const
Definition: Analyzer.cpp:4186
uint32_t log2_bytes(const uint32_t bytes)
Definition: Execute.h:198
Definition: sqltypes.h:72
size_t size() const final
Definition: NumGeometries.h:27
SQLTypeInfo get_elem_type() const
Definition: sqltypes.h:975
#define IS_GEO_MULTI(T)
Definition: sqltypes.h:317