OmniSciDB  b24e664e58
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
RelAlgTranslatorGeo.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 "../Shared/geo_types.h"
18 #include "ExpressionRewrite.h"
19 #include "RelAlgTranslator.h"
20 
21 std::vector<std::shared_ptr<Analyzer::Expr>> RelAlgTranslator::translateGeoColumn(
22  const RexInput* rex_input,
23  SQLTypeInfo& ti,
24  const bool with_bounds,
25  const bool with_render_group,
26  const bool expand_geo_col) const {
27  std::vector<std::shared_ptr<Analyzer::Expr>> args;
28  const auto source = rex_input->getSourceNode();
29  const auto it_rte_idx = input_to_nest_level_.find(source);
30  CHECK(it_rte_idx != input_to_nest_level_.end());
31  const int rte_idx = it_rte_idx->second;
32  const auto& in_metainfo = source->getOutputMetainfo();
33 
34  int32_t table_id{0};
35  int column_id{-1};
36  const auto scan_source = dynamic_cast<const RelScan*>(source);
37  if (scan_source) {
38  // We're at leaf (scan) level and not supposed to have input metadata,
39  // the name and type information come directly from the catalog.
40  CHECK(in_metainfo.empty());
41 
42  const auto td = scan_source->getTableDescriptor();
43  table_id = td->tableId;
44 
45  const auto gcd = cat_.getMetadataForColumnBySpi(table_id, rex_input->getIndex() + 1);
46  CHECK(gcd);
47  ti = gcd->columnType;
48  column_id = gcd->columnId;
49 
50  } else {
51  // Likely backed by a temp table. Read the table ID from the source node and negate it
52  // (see RelAlgTranslator::translateInput)
53  table_id = -source->getId();
54 
55  CHECK(!expand_geo_col);
56 
57  CHECK(!in_metainfo.empty());
58  CHECK_GE(rte_idx, 0);
59  column_id = rex_input->getIndex();
60  CHECK_LT(static_cast<size_t>(column_id), in_metainfo.size());
61  ti = in_metainfo[column_id].get_type_info();
62  }
63  CHECK(IS_GEO(ti.get_type()));
64 
65  // Return geo column reference. The geo column may be expanded if required for extension
66  // function arguments. Otherwise, the geo column reference will be translated into
67  // physical columns as required. Bounds column will be added if present and requested.
68  if (expand_geo_col) {
69  for (auto i = 0; i < ti.get_physical_coord_cols(); i++) {
70  const auto pcd = cat_.getMetadataForColumnBySpi(
71  table_id, SPIMAP_GEO_PHYSICAL_INPUT(rex_input->getIndex(), i + 1));
72  auto pcol_ti = pcd->columnType;
73  args.push_back(std::make_shared<Analyzer::ColumnVar>(
74  pcol_ti, table_id, pcd->columnId, rte_idx));
75  }
76  } else {
77  args.push_back(
78  std::make_shared<Analyzer::ColumnVar>(ti, table_id, column_id, rte_idx));
79  }
80  if (with_bounds && ti.has_bounds()) {
81  const auto bounds_cd = cat_.getMetadataForColumnBySpi(
82  table_id,
84  ti.get_physical_coord_cols() + 1));
85  auto bounds_ti = bounds_cd->columnType;
86  args.push_back(std::make_shared<Analyzer::ColumnVar>(
87  bounds_ti, table_id, bounds_cd->columnId, rte_idx));
88  }
89  if (with_render_group && ti.has_render_group()) {
90  const auto render_group_cd = cat_.getMetadataForColumnBySpi(
91  table_id,
93  ti.get_physical_coord_cols() + 2));
94  auto render_group_ti = render_group_cd->columnType;
95  args.push_back(std::make_shared<Analyzer::ColumnVar>(
96  render_group_ti, table_id, render_group_cd->columnId, rte_idx));
97  }
98  return args;
99 }
100 
101 namespace Importer_NS {
102 
103 std::vector<uint8_t> compress_coords(std::vector<double>& coords, const SQLTypeInfo& ti);
104 
105 } // namespace Importer_NS
106 
107 std::vector<std::shared_ptr<Analyzer::Expr>> RelAlgTranslator::translateGeoLiteral(
108  const RexLiteral* rex_literal,
109  SQLTypeInfo& ti,
110  bool with_bounds) const {
111  CHECK(rex_literal);
112  if (rex_literal->getType() != kTEXT) {
113  throw std::runtime_error("Geo literals must be strings");
114  }
115  const auto e = translateLiteral(rex_literal);
116  auto wkt = std::dynamic_pointer_cast<Analyzer::Constant>(e);
117  CHECK(wkt);
118  std::vector<double> coords;
119  std::vector<double> bounds;
120  std::vector<int> ring_sizes;
121  std::vector<int> poly_rings;
122  int32_t srid = ti.get_output_srid();
124  *wkt->get_constval().stringval, ti, coords, bounds, ring_sizes, poly_rings)) {
125  throw QueryNotSupported("Could not read geometry from text");
126  }
128  ti.set_input_srid(srid);
129  ti.set_output_srid(srid);
130  // Compress geo literals by default
131  if (srid == 4326) {
133  ti.set_comp_param(32);
134  }
135 
136  std::vector<std::shared_ptr<Analyzer::Expr>> args;
137 
138  std::vector<uint8_t> compressed_coords = Importer_NS::compress_coords(coords, ti);
139  std::list<std::shared_ptr<Analyzer::Expr>> compressed_coords_exprs;
140  for (auto cc : compressed_coords) {
141  Datum d;
142  d.tinyintval = cc;
143  auto e = makeExpr<Analyzer::Constant>(kTINYINT, false, d);
144  compressed_coords_exprs.push_back(e);
145  }
146  SQLTypeInfo arr_ti = SQLTypeInfo(kARRAY, true);
147  arr_ti.set_subtype(kTINYINT);
148  arr_ti.set_size(compressed_coords.size() * sizeof(int8_t));
149  arr_ti.set_compression(ti.get_compression());
150  arr_ti.set_comp_param((ti.get_compression() == kENCODING_GEOINT) ? 32 : 64);
151  args.push_back(makeExpr<Analyzer::Constant>(arr_ti, false, compressed_coords_exprs));
152 
153  auto lit_type = ti.get_type();
154  if (lit_type == kPOLYGON || lit_type == kMULTIPOLYGON) {
155  // ring sizes
156  std::list<std::shared_ptr<Analyzer::Expr>> ring_size_exprs;
157  for (auto c : ring_sizes) {
158  Datum d;
159  d.intval = c;
160  auto e = makeExpr<Analyzer::Constant>(kINT, false, d);
161  ring_size_exprs.push_back(e);
162  }
163  SQLTypeInfo arr_ti = SQLTypeInfo(kARRAY, true);
164  arr_ti.set_subtype(kINT);
165  arr_ti.set_size(ring_sizes.size() * sizeof(int32_t));
166  args.push_back(makeExpr<Analyzer::Constant>(arr_ti, false, ring_size_exprs));
167 
168  // poly rings
169  if (lit_type == kMULTIPOLYGON) {
170  std::list<std::shared_ptr<Analyzer::Expr>> poly_rings_exprs;
171  for (auto c : poly_rings) {
172  Datum d;
173  d.intval = c;
174  auto e = makeExpr<Analyzer::Constant>(kINT, false, d);
175  poly_rings_exprs.push_back(e);
176  }
177  SQLTypeInfo arr_ti = SQLTypeInfo(kARRAY, true);
178  arr_ti.set_subtype(kINT);
179  arr_ti.set_size(poly_rings.size() * sizeof(int32_t));
180  args.push_back(makeExpr<Analyzer::Constant>(arr_ti, false, poly_rings_exprs));
181  }
182  }
183 
184  if (with_bounds && ti.has_bounds()) {
185  // bounds
186  std::list<std::shared_ptr<Analyzer::Expr>> bounds_exprs;
187  for (auto b : bounds) {
188  Datum d;
189  d.doubleval = b;
190  auto e = makeExpr<Analyzer::Constant>(kDOUBLE, false, d);
191  bounds_exprs.push_back(e);
192  }
193  SQLTypeInfo arr_ti = SQLTypeInfo(kARRAY, true);
194  arr_ti.set_subtype(kDOUBLE);
195  arr_ti.set_size(bounds.size() * sizeof(double));
196  args.push_back(makeExpr<Analyzer::Constant>(arr_ti, false, bounds_exprs));
197  }
198 
199  return args;
200 }
201 
202 std::vector<std::shared_ptr<Analyzer::Expr>> RelAlgTranslator::translateGeoFunctionArg(
203  const RexScalar* rex_scalar,
204  SQLTypeInfo& arg_ti,
205  int32_t& lindex,
206  const bool with_bounds,
207  const bool with_render_group,
208  const bool expand_geo_col,
209  const bool is_projection) const {
210  std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
211 
212  const auto rex_input = dynamic_cast<const RexInput*>(rex_scalar);
213  if (rex_input) {
214  const auto input = translateInput(rex_input);
215  const auto column = dynamic_cast<const Analyzer::ColumnVar*>(input.get());
216  if (!column || !column->get_type_info().is_geometry()) {
217  throw QueryNotSupported("Geo function is expecting a geo column argument");
218  }
219  return translateGeoColumn(
220  rex_input, arg_ti, with_bounds, with_render_group, expand_geo_col);
221  }
222  const auto rex_function = dynamic_cast<const RexFunctionOperator*>(rex_scalar);
223  if (rex_function) {
224  if (rex_function->getName() == "ST_Transform"sv) {
225  CHECK_EQ(size_t(2), rex_function->size());
226  const auto rex_scalar0 =
227  dynamic_cast<const RexScalar*>(rex_function->getOperand(0));
228  if (!rex_scalar0) {
229  throw QueryNotSupported(rex_function->getName() + ": unexpected first argument");
230  }
231  auto arg0 = translateGeoFunctionArg(
232  rex_scalar0, arg_ti, lindex, with_bounds, with_render_group, expand_geo_col);
233 
234  const auto rex_literal =
235  dynamic_cast<const RexLiteral*>(rex_function->getOperand(1));
236  if (!rex_literal) {
237  throw QueryNotSupported(rex_function->getName() +
238  ": second argument is expected to be a literal");
239  }
240  const auto e = translateLiteral(rex_literal);
241  auto ce = std::dynamic_pointer_cast<Analyzer::Constant>(e);
242  if (!ce || !e->get_type_info().is_integer()) {
243  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
244  }
245  int32_t srid = 0;
246  if (e->get_type_info().get_type() == kSMALLINT) {
247  srid = static_cast<int32_t>(ce->get_constval().smallintval);
248  } else if (e->get_type_info().get_type() == kTINYINT) {
249  srid = static_cast<int32_t>(ce->get_constval().tinyintval);
250  } else if (e->get_type_info().get_type() == kINT) {
251  srid = static_cast<int32_t>(ce->get_constval().intval);
252  } else {
253  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
254  }
255  if (srid != 900913) {
256  throw QueryNotSupported(rex_function->getName() + ": unsupported output SRID " +
257  std::to_string(srid));
258  }
259  if (arg_ti.get_input_srid() > 0) {
260  if (arg_ti.get_input_srid() != 4326) {
261  throw QueryNotSupported(rex_function->getName() + ": unsupported input SRID " +
262  std::to_string(arg_ti.get_input_srid()));
263  }
264  arg_ti.set_output_srid(
265  srid); // We have a valid input SRID, register the output SRID for transform
266  } else {
267  throw QueryNotSupported(rex_function->getName() +
268  ": unexpected input SRID, unable to transform");
269  }
270  return arg0;
271  } else if (func_resolve(
272  rex_function->getName(), "ST_GeomFromText"sv, "ST_GeogFromText"sv)) {
273  CHECK(rex_function->size() == size_t(1) || rex_function->size() == size_t(2));
274  // First - register srid, then send it to geo literal translation
275  int32_t srid = 0;
276  if (rex_function->size() == 2) {
277  const auto rex_literal =
278  dynamic_cast<const RexLiteral*>(rex_function->getOperand(1));
279  if (!rex_literal) {
280  throw QueryNotSupported(rex_function->getName() +
281  ": second argument is expected to be a literal");
282  }
283  const auto e = translateLiteral(rex_literal);
284  auto ce = std::dynamic_pointer_cast<Analyzer::Constant>(e);
285  if (!ce || !e->get_type_info().is_integer()) {
286  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
287  }
288  if (e->get_type_info().get_type() == kSMALLINT) {
289  srid = static_cast<int32_t>(ce->get_constval().smallintval);
290  } else if (e->get_type_info().get_type() == kTINYINT) {
291  srid = static_cast<int32_t>(ce->get_constval().tinyintval);
292  } else if (e->get_type_info().get_type() == kINT) {
293  srid = static_cast<int32_t>(ce->get_constval().intval);
294  } else {
295  throw QueryNotSupported(rex_function->getName() + " expecting integer SRID");
296  }
297  if (srid != 0 && srid != 4326 && srid != 900913) {
298  throw QueryNotSupported(rex_function->getName() + ": unsupported SRID " +
299  std::to_string(srid));
300  }
301  }
302  arg_ti.set_input_srid(srid); // Input SRID
303  arg_ti.set_output_srid(srid); // Output SRID is the same - no transform
304 
305  const auto rex_literal =
306  dynamic_cast<const RexLiteral*>(rex_function->getOperand(0));
307  if (!rex_literal) {
308  throw QueryNotSupported(rex_function->getName() +
309  " expects a string literal as first argument");
310  }
311  auto arg0 = translateGeoLiteral(rex_literal, arg_ti, with_bounds);
312  arg_ti.set_subtype((rex_function->getName() == "ST_GeogFromText"sv) ? kGEOGRAPHY
313  : kGEOMETRY);
314  return arg0;
315  } else if (rex_function->getName() == "ST_PointN"sv) {
316  CHECK_EQ(size_t(2), rex_function->size());
317  const auto rex_scalar0 =
318  dynamic_cast<const RexScalar*>(rex_function->getOperand(0));
319  if (!rex_scalar0) {
320  throw QueryNotSupported(rex_function->getName() +
321  ": expects scalar as first argument");
322  }
323  auto arg0 = translateGeoFunctionArg(
324  rex_scalar0, arg_ti, lindex, with_bounds, with_render_group, expand_geo_col);
325  if (arg_ti.get_type() != kLINESTRING) {
326  throw QueryNotSupported(rex_function->getName() +
327  " expects LINESTRING as first argument");
328  }
329  const auto rex_literal =
330  dynamic_cast<const RexLiteral*>(rex_function->getOperand(1));
331  if (!rex_literal) {
332  throw QueryNotSupported(rex_function->getName() +
333  ": second argument is expected to be a literal");
334  }
335  const auto e = translateLiteral(rex_literal);
336  auto ce = std::dynamic_pointer_cast<Analyzer::Constant>(e);
337  if (!ce || !e->get_type_info().is_integer()) {
338  throw QueryNotSupported(rex_function->getName() +
339  ": expecting integer index as second argument");
340  }
341  int32_t index = 0;
342  if (e->get_type_info().get_type() == kSMALLINT) {
343  index = static_cast<int32_t>(ce->get_constval().smallintval);
344  } else if (e->get_type_info().get_type() == kTINYINT) {
345  index = static_cast<int32_t>(ce->get_constval().tinyintval);
346  } else if (e->get_type_info().get_type() == kINT) {
347  index = static_cast<int32_t>(ce->get_constval().intval);
348  } else {
349  throw QueryNotSupported(rex_function->getName() + " expecting integer index");
350  }
351  if (lindex != 0) {
352  throw QueryNotSupported(rex_function->getName() +
353  ": LINESTRING is already indexed");
354  }
355  if (index == 0) {
356  throw QueryNotSupported(rex_function->getName() + ": invalid index");
357  }
358  lindex = index;
359  return arg0;
360  } else if (rex_function->getName() == "ST_StartPoint"sv) {
361  CHECK_EQ(size_t(1), rex_function->size());
362  const auto rex_scalar0 =
363  dynamic_cast<const RexScalar*>(rex_function->getOperand(0));
364  if (!rex_scalar0) {
365  throw QueryNotSupported(rex_function->getName() +
366  ": expects scalar as first argument");
367  }
368  auto arg0 = translateGeoFunctionArg(
369  rex_scalar0, arg_ti, lindex, with_bounds, with_render_group, expand_geo_col);
370  if (arg_ti.get_type() != kLINESTRING) {
371  throw QueryNotSupported(rex_function->getName() +
372  " expects LINESTRING as first argument");
373  }
374  if (lindex != 0) {
375  throw QueryNotSupported(rex_function->getName() +
376  ": LINESTRING is already indexed");
377  }
378  lindex = 1;
379  return arg0;
380  } else if (rex_function->getName() == "ST_EndPoint"sv) {
381  CHECK_EQ(size_t(1), rex_function->size());
382  const auto rex_scalar0 =
383  dynamic_cast<const RexScalar*>(rex_function->getOperand(0));
384  if (!rex_scalar0) {
385  throw QueryNotSupported(rex_function->getName() +
386  ": expects scalar as first argument");
387  }
388  auto arg0 = translateGeoFunctionArg(
389  rex_scalar0, arg_ti, lindex, with_bounds, with_render_group, expand_geo_col);
390  if (arg_ti.get_type() != kLINESTRING) {
391  throw QueryNotSupported(rex_function->getName() +
392  " expects LINESTRING as first argument");
393  }
394  if (lindex != 0) {
395  throw QueryNotSupported(rex_function->getName() +
396  ": LINESTRING is already indexed");
397  }
398  lindex = -1;
399  return arg0;
400  } else if (rex_function->getName() == "ST_SRID"sv) {
401  CHECK_EQ(size_t(1), rex_function->size());
402  const auto rex_scalar0 =
403  dynamic_cast<const RexScalar*>(rex_function->getOperand(0));
404  if (!rex_scalar0) {
405  throw QueryNotSupported(rex_function->getName() +
406  ": expects scalar as first argument");
407  }
408  auto arg0 = translateGeoFunctionArg(
409  rex_scalar0, arg_ti, lindex, with_bounds, with_render_group, expand_geo_col);
410  if (!IS_GEO(arg_ti.get_type())) {
411  throw QueryNotSupported(rex_function->getName() + " expects geometry argument");
412  }
413  return arg0;
414  } else if (rex_function->getName() == "ST_SetSRID"sv) {
415  CHECK_EQ(size_t(2), rex_function->size());
416  const auto rex_scalar0 =
417  dynamic_cast<const RexScalar*>(rex_function->getOperand(0));
418  if (!rex_scalar0) {
419  throw QueryNotSupported(rex_function->getName() +
420  ": expects scalar as first argument");
421  }
422  auto arg0 = translateGeoFunctionArg(rex_scalar0,
423  arg_ti,
424  lindex,
425  with_bounds,
426  with_render_group,
427  expand_geo_col,
428  is_projection);
429  if (!IS_GEO(arg_ti.get_type())) {
430  throw QueryNotSupported(rex_function->getName() + " expects geometry argument");
431  }
432  const auto rex_literal =
433  dynamic_cast<const RexLiteral*>(rex_function->getOperand(1));
434  if (!rex_literal) {
435  throw QueryNotSupported(rex_function->getName() +
436  ": second argument is expected to be a literal");
437  }
438  const auto e = translateLiteral(rex_literal);
439  auto ce = std::dynamic_pointer_cast<Analyzer::Constant>(e);
440  if (!ce || !e->get_type_info().is_integer()) {
441  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
442  }
443  int32_t srid = 0;
444  if (e->get_type_info().get_type() == kSMALLINT) {
445  srid = static_cast<int32_t>(ce->get_constval().smallintval);
446  } else if (e->get_type_info().get_type() == kTINYINT) {
447  srid = static_cast<int32_t>(ce->get_constval().tinyintval);
448  } else if (e->get_type_info().get_type() == kINT) {
449  srid = static_cast<int32_t>(ce->get_constval().intval);
450  } else {
451  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
452  }
453  arg_ti.set_input_srid(srid); // Input SRID
454  arg_ti.set_output_srid(srid); // Output SRID is the same - no transform
455  return arg0;
456  } else if (rex_function->getName() == "CastToGeography"sv) {
457  CHECK_EQ(size_t(1), rex_function->size());
458  const auto rex_scalar0 =
459  dynamic_cast<const RexScalar*>(rex_function->getOperand(0));
460  if (!rex_scalar0) {
461  throw QueryNotSupported(rex_function->getName() +
462  ": expects scalar as first argument");
463  }
464  auto arg0 = translateGeoFunctionArg(
465  rex_scalar0, arg_ti, lindex, with_bounds, with_render_group, expand_geo_col);
466  if (!IS_GEO(arg_ti.get_type())) {
467  throw QueryNotSupported(rex_function->getName() + " expects geometry argument");
468  }
469  if (arg_ti.get_output_srid() != 4326) {
470  throw QueryNotSupported(rex_function->getName() +
471  " expects geometry with SRID=4326");
472  }
473  arg_ti.set_subtype(kGEOGRAPHY);
474  return arg0;
475  } else if (rex_function->getName() == "ST_Point"sv) {
476  CHECK_EQ(size_t(2), rex_function->size());
477  arg_ti.set_type(kPOINT);
478  arg_ti.set_subtype(kGEOMETRY);
479  arg_ti.set_input_srid(0);
480  arg_ti.set_output_srid(0);
482 
483  auto coord1 = translateScalarRex(rex_function->getOperand(0));
484  auto coord2 = translateScalarRex(rex_function->getOperand(1));
485  auto d_ti = SQLTypeInfo(kDOUBLE, true);
486  auto cast_coord1 = coord1->add_cast(d_ti);
487  auto cast_coord2 = coord2->add_cast(d_ti);
488  // First try to fold to geo literal
489  auto fold1 = fold_expr(cast_coord1.get());
490  auto fold2 = fold_expr(cast_coord2.get());
491  auto const_coord1 = std::dynamic_pointer_cast<Analyzer::Constant>(fold1);
492  auto const_coord2 = std::dynamic_pointer_cast<Analyzer::Constant>(fold2);
493  if (const_coord1 && const_coord2) {
494  CHECK(const_coord1->get_type_info().get_type() == kDOUBLE);
495  CHECK(const_coord2->get_type_info().get_type() == kDOUBLE);
496  std::string wkt = "POINT(" +
497  std::to_string(const_coord1->get_constval().doubleval) + " " +
498  std::to_string(const_coord2->get_constval().doubleval) + ")";
499  RexLiteral rex_literal{wkt, kTEXT, kNULLT, 0, 0, 0, 0};
500  auto args = translateGeoLiteral(&rex_literal, arg_ti, false);
501  CHECK(arg_ti.get_type() == kPOINT);
502  return args;
503  }
504  // Couldn't fold to geo literal, construct on the fly
505  auto da_ti = SQLTypeInfo(kARRAY, true);
506  da_ti.set_subtype(kDOUBLE);
507  da_ti.set_size(16);
508  auto cast_coords = {cast_coord1, cast_coord2};
509  auto is_local_alloca = !is_projection;
510  auto ae = makeExpr<Analyzer::ArrayExpr>(da_ti, cast_coords, 0, is_local_alloca);
511  // cast it to tinyint[16]
512  SQLTypeInfo tia_ti = SQLTypeInfo(kARRAY, true);
513  tia_ti.set_subtype(kTINYINT);
514  tia_ti.set_size(16);
515  return {makeExpr<Analyzer::UOper>(tia_ti, false, kCAST, ae)};
516  } else {
517  throw QueryNotSupported("Unsupported argument: " + rex_function->getName());
518  }
519  }
520  const auto rex_literal = dynamic_cast<const RexLiteral*>(rex_scalar);
521  if (rex_literal) {
522  return translateGeoLiteral(rex_literal, arg_ti, with_bounds);
523  }
524  throw QueryNotSupported("Geo function argument not supported");
525 }
526 
527 namespace {
528 
529 std::string suffix(SQLTypes type) {
530  if (type == kPOINT) {
531  return std::string("_Point");
532  }
533  if (type == kLINESTRING) {
534  return std::string("_LineString");
535  }
536  if (type == kPOLYGON) {
537  return std::string("_Polygon");
538  }
539  if (type == kMULTIPOLYGON) {
540  return std::string("_MultiPolygon");
541  }
542  throw QueryNotSupported("Unsupported argument type");
543 }
544 
545 } // namespace
546 
547 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateGeoConstructor(
548  const RexFunctionOperator* rex_function) const {
549  if (func_resolve(rex_function->getName(),
550  "ST_GeomFromText"sv,
551  "ST_GeogFromText"sv,
552  "ST_Point"sv,
553  "ST_SetSRID"sv)) {
554  SQLTypeInfo arg_ti;
555  int32_t lindex = 0;
556  auto geoargs =
557  translateGeoFunctionArg(rex_function, arg_ti, lindex, false, false, true, true);
558  return makeExpr<Analyzer::GeoExpr>(arg_ti, geoargs);
559  }
560  throw QueryNotSupported(rex_function->getName() +
561  " geo constructor is not supported in this context");
562 }
563 
564 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateUnaryGeoFunction(
565  const RexFunctionOperator* rex_function) const {
566  CHECK_EQ(size_t(1), rex_function->size());
567 
568  int32_t lindex = 0;
569  std::string specialized_geofunc{rex_function->getName()};
570 
571  // Geo function calls which do not need the coords col but do need cols associated with
572  // physical coords (e.g. ring_sizes / poly_rings)
573  if (rex_function->getName() == "ST_NRings"sv) {
574  SQLTypeInfo arg_ti;
575  auto geoargs = translateGeoFunctionArg(
576  rex_function->getOperand(0), arg_ti, lindex, false, false, true);
577  if (arg_ti.get_type() == kPOLYGON) {
578  CHECK_EQ(geoargs.size(), 2u);
579  geoargs.erase(geoargs.begin(), geoargs.begin() + 1); // remove the coords
580  return makeExpr<Analyzer::FunctionOper>(
581  rex_function->getType(), specialized_geofunc, geoargs);
582  } else if (arg_ti.get_type() == kMULTIPOLYGON) {
583  CHECK_EQ(geoargs.size(), 3u);
584  geoargs.erase(geoargs.begin(), geoargs.begin() + 1); // remove the coords
585  geoargs.erase(geoargs.begin() + 1, geoargs.end()); // remove the poly_rings
586  return makeExpr<Analyzer::FunctionOper>(
587  rex_function->getType(), specialized_geofunc, geoargs);
588  } else {
589  throw QueryNotSupported(rex_function->getName() +
590  " expects a POLYGON or MULTIPOLYGON");
591  }
592  } else if (rex_function->getName() == "ST_NPoints"sv) {
593  SQLTypeInfo arg_ti;
594  auto geoargs = translateGeoFunctionArg(
595  rex_function->getOperand(0), arg_ti, lindex, false, false, true);
596  geoargs.erase(geoargs.begin() + 1, geoargs.end()); // remove all but coords
597  // Add compression information
598  Datum input_compression;
599  input_compression.intval =
600  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
601  ? 1
602  : 0;
603  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
604  return makeExpr<Analyzer::FunctionOper>(
605  rex_function->getType(), specialized_geofunc, geoargs);
606  } else if (func_resolve(rex_function->getName(), "ST_Perimeter"sv, "ST_Area"sv)) {
607  SQLTypeInfo arg_ti;
608  auto geoargs = translateGeoFunctionArg(
609  rex_function->getOperand(0), arg_ti, lindex, false, false, true);
610  if (arg_ti.get_type() != kPOLYGON && arg_ti.get_type() != kMULTIPOLYGON) {
611  throw QueryNotSupported(rex_function->getName() +
612  " expects a POLYGON or MULTIPOLYGON");
613  }
614  specialized_geofunc += suffix(arg_ti.get_type());
615  if (arg_ti.get_subtype() == kGEOGRAPHY && arg_ti.get_output_srid() == 4326) {
616  specialized_geofunc += "_Geodesic"s;
617  }
618  // Add compression information
619  Datum input_compression;
620  input_compression.intval =
621  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
622  ? 1
623  : 0;
624  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
625  Datum input_srid;
626  input_srid.intval = arg_ti.get_input_srid();
627  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid));
628  Datum output_srid;
629  output_srid.intval = arg_ti.get_output_srid();
630  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
631  return makeExpr<Analyzer::FunctionOper>(
632  rex_function->getType(), specialized_geofunc, geoargs);
633  }
634 
635  // Accessors for poly bounds and render group for in-situ poly render queries
636  if (func_resolve(rex_function->getName(),
637  "MapD_GeoPolyBoundsPtr"sv /* deprecated */,
638  "OmniSci_Geo_PolyBoundsPtr"sv)) {
639  SQLTypeInfo arg_ti;
640  // get geo column plus bounds only (not expanded)
641  auto geoargs = translateGeoFunctionArg(
642  rex_function->getOperand(0), arg_ti, lindex, true, false, false);
643  // this function only works on polys
644  if (!IS_GEO_POLY(arg_ti.get_type())) {
645  throw QueryNotSupported(rex_function->getName() +
646  " expects a POLYGON or MULTIPOLYGON");
647  }
648  // only need the bounds argument (last), discard the rest
649  geoargs.erase(geoargs.begin(), geoargs.end() - 1);
650  // done
651  return makeExpr<Analyzer::FunctionOper>(
652  rex_function->getType(), specialized_geofunc, geoargs);
653  } else if (func_resolve(rex_function->getName(),
654  "MapD_GeoPolyRenderGroup"sv /* deprecated */,
655  "OmniSci_Geo_PolyRenderGroup"sv)) {
656  SQLTypeInfo arg_ti;
657  // get geo column plus render_group only (not expanded)
658  auto geoargs = translateGeoFunctionArg(
659  rex_function->getOperand(0), arg_ti, lindex, false, true, false);
660  // this function only works on polys
661  if (!IS_GEO_POLY(arg_ti.get_type())) {
662  throw QueryNotSupported(rex_function->getName() +
663  " expects a POLYGON or MULTIPOLYGON");
664  }
665  // only need the render_group argument (last), discard the rest
666  geoargs.erase(geoargs.begin(), geoargs.end() - 1);
667  // done
668  return makeExpr<Analyzer::FunctionOper>(
669  rex_function->getType(), specialized_geofunc, geoargs);
670  }
671 
672  // All functions below use geo col as reference and expand it as necessary
673  SQLTypeInfo arg_ti;
674  bool with_bounds = true;
675  auto geoargs = translateGeoFunctionArg(
676  rex_function->getOperand(0), arg_ti, lindex, with_bounds, false, false);
677 
678  if (rex_function->getName() == "ST_SRID"sv) {
679  Datum output_srid;
680  output_srid.intval = arg_ti.get_output_srid();
681  return makeExpr<Analyzer::Constant>(kINT, false, output_srid);
682  }
683 
684  if (func_resolve(
685  rex_function->getName(), "ST_XMin"sv, "ST_YMin"sv, "ST_XMax"sv, "ST_YMax"sv)) {
686  // If type has bounds - use them, otherwise look at coords
687  if (arg_ti.has_bounds()) {
688  if (lindex != 0) {
689  throw QueryNotSupported(rex_function->getName() +
690  " doesn't support indexed LINESTRINGs");
691  }
692  // Only need the bounds argument, discard the rest
693  geoargs.erase(geoargs.begin(), geoargs.end() - 1);
694 
695  // Supply srids too - transformed geo would have a transformed bounding box
696  Datum input_srid;
697  input_srid.intval = arg_ti.get_input_srid();
698  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid));
699  Datum output_srid;
700  output_srid.intval = arg_ti.get_output_srid();
701  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
702 
703  specialized_geofunc += "_Bounds"s;
704  return makeExpr<Analyzer::FunctionOper>(
705  rex_function->getType(), specialized_geofunc, geoargs);
706  }
707  }
708 
709  // All geo function calls translated below only need the coords, extras e.g. ring_sizes
710  // are dropped. Specialize for other/new functions if needed.
711  geoargs.erase(geoargs.begin() + 1, geoargs.end());
712 
713  if (func_resolve(rex_function->getName(), "ST_X"sv, "ST_Y"sv)) {
714  if (arg_ti.get_type() == kLINESTRING) {
715  if (lindex == 0) {
716  throw QueryNotSupported(
717  rex_function->getName() +
718  " expects a POINT, use LINESTRING accessor, e.g. ST_POINTN");
719  }
720  Datum index;
721  index.intval = lindex;
722  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, index));
723  } else if (arg_ti.get_type() != kPOINT) {
724  throw QueryNotSupported(rex_function->getName() + " expects a POINT");
725  }
726  specialized_geofunc += suffix(arg_ti.get_type());
727  } else if (rex_function->getName() == "ST_Length"sv) {
728  if (arg_ti.get_type() != kLINESTRING || lindex != 0) {
729  throw QueryNotSupported(rex_function->getName() + " expects unindexed LINESTRING");
730  }
731  specialized_geofunc += suffix(arg_ti.get_type());
732  if (arg_ti.get_subtype() == kGEOGRAPHY && arg_ti.get_output_srid() == 4326) {
733  specialized_geofunc += "_Geodesic"s;
734  }
735  }
736 
737  // Add input compression mode and SRID args to enable on-the-fly
738  // decompression/transforms
739  Datum input_compression;
740  input_compression.intval =
741  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32) ? 1
742  : 0;
743  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
744  Datum input_srid;
745  input_srid.intval = arg_ti.get_input_srid();
746  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid));
747 
748  // Add output SRID arg to enable on-the-fly transforms
749  Datum output_srid;
750  output_srid.intval = arg_ti.get_output_srid();
751  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
752 
753  return makeExpr<Analyzer::FunctionOper>(
754  rex_function->getType(), specialized_geofunc, geoargs);
755 }
756 
757 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateBinaryGeoFunction(
758  const RexFunctionOperator* rex_function) const {
759  auto function_name = rex_function->getName();
760  auto return_type = rex_function->getType();
761  bool swap_args = false;
762  bool with_bounds = false;
763  bool negate_result = false;
764  if (function_name == "ST_DWithin"sv) {
765  CHECK_EQ(size_t(3), rex_function->size());
766  function_name = "ST_Distance";
767  return_type = SQLTypeInfo(kDOUBLE, false);
768  } else if (function_name == "ST_DFullyWithin"sv) {
769  CHECK_EQ(size_t(3), rex_function->size());
770  function_name = "ST_MaxDistance";
771  return_type = SQLTypeInfo(kDOUBLE, false);
772  } else {
773  CHECK_EQ(size_t(2), rex_function->size());
774  }
775  if (function_name == "ST_Within"sv) {
776  function_name = "ST_Contains";
777  swap_args = true;
778  } else if (function_name == "ST_Disjoint"sv) {
779  function_name = "ST_Intersects";
780  negate_result = true;
781  }
782  if (func_resolve(function_name, "ST_Contains"sv, "ST_Intersects"sv)) {
783  with_bounds = true;
784  }
785 
786  std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
787  SQLTypeInfo arg0_ti;
788  SQLTypeInfo arg1_ti;
789  int32_t lindex0 = 0;
790  int32_t lindex1 = 0;
791 
792  auto geoargs0 = translateGeoFunctionArg(rex_function->getOperand(swap_args ? 1 : 0),
793  arg0_ti,
794  lindex0,
795  with_bounds,
796  false,
797  false);
798  if (arg0_ti.get_type() == kLINESTRING) {
799  Datum index;
800  index.intval = lindex0;
801  geoargs0.push_back(makeExpr<Analyzer::Constant>(kINT, false, index));
802  }
803  geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
804  auto geoargs1 = translateGeoFunctionArg(rex_function->getOperand(swap_args ? 0 : 1),
805  arg1_ti,
806  lindex1,
807  with_bounds,
808  false,
809  false);
810  if (arg1_ti.get_type() == kLINESTRING) {
811  Datum index;
812  index.intval = lindex1;
813  geoargs1.push_back(makeExpr<Analyzer::Constant>(kINT, false, index));
814  }
815  geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
816 
817  if (arg0_ti.get_subtype() != kNULLT && arg0_ti.get_subtype() != arg1_ti.get_subtype()) {
818  throw QueryNotSupported(rex_function->getName() +
819  " accepts either two GEOGRAPHY or two GEOMETRY arguments");
820  }
821  if (arg0_ti.get_output_srid() > 0 &&
822  arg0_ti.get_output_srid() != arg1_ti.get_output_srid()) {
823  throw QueryNotSupported(rex_function->getName() + " cannot accept different SRIDs");
824  }
825 
826  std::string specialized_geofunc{function_name + suffix(arg0_ti.get_type()) +
827  suffix(arg1_ti.get_type())};
828 
829  if (arg0_ti.get_subtype() == kGEOGRAPHY && arg0_ti.get_output_srid() == 4326) {
830  // Need to call geodesic runtime functions
831  if (function_name == "ST_Distance"sv) {
832  if ((arg0_ti.get_type() == kPOINT ||
833  (arg0_ti.get_type() == kLINESTRING && lindex0 != 0)) &&
834  (arg1_ti.get_type() == kPOINT ||
835  (arg1_ti.get_type() == kLINESTRING && lindex1 != 0))) {
836  // Geodesic distance between points (or indexed linestrings)
837  specialized_geofunc += "_Geodesic"s;
838  } else {
839  throw QueryNotSupported(function_name +
840  " currently doesn't accept non-POINT geographies");
841  }
842  } else if (rex_function->getName() == "ST_Contains"sv) {
843  // We currently don't have a geodesic implementation of ST_Contains,
844  // allowing calls to a [less precise] cartesian implementation.
845  } else {
846  throw QueryNotSupported(function_name + " doesn't accept geographies");
847  }
848  } else if (function_name == "ST_Distance"sv && rex_function->size() == 3) {
849  if (arg0_ti.get_type() == kPOINT && arg1_ti.get_type() == kPOINT) {
850  // Cartesian distance between points used by ST_DWithin - switch to faster Squared
851  specialized_geofunc += "_Squared"s;
852  }
853  }
854 
855  // Add first input's compression mode and SRID args to enable on-the-fly
856  // decompression/transforms
857  Datum input_compression0;
858  input_compression0.intval =
859  (arg0_ti.get_compression() == kENCODING_GEOINT && arg0_ti.get_comp_param() == 32)
860  ? 1
861  : 0;
862  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression0));
863  Datum input_srid0;
864  input_srid0.intval = arg0_ti.get_input_srid();
865  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid0));
866 
867  // Add second input's compression mode and SRID args to enable on-the-fly
868  // decompression/transforms
869  Datum input_compression1;
870  input_compression1.intval =
871  (arg1_ti.get_compression() == kENCODING_GEOINT && arg1_ti.get_comp_param() == 32)
872  ? 1
873  : 0;
874  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression1));
875  Datum input_srid1;
876  input_srid1.intval = arg1_ti.get_input_srid();
877  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid1));
878 
879  // Add output SRID arg to enable on-the-fly transforms
880  Datum output_srid;
881  output_srid.intval = arg0_ti.get_output_srid();
882  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
883 
884  auto result =
885  makeExpr<Analyzer::FunctionOper>(return_type, specialized_geofunc, geoargs);
886  if (negate_result) {
887  return makeExpr<Analyzer::UOper>(kBOOLEAN, kNOT, result);
888  }
889  return result;
890 }
891 
892 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateTernaryGeoFunction(
893  const RexFunctionOperator* rex_function) const {
894  CHECK_EQ(size_t(3), rex_function->size());
895 
896  auto distance_expr = translateScalarRex(rex_function->getOperand(2));
897  const auto& distance_ti = SQLTypeInfo(kDOUBLE, false);
898  if (distance_expr->get_type_info().get_type() != kDOUBLE) {
899  distance_expr->add_cast(distance_ti);
900  }
901 
902  // Translate the geo distance function call portion
903  const auto geo_distance_expr = translateBinaryGeoFunction(rex_function);
904 
905  if (rex_function->getName() == "ST_DWithin") {
906  auto func_oper = dynamic_cast<Analyzer::FunctionOper*>(geo_distance_expr.get());
907  if (func_oper && func_oper->getName() == "ST_Distance_Point_Point_Squared"sv) {
908  // Point_Point combination will yield geo_distance squared which is faster,
909  // need to compare it with distance squared
910  distance_expr = makeExpr<Analyzer::BinOper>(distance_ti,
911  distance_expr->get_contains_agg(),
912  kMULTIPLY,
913  kONE,
914  distance_expr,
915  distance_expr);
916  distance_expr = fold_expr(distance_expr.get());
917  }
918  }
919 
920  return makeExpr<Analyzer::BinOper>(
921  kBOOLEAN, kLE, kONE, geo_distance_expr, distance_expr);
922 }
923 
924 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateGeoComparison(
925  const RexOperator* rex_operator) const {
926  if (rex_operator->size() != size_t(2)) {
927  return nullptr;
928  }
929 
930  auto geo_distance_expr = translateScalarRex(rex_operator->getOperand(0));
931  auto func_oper = dynamic_cast<Analyzer::FunctionOper*>(geo_distance_expr.get());
932  if (func_oper && func_oper->getName() == "ST_Distance_Point_Point"sv) {
933  const auto& distance_ti = SQLTypeInfo(kDOUBLE, false);
934  std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
935  for (size_t i = 0; i < func_oper->getArity(); i++) {
936  geoargs.push_back(func_oper->getOwnArg(i));
937  }
938  geo_distance_expr = makeExpr<Analyzer::FunctionOper>(
939  distance_ti, "ST_Distance_Point_Point_Squared"s, geoargs);
940  auto distance_expr = translateScalarRex(rex_operator->getOperand(1));
941  if (distance_expr->get_type_info().get_type() != kDOUBLE) {
942  distance_expr->add_cast(distance_ti);
943  }
944  distance_expr = makeExpr<Analyzer::BinOper>(distance_ti,
945  distance_expr->get_contains_agg(),
946  kMULTIPLY,
947  kONE,
948  distance_expr,
949  distance_expr);
950  distance_expr = fold_expr(distance_expr.get());
951  return makeExpr<Analyzer::BinOper>(
952  kBOOLEAN, rex_operator->getOperator(), kONE, geo_distance_expr, distance_expr);
953  }
954  return nullptr;
955 }
956 
957 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateFunctionWithGeoArg(
958  const RexFunctionOperator* rex_function) const {
959  int32_t lindex = 0;
960  std::string specialized_geofunc{rex_function->getName()};
961  if (func_resolve(rex_function->getName(),
962  "convert_meters_to_pixel_width"sv,
963  "convert_meters_to_pixel_height"sv)) {
964  CHECK_EQ(rex_function->size(), 6u);
965  SQLTypeInfo arg_ti;
966  std::vector<std::shared_ptr<Analyzer::Expr>> args;
967  args.push_back(translateScalarRex(rex_function->getOperand(0)));
968  auto geoargs = translateGeoFunctionArg(
969  rex_function->getOperand(1), arg_ti, lindex, false, true, false);
970  // only works on points
971  if (arg_ti.get_type() != kPOINT) {
972  throw QueryNotSupported(rex_function->getName() +
973  " expects a point for the second argument");
974  }
975 
976  args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
977 
978  // Add compression information
979  Datum input_compression;
980  input_compression.intval =
981  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
982  ? 1
983  : 0;
984  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
985  if (arg_ti.get_input_srid() != 4326) {
986  throw QueryNotSupported(
987  rex_function->getName() +
988  " currently only supports points of with SRID WGS84/EPSG:4326");
989  }
990  Datum input_srid;
991  input_srid.intval = arg_ti.get_input_srid();
992  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid));
993  Datum output_srid;
994  // Forcing web-mercator projection for now
995  // TODO(croot): check that the input-to-output conversion routines exist?
996  output_srid.intval =
997  arg_ti.get_output_srid() != 900913 ? 900913 : arg_ti.get_output_srid();
998  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
999 
1000  args.push_back(translateScalarRex(rex_function->getOperand(2)));
1001  args.push_back(translateScalarRex(rex_function->getOperand(3)));
1002  args.push_back(translateScalarRex(rex_function->getOperand(4)));
1003  args.push_back(translateScalarRex(rex_function->getOperand(5)));
1004  return makeExpr<Analyzer::FunctionOper>(
1005  rex_function->getType(), specialized_geofunc, args);
1006  } else if (rex_function->getName() == "is_point_in_view"sv) {
1007  CHECK_EQ(rex_function->size(), 5u);
1008  SQLTypeInfo arg_ti;
1009  std::vector<std::shared_ptr<Analyzer::Expr>> args;
1010  auto geoargs = translateGeoFunctionArg(
1011  rex_function->getOperand(0), arg_ti, lindex, false, true, false);
1012  // only works on points
1013  if (arg_ti.get_type() != kPOINT) {
1014  throw QueryNotSupported(rex_function->getName() +
1015  " expects a point for the second argument");
1016  }
1017 
1018  args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1019 
1020  // Add compression information
1021  Datum input_compression;
1022  input_compression.intval =
1023  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
1024  ? 1
1025  : 0;
1026  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
1027  if (arg_ti.get_input_srid() != 4326) {
1028  throw QueryNotSupported(
1029  rex_function->getName() +
1030  " currently only supports points of with SRID WGS84/EPSG:4326");
1031  }
1032  args.push_back(translateScalarRex(rex_function->getOperand(1)));
1033  args.push_back(translateScalarRex(rex_function->getOperand(2)));
1034  args.push_back(translateScalarRex(rex_function->getOperand(3)));
1035  args.push_back(translateScalarRex(rex_function->getOperand(4)));
1036  return makeExpr<Analyzer::FunctionOper>(
1037  rex_function->getType(), specialized_geofunc, args);
1038  } else if (rex_function->getName() == "is_point_size_in_view"sv) {
1039  CHECK_EQ(rex_function->size(), 6u);
1040  SQLTypeInfo arg_ti;
1041  std::vector<std::shared_ptr<Analyzer::Expr>> args;
1042  auto geoargs = translateGeoFunctionArg(
1043  rex_function->getOperand(0), arg_ti, lindex, false, true, false);
1044  // only works on points
1045  if (arg_ti.get_type() != kPOINT) {
1046  throw QueryNotSupported(rex_function->getName() +
1047  " expects a point for the second argument");
1048  }
1049 
1050  args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1051 
1052  // Add compression information
1053  Datum input_compression;
1054  input_compression.intval =
1055  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
1056  ? 1
1057  : 0;
1058  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
1059  if (arg_ti.get_input_srid() != 4326) {
1060  throw QueryNotSupported(
1061  rex_function->getName() +
1062  " currently only supports points of with SRID WGS84/EPSG:4326");
1063  }
1064  args.push_back(translateScalarRex(rex_function->getOperand(1)));
1065  args.push_back(translateScalarRex(rex_function->getOperand(2)));
1066  args.push_back(translateScalarRex(rex_function->getOperand(3)));
1067  args.push_back(translateScalarRex(rex_function->getOperand(4)));
1068  args.push_back(translateScalarRex(rex_function->getOperand(5)));
1069  return makeExpr<Analyzer::FunctionOper>(
1070  rex_function->getType(), specialized_geofunc, args);
1071  }
1072  CHECK(false);
1073  return nullptr;
1074 }
1075 
1076 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateGeoOverlapsOper(
1077  const RexOperator* rex_operator) const {
1078  CHECK_EQ(rex_operator->size(), 2u);
1079 
1080  auto translate_input =
1081  [&](const RexScalar* operand) -> std::shared_ptr<Analyzer::Expr> {
1082  const auto input = dynamic_cast<const RexInput*>(operand);
1083  CHECK(input);
1084 
1085  SQLTypeInfo ti;
1086  const auto exprs = translateGeoColumn(input, ti, true, false, false);
1087  CHECK_GT(exprs.size(), 0u);
1088  if (ti.get_type() == kPOINT) {
1089  return exprs.front();
1090  } else {
1091  return exprs.back();
1092  }
1093  };
1094 
1095  SQLQualifier sql_qual{kONE};
1096  SQLOps sql_op{kOVERLAPS};
1097  return makeExpr<Analyzer::BinOper>(SQLTypeInfo(kBOOLEAN, false),
1098  false,
1099  sql_op,
1100  sql_qual,
1101  translate_input(rex_operator->getOperand(1)),
1102  translate_input(rex_operator->getOperand(0)));
1103 }
int8_t tinyintval
Definition: sqltypes.h:126
#define CHECK_EQ(x, y)
Definition: Logger.h:198
auto func_resolve
HOST DEVICE int get_output_srid() const
Definition: sqltypes.h:332
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:334
HOST DEVICE int get_comp_param() const
Definition: sqltypes.h:335
SQLTypes
Definition: sqltypes.h:41
#define SPIMAP_GEO_PHYSICAL_INPUT(c, i)
Definition: Catalog.h:70
SQLQualifier
Definition: sqldefs.h:69
std::shared_ptr< Analyzer::Expr > translateScalarRex(const RexScalar *rex) const
const SQLTypeInfo & getType() const
size_t size() const
const RexScalar * getOperand(const size_t idx) const
bool has_bounds() const
Definition: sqltypes.h:395
SQLOps
Definition: sqldefs.h:29
Definition: sqldefs.h:35
void set_size(int s)
Definition: sqltypes.h:424
std::vector< uint8_t > compress_coords(std::vector< double > &coords, const SQLTypeInfo &ti)
Definition: Importer.cpp:1422
void set_input_srid(int d)
Definition: sqltypes.h:420
#define CHECK_GE(x, y)
Definition: Logger.h:203
Definition: sqldefs.h:49
HOST DEVICE void set_type(SQLTypes t)
Definition: sqltypes.h:416
#define CHECK_GT(x, y)
Definition: Logger.h:202
void set_compression(EncodingType c)
Definition: sqltypes.h:426
int32_t intval
Definition: sqltypes.h:128
std::string to_string(char const *&&v)
void set_output_srid(int s)
Definition: sqltypes.h:422
std::shared_ptr< Analyzer::Expr > translateInput(const RexInput *) const
std::shared_ptr< Analyzer::Expr > translateUnaryGeoFunction(const RexFunctionOperator *) const
std::shared_ptr< Analyzer::Expr > translateGeoOverlapsOper(const RexOperator *) const
std::vector< std::shared_ptr< Analyzer::Expr > > translateGeoLiteral(const RexLiteral *, SQLTypeInfo &, bool) const
HOST DEVICE void set_subtype(SQLTypes st)
Definition: sqltypes.h:417
unsigned getIndex() const
static std::shared_ptr< Analyzer::Expr > translateLiteral(const RexLiteral *)
SQLOps getOperator() const
CHECK(cgen_state)
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:326
int get_physical_coord_cols() const
Definition: sqltypes.h:362
std::shared_ptr< Analyzer::Expr > translateGeoConstructor(const RexFunctionOperator *) const
SQLTypeInfoCore< ArrayContextTypeSizer, ExecutorTypePackaging, DateTimeFacilities > SQLTypeInfo
Definition: sqltypes.h:852
const ColumnDescriptor * getMetadataForColumnBySpi(const int tableId, const size_t spi) const
Definition: Catalog.cpp:1437
const std::unordered_map< const RelAlgNode *, int > input_to_nest_level_
#define CHECK_LT(x, y)
Definition: Logger.h:200
Definition: sqltypes.h:55
Definition: sqldefs.h:69
const RelAlgNode * getSourceNode() const
static bool getGeoColumns(const std::string &wkt, SQLTypeInfo &ti, std::vector< double > &coords, std::vector< double > &bounds, std::vector< int > &ring_sizes, std::vector< int > &poly_rings, const bool promote_poly_to_mpoly=false)
Definition: geo_types.cpp:459
bool has_render_group() const
Definition: sqltypes.h:406
void set_comp_param(int p)
Definition: sqltypes.h:427
HOST DEVICE SQLTypes get_subtype() const
Definition: sqltypes.h:327
std::shared_ptr< Analyzer::Expr > translateTernaryGeoFunction(const RexFunctionOperator *) const
std::shared_ptr< Analyzer::Expr > translateBinaryGeoFunction(const RexFunctionOperator *) const
std::shared_ptr< Analyzer::Expr > translateFunctionWithGeoArg(const RexFunctionOperator *) const
Definition: sqltypes.h:48
SQLTypeInfo columnType
const std::string & getName() const
std::shared_ptr< Analyzer::Expr > translateGeoComparison(const RexOperator *) const
HOST DEVICE int get_input_srid() const
Definition: sqltypes.h:330
std::vector< std::shared_ptr< Analyzer::Expr > > translateGeoColumn(const RexInput *, SQLTypeInfo &, const bool with_bounds, const bool with_render_group, const bool expand_geo_col) const
#define IS_GEO(T)
Definition: sqltypes.h:167
Definition: sqldefs.h:39
std::shared_ptr< Analyzer::Expr > fold_expr(const Analyzer::Expr *expr)
std::vector< std::shared_ptr< Analyzer::Expr > > translateGeoFunctionArg(const RexScalar *rex_scalar, SQLTypeInfo &arg_ti, int32_t &lindex, const bool with_bounds, const bool with_render_group, const bool expand_geo_col, const bool is_projection=false) const
double doubleval
Definition: sqltypes.h:131
const Catalog_Namespace::Catalog & cat_
#define IS_GEO_POLY(T)
Definition: sqltypes.h:171