OmniSciDB  c07336695a
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) const {
209  std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
210 
211  const auto rex_input = dynamic_cast<const RexInput*>(rex_scalar);
212  if (rex_input) {
213  const auto input = translateInput(rex_input);
214  const auto column = dynamic_cast<const Analyzer::ColumnVar*>(input.get());
215  if (!column || !column->get_type_info().is_geometry()) {
216  throw QueryNotSupported("Geo function is expecting a geo column argument");
217  }
218  return translateGeoColumn(
219  rex_input, arg_ti, with_bounds, with_render_group, expand_geo_col);
220  }
221  const auto rex_function = dynamic_cast<const RexFunctionOperator*>(rex_scalar);
222  if (rex_function) {
223  if (rex_function->getName() == std::string("ST_Transform")) {
224  CHECK_EQ(size_t(2), rex_function->size());
225  const auto rex_scalar0 =
226  dynamic_cast<const RexScalar*>(rex_function->getOperand(0));
227  if (!rex_scalar0) {
228  throw QueryNotSupported(rex_function->getName() + ": unexpected first argument");
229  }
230  auto arg0 = translateGeoFunctionArg(
231  rex_scalar0, arg_ti, lindex, with_bounds, with_render_group, expand_geo_col);
232 
233  const auto rex_literal =
234  dynamic_cast<const RexLiteral*>(rex_function->getOperand(1));
235  if (!rex_literal) {
236  throw QueryNotSupported(rex_function->getName() +
237  ": second argument is expected to be a literal");
238  }
239  const auto e = translateLiteral(rex_literal);
240  auto ce = std::dynamic_pointer_cast<Analyzer::Constant>(e);
241  if (!ce || !e->get_type_info().is_integer()) {
242  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
243  }
244  int32_t srid = 0;
245  if (e->get_type_info().get_type() == kSMALLINT) {
246  srid = static_cast<int32_t>(ce->get_constval().smallintval);
247  } else if (e->get_type_info().get_type() == kTINYINT) {
248  srid = static_cast<int32_t>(ce->get_constval().tinyintval);
249  } else if (e->get_type_info().get_type() == kINT) {
250  srid = static_cast<int32_t>(ce->get_constval().intval);
251  } else {
252  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
253  }
254  if (srid != 900913) {
255  throw QueryNotSupported(rex_function->getName() + ": unsupported output SRID " +
256  std::to_string(srid));
257  }
258  if (arg_ti.get_input_srid() > 0) {
259  if (arg_ti.get_input_srid() != 4326) {
260  throw QueryNotSupported(rex_function->getName() + ": unsupported input SRID " +
261  std::to_string(arg_ti.get_input_srid()));
262  }
263  arg_ti.set_output_srid(
264  srid); // We have a valid input SRID, register the output SRID for transform
265  } else {
266  throw QueryNotSupported(rex_function->getName() +
267  ": unexpected input SRID, unable to transform");
268  }
269  return arg0;
270  } else if (rex_function->getName() == std::string("ST_GeomFromText") ||
271  rex_function->getName() == std::string("ST_GeogFromText")) {
272  CHECK(rex_function->size() == size_t(1) || rex_function->size() == size_t(2));
273  // First - register srid, then send it to geo literal translation
274  int32_t srid = 0;
275  if (rex_function->size() == 2) {
276  const auto rex_literal =
277  dynamic_cast<const RexLiteral*>(rex_function->getOperand(1));
278  if (!rex_literal) {
279  throw QueryNotSupported(rex_function->getName() +
280  ": second argument is expected to be a literal");
281  }
282  const auto e = translateLiteral(rex_literal);
283  auto ce = std::dynamic_pointer_cast<Analyzer::Constant>(e);
284  if (!ce || !e->get_type_info().is_integer()) {
285  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
286  }
287  if (e->get_type_info().get_type() == kSMALLINT) {
288  srid = static_cast<int32_t>(ce->get_constval().smallintval);
289  } else if (e->get_type_info().get_type() == kTINYINT) {
290  srid = static_cast<int32_t>(ce->get_constval().tinyintval);
291  } else if (e->get_type_info().get_type() == kINT) {
292  srid = static_cast<int32_t>(ce->get_constval().intval);
293  } else {
294  throw QueryNotSupported(rex_function->getName() + " expecting integer SRID");
295  }
296  if (srid != 0 && srid != 4326 && srid != 900913) {
297  throw QueryNotSupported(rex_function->getName() + ": unsupported SRID " +
298  std::to_string(srid));
299  }
300  }
301  arg_ti.set_input_srid(srid); // Input SRID
302  arg_ti.set_output_srid(srid); // Output SRID is the same - no transform
303 
304  const auto rex_literal =
305  dynamic_cast<const RexLiteral*>(rex_function->getOperand(0));
306  if (!rex_literal) {
307  throw QueryNotSupported(rex_function->getName() +
308  " expects a string literal as first argument");
309  }
310  auto arg0 = translateGeoLiteral(rex_literal, arg_ti, with_bounds);
311  arg_ti.set_subtype((rex_function->getName() == std::string("ST_GeogFromText"))
312  ? kGEOGRAPHY
313  : kGEOMETRY);
314  return arg0;
315  } else if (rex_function->getName() == std::string("ST_PointN")) {
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() == std::string("ST_StartPoint")) {
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() == std::string("ST_EndPoint")) {
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() == std::string("ST_SRID")) {
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() == std::string("ST_SetSRID")) {
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(
423  rex_scalar0, arg_ti, lindex, with_bounds, with_render_group, expand_geo_col);
424  if (!IS_GEO(arg_ti.get_type())) {
425  throw QueryNotSupported(rex_function->getName() + " expects geometry argument");
426  }
427  const auto rex_literal =
428  dynamic_cast<const RexLiteral*>(rex_function->getOperand(1));
429  if (!rex_literal) {
430  throw QueryNotSupported(rex_function->getName() +
431  ": second argument is expected to be a literal");
432  }
433  const auto e = translateLiteral(rex_literal);
434  auto ce = std::dynamic_pointer_cast<Analyzer::Constant>(e);
435  if (!ce || !e->get_type_info().is_integer()) {
436  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
437  }
438  int32_t srid = 0;
439  if (e->get_type_info().get_type() == kSMALLINT) {
440  srid = static_cast<int32_t>(ce->get_constval().smallintval);
441  } else if (e->get_type_info().get_type() == kTINYINT) {
442  srid = static_cast<int32_t>(ce->get_constval().tinyintval);
443  } else if (e->get_type_info().get_type() == kINT) {
444  srid = static_cast<int32_t>(ce->get_constval().intval);
445  } else {
446  throw QueryNotSupported(rex_function->getName() + ": expecting integer SRID");
447  }
448  arg_ti.set_input_srid(srid); // Input SRID
449  arg_ti.set_output_srid(srid); // Output SRID is the same - no transform
450  return arg0;
451  } else if (rex_function->getName() == std::string("CastToGeography")) {
452  CHECK_EQ(size_t(1), rex_function->size());
453  const auto rex_scalar0 =
454  dynamic_cast<const RexScalar*>(rex_function->getOperand(0));
455  if (!rex_scalar0) {
456  throw QueryNotSupported(rex_function->getName() +
457  ": expects scalar as first argument");
458  }
459  auto arg0 = translateGeoFunctionArg(
460  rex_scalar0, arg_ti, lindex, with_bounds, with_render_group, expand_geo_col);
461  if (!IS_GEO(arg_ti.get_type())) {
462  throw QueryNotSupported(rex_function->getName() + " expects geometry argument");
463  }
464  if (arg_ti.get_output_srid() != 4326) {
465  throw QueryNotSupported(rex_function->getName() +
466  " expects geometry with SRID=4326");
467  }
468  arg_ti.set_subtype(kGEOGRAPHY);
469  return arg0;
470  } else if (rex_function->getName() == std::string("ST_Point")) {
471  CHECK_EQ(size_t(2), rex_function->size());
472  arg_ti.set_type(kPOINT);
473  arg_ti.set_subtype(kGEOMETRY);
474  arg_ti.set_input_srid(0);
475  arg_ti.set_output_srid(0);
477 
478  auto coord1 = translateScalarRex(rex_function->getOperand(0));
479  auto coord2 = translateScalarRex(rex_function->getOperand(1));
480  auto d_ti = SQLTypeInfo(kDOUBLE, true);
481  auto cast_coord1 = coord1->add_cast(d_ti);
482  auto cast_coord2 = coord2->add_cast(d_ti);
483  // First try to fold to geo literal
484  auto fold1 = fold_expr(cast_coord1.get());
485  auto fold2 = fold_expr(cast_coord2.get());
486  auto const_coord1 = std::dynamic_pointer_cast<Analyzer::Constant>(fold1);
487  auto const_coord2 = std::dynamic_pointer_cast<Analyzer::Constant>(fold2);
488  if (const_coord1 && const_coord2) {
489  CHECK(const_coord1->get_type_info().get_type() == kDOUBLE);
490  CHECK(const_coord2->get_type_info().get_type() == kDOUBLE);
491  std::string wkt = "POINT(" +
492  std::to_string(const_coord1->get_constval().doubleval) + " " +
493  std::to_string(const_coord2->get_constval().doubleval) + ")";
494  RexLiteral rex_literal{wkt, kTEXT, kNULLT, 0, 0, 0, 0};
495  auto args = translateGeoLiteral(&rex_literal, arg_ti, false);
496  CHECK(arg_ti.get_type() == kPOINT);
497  return args;
498  }
499  // Couldn't fold to geo literal, construct on the fly
500  auto da_ti = SQLTypeInfo(kARRAY, true);
501  da_ti.set_subtype(kDOUBLE);
502  da_ti.set_size(16);
503  auto cast_coords = {cast_coord1, cast_coord2};
504  auto ae = makeExpr<Analyzer::ArrayExpr>(da_ti, cast_coords, 0, true);
505  // cast it to tinyint[16]
506  SQLTypeInfo tia_ti = SQLTypeInfo(kARRAY, true);
507  tia_ti.set_subtype(kTINYINT);
508  tia_ti.set_size(16);
509  return {makeExpr<Analyzer::UOper>(tia_ti, false, kCAST, ae)};
510  } else {
511  throw QueryNotSupported("Unsupported argument: " + rex_function->getName());
512  }
513  }
514  const auto rex_literal = dynamic_cast<const RexLiteral*>(rex_scalar);
515  if (rex_literal) {
516  return translateGeoLiteral(rex_literal, arg_ti, with_bounds);
517  }
518  throw QueryNotSupported("Geo function argument not supported");
519 }
520 
521 namespace {
522 
523 std::string suffix(SQLTypes type) {
524  if (type == kPOINT) {
525  return std::string("_Point");
526  }
527  if (type == kLINESTRING) {
528  return std::string("_LineString");
529  }
530  if (type == kPOLYGON) {
531  return std::string("_Polygon");
532  }
533  if (type == kMULTIPOLYGON) {
534  return std::string("_MultiPolygon");
535  }
536  throw QueryNotSupported("Unsupported argument type");
537 }
538 
539 } // namespace
540 
541 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateUnaryGeoFunction(
542  const RexFunctionOperator* rex_function) const {
543  CHECK_EQ(size_t(1), rex_function->size());
544 
545  int32_t lindex = 0;
546  std::string specialized_geofunc{rex_function->getName()};
547 
548  // Geo function calls which do not need the coords col but do need cols associated with
549  // physical coords (e.g. ring_sizes / poly_rings)
550  if (rex_function->getName() == std::string("ST_NRings")) {
551  SQLTypeInfo arg_ti;
552  auto geoargs = translateGeoFunctionArg(
553  rex_function->getOperand(0), arg_ti, lindex, false, false, true);
554  if (arg_ti.get_type() == kPOLYGON) {
555  CHECK_EQ(geoargs.size(), 2u);
556  geoargs.erase(geoargs.begin(), geoargs.begin() + 1); // remove the coords
557  return makeExpr<Analyzer::FunctionOper>(
558  rex_function->getType(), specialized_geofunc, geoargs);
559  } else if (arg_ti.get_type() == kMULTIPOLYGON) {
560  CHECK_EQ(geoargs.size(), 3u);
561  geoargs.erase(geoargs.begin(), geoargs.begin() + 1); // remove the coords
562  geoargs.erase(geoargs.begin() + 1, geoargs.end()); // remove the poly_rings
563  return makeExpr<Analyzer::FunctionOper>(
564  rex_function->getType(), specialized_geofunc, geoargs);
565  } else {
566  throw QueryNotSupported(rex_function->getName() +
567  " expects a POLYGON or MULTIPOLYGON");
568  }
569  } else if (rex_function->getName() == std::string("ST_NPoints")) {
570  SQLTypeInfo arg_ti;
571  auto geoargs = translateGeoFunctionArg(
572  rex_function->getOperand(0), arg_ti, lindex, false, false, true);
573  geoargs.erase(geoargs.begin() + 1, geoargs.end()); // remove all but coords
574  // Add compression information
575  Datum input_compression;
576  input_compression.intval =
577  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
578  ? 1
579  : 0;
580  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
581  return makeExpr<Analyzer::FunctionOper>(
582  rex_function->getType(), specialized_geofunc, geoargs);
583  } else if (rex_function->getName() == std::string("ST_Perimeter") ||
584  rex_function->getName() == std::string("ST_Area")) {
585  SQLTypeInfo arg_ti;
586  auto geoargs = translateGeoFunctionArg(
587  rex_function->getOperand(0), arg_ti, lindex, false, false, true);
588  if (arg_ti.get_type() != kPOLYGON && arg_ti.get_type() != kMULTIPOLYGON) {
589  throw QueryNotSupported(rex_function->getName() +
590  " expects a POLYGON or MULTIPOLYGON");
591  }
592  specialized_geofunc += suffix(arg_ti.get_type());
593  if (arg_ti.get_subtype() == kGEOGRAPHY && arg_ti.get_output_srid() == 4326) {
594  specialized_geofunc += std::string("_Geodesic");
595  }
596  // Add compression information
597  Datum input_compression;
598  input_compression.intval =
599  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
600  ? 1
601  : 0;
602  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
603  Datum input_srid;
604  input_srid.intval = arg_ti.get_input_srid();
605  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid));
606  Datum output_srid;
607  output_srid.intval = arg_ti.get_output_srid();
608  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
609  return makeExpr<Analyzer::FunctionOper>(
610  rex_function->getType(), specialized_geofunc, geoargs);
611  }
612 
613  // Accessors for poly bounds and render group for in-situ poly render queries
614  if (rex_function->getName() == std::string("MapD_GeoPolyBoundsPtr") || // deprecated
615  rex_function->getName() == std::string("OmniSci_Geo_PolyBoundsPtr")) {
616  SQLTypeInfo arg_ti;
617  // get geo column plus bounds only (not expanded)
618  auto geoargs = translateGeoFunctionArg(
619  rex_function->getOperand(0), arg_ti, lindex, true, false, false);
620  // this function only works on polys
621  if (!IS_GEO_POLY(arg_ti.get_type())) {
622  throw QueryNotSupported(rex_function->getName() +
623  " expects a POLYGON or MULTIPOLYGON");
624  }
625  // only need the bounds argument (last), discard the rest
626  geoargs.erase(geoargs.begin(), geoargs.end() - 1);
627  // done
628  return makeExpr<Analyzer::FunctionOper>(
629  rex_function->getType(), specialized_geofunc, geoargs);
630  } else if (rex_function->getName() ==
631  std::string("MapD_GeoPolyRenderGroup") || // deprecated
632  rex_function->getName() == std::string("OmniSci_Geo_PolyRenderGroup")) {
633  SQLTypeInfo arg_ti;
634  // get geo column plus render_group only (not expanded)
635  auto geoargs = translateGeoFunctionArg(
636  rex_function->getOperand(0), arg_ti, lindex, false, true, false);
637  // this function only works on polys
638  if (!IS_GEO_POLY(arg_ti.get_type())) {
639  throw QueryNotSupported(rex_function->getName() +
640  " expects a POLYGON or MULTIPOLYGON");
641  }
642  // only need the render_group argument (last), discard the rest
643  geoargs.erase(geoargs.begin(), geoargs.end() - 1);
644  // done
645  return makeExpr<Analyzer::FunctionOper>(
646  rex_function->getType(), specialized_geofunc, geoargs);
647  }
648 
649  // All functions below use geo col as reference and expand it as necessary
650  SQLTypeInfo arg_ti;
651  bool with_bounds = true;
652  auto geoargs = translateGeoFunctionArg(
653  rex_function->getOperand(0), arg_ti, lindex, with_bounds, false, false);
654 
655  if (rex_function->getName() == std::string("ST_SRID")) {
656  Datum output_srid;
657  output_srid.intval = arg_ti.get_output_srid();
658  return makeExpr<Analyzer::Constant>(kINT, false, output_srid);
659  }
660 
661  if (rex_function->getName() == std::string("ST_XMin") ||
662  rex_function->getName() == std::string("ST_YMin") ||
663  rex_function->getName() == std::string("ST_XMax") ||
664  rex_function->getName() == std::string("ST_YMax")) {
665  // If type has bounds - use them, otherwise look at coords
666  if (arg_ti.has_bounds()) {
667  if (lindex != 0) {
668  throw QueryNotSupported(rex_function->getName() +
669  " doesn't support indexed LINESTRINGs");
670  }
671  // Only need the bounds argument, discard the rest
672  geoargs.erase(geoargs.begin(), geoargs.end() - 1);
673 
674  // Supply srids too - transformed geo would have a transformed bounding box
675  Datum input_srid;
676  input_srid.intval = arg_ti.get_input_srid();
677  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid));
678  Datum output_srid;
679  output_srid.intval = arg_ti.get_output_srid();
680  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
681 
682  specialized_geofunc += std::string("_Bounds");
683  return makeExpr<Analyzer::FunctionOper>(
684  rex_function->getType(), specialized_geofunc, geoargs);
685  }
686  }
687 
688  // All geo function calls translated below only need the coords, extras e.g. ring_sizes
689  // are dropped. Specialize for other/new functions if needed.
690  geoargs.erase(geoargs.begin() + 1, geoargs.end());
691 
692  if (rex_function->getName() == std::string("ST_X") ||
693  rex_function->getName() == std::string("ST_Y")) {
694  if (arg_ti.get_type() == kLINESTRING) {
695  if (lindex == 0) {
696  throw QueryNotSupported(
697  rex_function->getName() +
698  " expects a POINT, use LINESTRING accessor, e.g. ST_POINTN");
699  }
700  Datum index;
701  index.intval = lindex;
702  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, index));
703  } else if (arg_ti.get_type() != kPOINT) {
704  throw QueryNotSupported(rex_function->getName() + " expects a POINT");
705  }
706  specialized_geofunc += suffix(arg_ti.get_type());
707  } else if (rex_function->getName() == std::string("ST_Length")) {
708  if (arg_ti.get_type() != kLINESTRING || lindex != 0) {
709  throw QueryNotSupported(rex_function->getName() + " expects unindexed LINESTRING");
710  }
711  specialized_geofunc += suffix(arg_ti.get_type());
712  if (arg_ti.get_subtype() == kGEOGRAPHY && arg_ti.get_output_srid() == 4326) {
713  specialized_geofunc += std::string("_Geodesic");
714  }
715  }
716 
717  // Add input compression mode and SRID args to enable on-the-fly
718  // decompression/transforms
719  Datum input_compression;
720  input_compression.intval =
721  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32) ? 1
722  : 0;
723  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
724  Datum input_srid;
725  input_srid.intval = arg_ti.get_input_srid();
726  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid));
727 
728  // Add output SRID arg to enable on-the-fly transforms
729  Datum output_srid;
730  output_srid.intval = arg_ti.get_output_srid();
731  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
732 
733  return makeExpr<Analyzer::FunctionOper>(
734  rex_function->getType(), specialized_geofunc, geoargs);
735 }
736 
737 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateBinaryGeoFunction(
738  const RexFunctionOperator* rex_function) const {
739  auto function_name = rex_function->getName();
740  auto return_type = rex_function->getType();
741  bool swap_args = false;
742  bool with_bounds = false;
743  bool negate_result = false;
744  if (function_name == "ST_DWithin") {
745  CHECK_EQ(size_t(3), rex_function->size());
746  function_name = "ST_Distance";
747  return_type = SQLTypeInfo(kDOUBLE, false);
748  } else if (function_name == "ST_DFullyWithin") {
749  CHECK_EQ(size_t(3), rex_function->size());
750  function_name = "ST_MaxDistance";
751  return_type = SQLTypeInfo(kDOUBLE, false);
752  } else {
753  CHECK_EQ(size_t(2), rex_function->size());
754  }
755  if (function_name == std::string("ST_Within")) {
756  function_name = "ST_Contains";
757  swap_args = true;
758  } else if (function_name == std::string("ST_Disjoint")) {
759  function_name = "ST_Intersects";
760  negate_result = true;
761  }
762  if (function_name == std::string("ST_Contains") ||
763  function_name == std::string("ST_Intersects")) {
764  with_bounds = true;
765  }
766 
767  std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
768  SQLTypeInfo arg0_ti;
769  SQLTypeInfo arg1_ti;
770  int32_t lindex0 = 0;
771  int32_t lindex1 = 0;
772 
773  auto geoargs0 = translateGeoFunctionArg(rex_function->getOperand(swap_args ? 1 : 0),
774  arg0_ti,
775  lindex0,
776  with_bounds,
777  false,
778  false);
779  if (arg0_ti.get_type() == kLINESTRING) {
780  Datum index;
781  index.intval = lindex0;
782  geoargs0.push_back(makeExpr<Analyzer::Constant>(kINT, false, index));
783  }
784  geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
785  auto geoargs1 = translateGeoFunctionArg(rex_function->getOperand(swap_args ? 0 : 1),
786  arg1_ti,
787  lindex1,
788  with_bounds,
789  false,
790  false);
791  if (arg1_ti.get_type() == kLINESTRING) {
792  Datum index;
793  index.intval = lindex1;
794  geoargs1.push_back(makeExpr<Analyzer::Constant>(kINT, false, index));
795  }
796  geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
797 
798  if (arg0_ti.get_subtype() != kNULLT && arg0_ti.get_subtype() != arg1_ti.get_subtype()) {
799  throw QueryNotSupported(rex_function->getName() +
800  " accepts either two GEOGRAPHY or two GEOMETRY arguments");
801  }
802  if (arg0_ti.get_output_srid() > 0 &&
803  arg0_ti.get_output_srid() != arg1_ti.get_output_srid()) {
804  throw QueryNotSupported(rex_function->getName() + " cannot accept different SRIDs");
805  }
806 
807  std::string specialized_geofunc{function_name + suffix(arg0_ti.get_type()) +
808  suffix(arg1_ti.get_type())};
809 
810  if (arg0_ti.get_subtype() == kGEOGRAPHY && arg0_ti.get_output_srid() == 4326) {
811  // Need to call geodesic runtime functions
812  if (function_name == std::string("ST_Distance")) {
813  if ((arg0_ti.get_type() == kPOINT ||
814  (arg0_ti.get_type() == kLINESTRING && lindex0 != 0)) &&
815  (arg1_ti.get_type() == kPOINT ||
816  (arg1_ti.get_type() == kLINESTRING && lindex1 != 0))) {
817  // Geodesic distance between points (or indexed linestrings)
818  specialized_geofunc += std::string("_Geodesic");
819  } else {
820  throw QueryNotSupported(function_name +
821  " currently doesn't accept non-POINT geographies");
822  }
823  } else if (rex_function->getName() == std::string("ST_Contains")) {
824  // We currently don't have a geodesic implementation of ST_Contains,
825  // allowing calls to a [less precise] cartesian implementation.
826  } else {
827  throw QueryNotSupported(function_name + " doesn't accept geographies");
828  }
829  } else if (function_name == std::string("ST_Distance") && rex_function->size() == 3) {
830  if (arg0_ti.get_type() == kPOINT && arg1_ti.get_type() == kPOINT) {
831  // Cartesian distance between points used by ST_DWithin - switch to faster Squared
832  specialized_geofunc += std::string("_Squared");
833  }
834  }
835 
836  // Add first input's compression mode and SRID args to enable on-the-fly
837  // decompression/transforms
838  Datum input_compression0;
839  input_compression0.intval =
840  (arg0_ti.get_compression() == kENCODING_GEOINT && arg0_ti.get_comp_param() == 32)
841  ? 1
842  : 0;
843  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression0));
844  Datum input_srid0;
845  input_srid0.intval = arg0_ti.get_input_srid();
846  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid0));
847 
848  // Add second input's compression mode and SRID args to enable on-the-fly
849  // decompression/transforms
850  Datum input_compression1;
851  input_compression1.intval =
852  (arg1_ti.get_compression() == kENCODING_GEOINT && arg1_ti.get_comp_param() == 32)
853  ? 1
854  : 0;
855  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression1));
856  Datum input_srid1;
857  input_srid1.intval = arg1_ti.get_input_srid();
858  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid1));
859 
860  // Add output SRID arg to enable on-the-fly transforms
861  Datum output_srid;
862  output_srid.intval = arg0_ti.get_output_srid();
863  geoargs.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
864 
865  auto result =
866  makeExpr<Analyzer::FunctionOper>(return_type, specialized_geofunc, geoargs);
867  if (negate_result) {
868  return makeExpr<Analyzer::UOper>(kBOOLEAN, kNOT, result);
869  }
870  return result;
871 }
872 
873 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateTernaryGeoFunction(
874  const RexFunctionOperator* rex_function) const {
875  CHECK_EQ(size_t(3), rex_function->size());
876 
877  auto distance_expr = translateScalarRex(rex_function->getOperand(2));
878  const auto& distance_ti = SQLTypeInfo(kDOUBLE, false);
879  if (distance_expr->get_type_info().get_type() != kDOUBLE) {
880  distance_expr->add_cast(distance_ti);
881  }
882 
883  // Translate the geo distance function call portion
884  const auto geo_distance_expr = translateBinaryGeoFunction(rex_function);
885 
886  if (rex_function->getName() == std::string("ST_DWithin")) {
887  auto func_oper = dynamic_cast<Analyzer::FunctionOper*>(geo_distance_expr.get());
888  if (func_oper &&
889  func_oper->getName() == std::string("ST_Distance_Point_Point_Squared")) {
890  // Point_Point combination will yield geo_distance squared which is faster,
891  // need to compare it with distance squared
892  distance_expr = makeExpr<Analyzer::BinOper>(distance_ti,
893  distance_expr->get_contains_agg(),
894  kMULTIPLY,
895  kONE,
896  distance_expr,
897  distance_expr);
898  distance_expr = fold_expr(distance_expr.get());
899  }
900  }
901 
902  return makeExpr<Analyzer::BinOper>(
903  kBOOLEAN, kLE, kONE, geo_distance_expr, distance_expr);
904 }
905 
906 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateGeoComparison(
907  const RexOperator* rex_operator) const {
908  if (rex_operator->size() != size_t(2)) {
909  return nullptr;
910  }
911 
912  auto geo_distance_expr = translateScalarRex(rex_operator->getOperand(0));
913  auto func_oper = dynamic_cast<Analyzer::FunctionOper*>(geo_distance_expr.get());
914  if (func_oper && func_oper->getName() == std::string("ST_Distance_Point_Point")) {
915  const auto& distance_ti = SQLTypeInfo(kDOUBLE, false);
916  std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
917  for (size_t i = 0; i < func_oper->getArity(); i++) {
918  geoargs.push_back(func_oper->getOwnArg(i));
919  }
920  geo_distance_expr = makeExpr<Analyzer::FunctionOper>(
921  distance_ti, std::string("ST_Distance_Point_Point_Squared"), geoargs);
922  auto distance_expr = translateScalarRex(rex_operator->getOperand(1));
923  if (distance_expr->get_type_info().get_type() != kDOUBLE) {
924  distance_expr->add_cast(distance_ti);
925  }
926  distance_expr = makeExpr<Analyzer::BinOper>(distance_ti,
927  distance_expr->get_contains_agg(),
928  kMULTIPLY,
929  kONE,
930  distance_expr,
931  distance_expr);
932  distance_expr = fold_expr(distance_expr.get());
933  return makeExpr<Analyzer::BinOper>(
934  kBOOLEAN, rex_operator->getOperator(), kONE, geo_distance_expr, distance_expr);
935  }
936  return nullptr;
937 }
938 
939 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateFunctionWithGeoArg(
940  const RexFunctionOperator* rex_function) const {
941  int32_t lindex = 0;
942  std::string specialized_geofunc{rex_function->getName()};
943  if (rex_function->getName() == std::string("convert_meters_to_pixel_width") ||
944  rex_function->getName() == std::string("convert_meters_to_pixel_height")) {
945  CHECK_EQ(rex_function->size(), 6u);
946  SQLTypeInfo arg_ti;
947  std::vector<std::shared_ptr<Analyzer::Expr>> args;
948  args.push_back(translateScalarRex(rex_function->getOperand(0)));
949  auto geoargs = translateGeoFunctionArg(
950  rex_function->getOperand(1), arg_ti, lindex, false, true, false);
951  // only works on points
952  if (arg_ti.get_type() != kPOINT) {
953  throw QueryNotSupported(rex_function->getName() +
954  " expects a point for the second argument");
955  }
956 
957  args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
958 
959  // Add compression information
960  Datum input_compression;
961  input_compression.intval =
962  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
963  ? 1
964  : 0;
965  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
966  if (arg_ti.get_input_srid() != 4326) {
967  throw QueryNotSupported(
968  rex_function->getName() +
969  " currently only supports points of with SRID WGS84/EPSG:4326");
970  }
971  Datum input_srid;
972  input_srid.intval = arg_ti.get_input_srid();
973  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_srid));
974  Datum output_srid;
975  // Forcing web-mercator projection for now
976  // TODO(croot): check that the input-to-output conversion routines exist?
977  output_srid.intval =
978  arg_ti.get_output_srid() != 900913 ? 900913 : arg_ti.get_output_srid();
979  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, output_srid));
980 
981  args.push_back(translateScalarRex(rex_function->getOperand(2)));
982  args.push_back(translateScalarRex(rex_function->getOperand(3)));
983  args.push_back(translateScalarRex(rex_function->getOperand(4)));
984  args.push_back(translateScalarRex(rex_function->getOperand(5)));
985  return makeExpr<Analyzer::FunctionOper>(
986  rex_function->getType(), specialized_geofunc, args);
987  } else if (rex_function->getName() == std::string("is_point_in_view")) {
988  CHECK_EQ(rex_function->size(), 5u);
989  SQLTypeInfo arg_ti;
990  std::vector<std::shared_ptr<Analyzer::Expr>> args;
991  auto geoargs = translateGeoFunctionArg(
992  rex_function->getOperand(0), arg_ti, lindex, false, true, false);
993  // only works on points
994  if (arg_ti.get_type() != kPOINT) {
995  throw QueryNotSupported(rex_function->getName() +
996  " expects a point for the second argument");
997  }
998 
999  args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1000 
1001  // Add compression information
1002  Datum input_compression;
1003  input_compression.intval =
1004  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
1005  ? 1
1006  : 0;
1007  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
1008  if (arg_ti.get_input_srid() != 4326) {
1009  throw QueryNotSupported(
1010  rex_function->getName() +
1011  " currently only supports points of with SRID WGS84/EPSG:4326");
1012  }
1013  args.push_back(translateScalarRex(rex_function->getOperand(1)));
1014  args.push_back(translateScalarRex(rex_function->getOperand(2)));
1015  args.push_back(translateScalarRex(rex_function->getOperand(3)));
1016  args.push_back(translateScalarRex(rex_function->getOperand(4)));
1017  return makeExpr<Analyzer::FunctionOper>(
1018  rex_function->getType(), specialized_geofunc, args);
1019  } else if (rex_function->getName() == std::string("is_point_size_in_view")) {
1020  CHECK_EQ(rex_function->size(), 6u);
1021  SQLTypeInfo arg_ti;
1022  std::vector<std::shared_ptr<Analyzer::Expr>> args;
1023  auto geoargs = translateGeoFunctionArg(
1024  rex_function->getOperand(0), arg_ti, lindex, false, true, false);
1025  // only works on points
1026  if (arg_ti.get_type() != kPOINT) {
1027  throw QueryNotSupported(rex_function->getName() +
1028  " expects a point for the second argument");
1029  }
1030 
1031  args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1032 
1033  // Add compression information
1034  Datum input_compression;
1035  input_compression.intval =
1036  (arg_ti.get_compression() == kENCODING_GEOINT && arg_ti.get_comp_param() == 32)
1037  ? 1
1038  : 0;
1039  args.push_back(makeExpr<Analyzer::Constant>(kINT, false, input_compression));
1040  if (arg_ti.get_input_srid() != 4326) {
1041  throw QueryNotSupported(
1042  rex_function->getName() +
1043  " currently only supports points of with SRID WGS84/EPSG:4326");
1044  }
1045  args.push_back(translateScalarRex(rex_function->getOperand(1)));
1046  args.push_back(translateScalarRex(rex_function->getOperand(2)));
1047  args.push_back(translateScalarRex(rex_function->getOperand(3)));
1048  args.push_back(translateScalarRex(rex_function->getOperand(4)));
1049  args.push_back(translateScalarRex(rex_function->getOperand(5)));
1050  return makeExpr<Analyzer::FunctionOper>(
1051  rex_function->getType(), specialized_geofunc, args);
1052  }
1053  CHECK(false);
1054  return nullptr;
1055 }
1056 
1057 std::shared_ptr<Analyzer::Expr> RelAlgTranslator::translateGeoOverlapsOper(
1058  const RexOperator* rex_operator) const {
1059  CHECK_EQ(rex_operator->size(), 2u);
1060 
1061  auto translate_input =
1062  [&](const RexScalar* operand) -> std::shared_ptr<Analyzer::Expr> {
1063  const auto input = dynamic_cast<const RexInput*>(operand);
1064  CHECK(input);
1065 
1066  SQLTypeInfo ti;
1067  const auto exprs = translateGeoColumn(input, ti, true, false, false);
1068  CHECK_GT(exprs.size(), 0u);
1069  if (ti.get_type() == kPOINT) {
1070  return exprs.front();
1071  } else {
1072  return exprs.back();
1073  }
1074  };
1075 
1076  SQLQualifier sql_qual{kONE};
1077  SQLOps sql_op{kOVERLAPS};
1078  return makeExpr<Analyzer::BinOper>(SQLTypeInfo(kBOOLEAN, false),
1079  false,
1080  sql_op,
1081  sql_qual,
1082  translate_input(rex_operator->getOperand(1)),
1083  translate_input(rex_operator->getOperand(0)));
1084 }
int8_t tinyintval
Definition: sqltypes.h:123
std::shared_ptr< Analyzer::Expr > translateGeoComparison(const RexOperator *) const
SQLOps getOperator() const
#define CHECK_EQ(x, y)
Definition: Logger.h:195
int get_physical_coord_cols() const
Definition: sqltypes.h:355
std::shared_ptr< Analyzer::Expr > translateGeoOverlapsOper(const RexOperator *) const
void d(const SQLTypes expected_type, const std::string &str)
Definition: ImportTest.cpp:268
SQLTypes
Definition: sqltypes.h:40
#define SPIMAP_GEO_PHYSICAL_INPUT(c, i)
Definition: Catalog.h:70
SQLQualifier
Definition: sqldefs.h:69
SQLOps
Definition: sqldefs.h:29
Definition: sqldefs.h:35
void set_size(int s)
Definition: sqltypes.h:417
void c(const std::string &query_string, const ExecutorDeviceType device_type)
HOST DEVICE SQLTypes get_type() const
Definition: sqltypes.h:319
std::vector< uint8_t > compress_coords(std::vector< double > &coords, const SQLTypeInfo &ti)
Definition: Importer.cpp:1546
void set_input_srid(int d)
Definition: sqltypes.h:413
std::shared_ptr< Analyzer::Expr > translateFunctionWithGeoArg(const RexFunctionOperator *) const
#define CHECK_GE(x, y)
Definition: Logger.h:200
Definition: sqldefs.h:49
HOST DEVICE void set_type(SQLTypes t)
Definition: sqltypes.h:409
std::shared_ptr< Analyzer::Expr > translateUnaryGeoFunction(const RexFunctionOperator *) const
#define CHECK_GT(x, y)
Definition: Logger.h:199
HOST DEVICE EncodingType get_compression() const
Definition: sqltypes.h:327
void set_compression(EncodingType c)
Definition: sqltypes.h:419
int32_t intval
Definition: sqltypes.h:125
std::string to_string(char const *&&v)
void set_output_srid(int s)
Definition: sqltypes.h:415
HOST DEVICE void set_subtype(SQLTypes st)
Definition: sqltypes.h:410
std::shared_ptr< Analyzer::Expr > translateBinaryGeoFunction(const RexFunctionOperator *) const
static std::shared_ptr< Analyzer::Expr > translateLiteral(const RexLiteral *)
const RelAlgNode * getSourceNode() const
std::shared_ptr< Analyzer::Expr > translateScalarRex(const RexScalar *rex) const
HOST DEVICE SQLTypes get_subtype() const
Definition: sqltypes.h:320
HOST DEVICE int get_input_srid() const
Definition: sqltypes.h:323
bool has_render_group() const
Definition: sqltypes.h:399
const RexScalar * getOperand(const size_t idx) const
std::vector< std::shared_ptr< Analyzer::Expr > > translateGeoLiteral(const RexLiteral *, SQLTypeInfo &, bool) const
SQLTypeInfoCore< ArrayContextTypeSizer, ExecutorTypePackaging, DateTimeFacilities > SQLTypeInfo
Definition: sqltypes.h:819
const std::unordered_map< const RelAlgNode *, int > input_to_nest_level_
#define CHECK_LT(x, y)
Definition: Logger.h:197
Definition: sqltypes.h:54
HOST DEVICE int get_output_srid() const
Definition: sqltypes.h:325
Definition: sqldefs.h:69
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
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
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
void set_comp_param(int p)
Definition: sqltypes.h:420
const ColumnDescriptor * getMetadataForColumnBySpi(const int tableId, const size_t spi) const
Definition: Catalog.cpp:1435
HOST DEVICE int get_comp_param() const
Definition: sqltypes.h:328
#define CHECK(condition)
Definition: Logger.h:187
const SQLTypeInfo & getType() const
Definition: sqltypes.h:47
SQLTypeInfo columnType
const std::string & getName() const
std::shared_ptr< Analyzer::Expr > translateTernaryGeoFunction(const RexFunctionOperator *) const
std::shared_ptr< Analyzer::Expr > translateInput(const RexInput *) const
#define IS_GEO(T)
Definition: sqltypes.h:165
Definition: sqldefs.h:39
bool has_bounds() const
Definition: sqltypes.h:388
std::shared_ptr< Analyzer::Expr > fold_expr(const Analyzer::Expr *expr)
double doubleval
Definition: sqltypes.h:128
const Catalog_Namespace::Catalog & cat_
#define IS_GEO_POLY(T)
Definition: sqltypes.h:169