31 const bool with_bounds,
32 const bool expand_geo_col)
const {
33 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
37 const int rte_idx = it_rte_idx->second;
38 const auto& in_metainfo = source->getOutputMetainfo();
44 const auto scan_source =
dynamic_cast<const RelScan*
>(source);
48 CHECK(in_metainfo.empty());
50 const auto td = scan_source->getTableDescriptor();
51 table_id = td->tableId;
53 catalog = &scan_source->getCatalog();
54 db_id = catalog->getDatabaseId();
56 catalog->getMetadataForColumnBySpi(table_id, rex_input->
getIndex() + 1);
59 column_id = gcd->columnId;
64 table_id = -source->getId();
68 "Geospatial columns not yet supported in intermediate results.");
71 CHECK(!in_metainfo.empty());
74 CHECK_LT(static_cast<size_t>(column_id), in_metainfo.size());
75 ti = in_metainfo[column_id].get_type_info();
76 if (expand_geo_col && ti.is_geometry()) {
78 "Geospatial columns not yet supported in this temporary table context.");
84 "Geospatial expression and operator require geospatial column as their input "
94 const auto pcd = catalog->getMetadataForColumnBySpi(
96 auto pcol_ti = pcd->columnType;
97 args.push_back(std::make_shared<Analyzer::ColumnVar>(
101 args.push_back(std::make_shared<Analyzer::ColumnVar>(
106 const auto bounds_cd = catalog->getMetadataForColumnBySpi(
110 auto bounds_ti = bounds_cd->columnType;
111 args.push_back(std::make_shared<Analyzer::ColumnVar>(
118 const RexLiteral* rex_literal,
120 bool with_bounds)
const {
122 if (rex_literal->getType() !=
kTEXT) {
123 throw std::runtime_error(
"Geo literals must be strings");
130 std::vector<double> coords;
131 std::vector<double> bounds;
132 std::vector<int> ring_sizes;
133 std::vector<int> poly_rings;
135 const bool validate_with_geos_if_available =
false;
142 validate_with_geos_if_available)) {
154 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
157 std::list<std::shared_ptr<Analyzer::Expr>> compressed_coords_exprs;
158 for (
auto cc : compressed_coords) {
161 auto e = makeExpr<Analyzer::Constant>(
kTINYINT,
false, d);
162 compressed_coords_exprs.push_back(e);
166 arr_ti.
set_size(compressed_coords.size() *
sizeof(int8_t));
169 args.push_back(makeExpr<Analyzer::Constant>(arr_ti,
false, compressed_coords_exprs));
174 std::list<std::shared_ptr<Analyzer::Expr>> ring_size_exprs;
175 for (
auto c : ring_sizes) {
178 auto e = makeExpr<Analyzer::Constant>(
kINT,
false, d);
179 ring_size_exprs.push_back(e);
183 arr_ti.
set_size(ring_sizes.size() *
sizeof(int32_t));
184 args.push_back(makeExpr<Analyzer::Constant>(arr_ti,
false, ring_size_exprs));
188 std::list<std::shared_ptr<Analyzer::Expr>> poly_rings_exprs;
189 for (
auto c : poly_rings) {
192 auto e = makeExpr<Analyzer::Constant>(
kINT,
false, d);
193 poly_rings_exprs.push_back(e);
197 arr_ti.
set_size(poly_rings.size() *
sizeof(int32_t));
198 args.push_back(makeExpr<Analyzer::Constant>(arr_ti,
false, poly_rings_exprs));
204 std::list<std::shared_ptr<Analyzer::Expr>> bounds_exprs;
205 for (
auto b : bounds) {
208 auto e = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, d);
209 bounds_exprs.push_back(e);
213 arr_ti.
set_size(bounds.size() *
sizeof(double));
214 args.push_back(makeExpr<Analyzer::Constant>(arr_ti,
false, bounds_exprs));
224 return std::string(
"_Point");
227 return std::string(
"_MultiPoint");
230 return std::string(
"_LineString");
233 return std::string(
"_MultiLineString");
236 return std::string(
"_Polygon");
239 return std::string(
"_MultiPolygon");
276 const bool with_bounds,
277 const bool expand_geo_col,
279 const bool use_geo_expressions,
280 const bool try_to_compress,
281 const bool allow_gdal_transforms)
const {
282 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
284 const auto rex_input =
dynamic_cast<const RexInput*
>(rex_scalar);
288 if (!column || !column->get_type_info().is_geometry()) {
291 if (use_geo_expressions) {
292 arg_ti = column->get_type_info();
293 return {makeExpr<Analyzer::GeoColumnVar>(column, with_bounds)};
299 if (rex_function->getName() ==
"ST_Transform"sv) {
300 CHECK_EQ(
size_t(2), rex_function->size());
301 const auto rex_scalar0 =
302 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
304 throw QueryNotSupported(rex_function->getName() +
": unexpected first argument");
307 const auto rex_literal =
308 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
311 ": second argument is expected to be a literal");
315 if (!ce || !e->get_type_info().is_integer()) {
319 if (e->get_type_info().get_type() ==
kSMALLINT) {
320 srid =
static_cast<int32_t
>(ce->get_constval().smallintval);
321 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
322 srid =
static_cast<int32_t
>(ce->get_constval().tinyintval);
323 }
else if (e->get_type_info().get_type() ==
kINT) {
324 srid =
static_cast<int32_t
>(ce->get_constval().intval);
328 bool allow_result_gdal_transform =
false;
330 if (rex_function0 &&
func_resolve(rex_function0->getName(),
336 "ST_ConvexHull"sv)) {
347 if (!allow_gdal_transforms && !allow_result_gdal_transform) {
348 if (srid != 900913 && ((use_geo_expressions || is_projection) && srid != 4326 &&
355 bool arg0_use_geo_expressions = is_projection ?
true : use_geo_expressions;
356 if (allow_gdal_transforms) {
357 arg0_use_geo_expressions =
false;
364 arg0_use_geo_expressions);
366 if (use_geo_expressions) {
368 auto arg0_ti = arg0.front()->get_type_info();
369 arg0_ti.set_output_srid(srid);
370 if (arg0_ti.get_type() ==
kPOINT) {
373 const auto input_srid = arg0_ti.get_input_srid();
374 arg0_ti.set_input_srid(srid);
377 arg0_ti.set_comp_param(0);
382 return {makeExpr<Analyzer::GeoTransformOperator>(
383 arg0_ti, rex_function->getName(), arg0, input_srid, srid)};
385 if (
auto geo_constant =
386 std::dynamic_pointer_cast<Analyzer::GeoConstant>(arg0.front())) {
388 auto cast_geo_constant = geo_constant->add_cast(arg0_ti);
390 arg_ti = cast_geo_constant->get_type_info();
391 return {cast_geo_constant};
392 }
else if (
auto col_var =
393 std::dynamic_pointer_cast<Analyzer::ColumnVar>(arg0.front())) {
394 const auto& col_ti = col_var->get_type_info();
395 CHECK(col_ti.is_geometry());
396 if (col_ti.get_type() !=
kPOINT) {
401 if (!allow_gdal_transforms && !allow_result_gdal_transform) {
402 throw std::runtime_error(
403 "Transform on non-POINT geospatial types not yet supported in this "
411 if (!allow_gdal_transforms && !allow_result_gdal_transform) {
414 ": unsupported input SRID " +
419 if (allow_result_gdal_transform) {
429 ": unexpected input SRID, unable to transform");
433 rex_function->getName(),
"ST_GeomFromText"sv,
"ST_GeogFromText"sv)) {
434 CHECK(rex_function->size() == size_t(1) || rex_function->size() == size_t(2));
435 if (use_geo_expressions) {
437 if (rex_function->size() == 2) {
439 const auto rex_literal =
440 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
443 ": second argument is expected to be a literal");
447 if (!ce || !e->get_type_info().is_integer()) {
450 if (e->get_type_info().get_type() ==
kSMALLINT) {
451 srid =
static_cast<int32_t
>(ce->get_constval().smallintval);
452 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
453 srid =
static_cast<int32_t
>(ce->get_constval().tinyintval);
454 }
else if (e->get_type_info().get_type() ==
kINT) {
455 srid =
static_cast<int32_t
>(ce->get_constval().intval);
459 if (srid != 0 && srid != 4326 && srid != 900913) {
467 if (rex_function->getName() ==
"ST_GeogFromText"sv) {
478 use_geo_expressions);
479 CHECK_GE(func_args.size(), size_t(1));
485 if (rex_function->size() == 2) {
486 const auto rex_literal =
487 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
490 ": second argument is expected to be a literal");
494 if (!ce || !e->get_type_info().is_integer()) {
497 if (e->get_type_info().get_type() ==
kSMALLINT) {
498 srid =
static_cast<int32_t
>(ce->get_constval().smallintval);
499 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
500 srid =
static_cast<int32_t
>(ce->get_constval().tinyintval);
501 }
else if (e->get_type_info().get_type() ==
kINT) {
502 srid =
static_cast<int32_t
>(ce->get_constval().intval);
506 if (srid != 0 && srid != 4326 && srid != 900913) {
514 const auto rex_literal =
515 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(0));
518 " expects a string literal as first argument");
524 }
else if (rex_function->getName() ==
"ST_PointN"sv) {
526 const auto rex_scalar0 =
527 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
530 ": expects scalar as first argument");
540 if (arg0.front()->get_type_info().get_type() !=
kLINESTRING) {
542 " expects LINESTRING as first argument");
544 const auto rex_literal =
545 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
548 ": second argument is expected to be a literal");
552 if (!ce || !e->get_type_info().is_integer()) {
554 ": expecting integer index as second argument");
557 if (e->get_type_info().get_type() ==
kSMALLINT) {
558 index =
static_cast<int32_t
>(ce->get_constval().smallintval);
559 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
560 index =
static_cast<int32_t
>(ce->get_constval().tinyintval);
561 }
else if (e->get_type_info().get_type() ==
kINT) {
562 index =
static_cast<int32_t
>(ce->get_constval().intval);
572 arg0.front()->get_type_info();
574 oper_ti.set_notnull(
false);
578 return {makeExpr<Analyzer::GeoOperator>(oper_ti, rex_function->getName(), arg0)};
580 }
else if (rex_function->getName() ==
"ST_StartPoint"sv ||
581 rex_function->getName() ==
"ST_EndPoint"sv) {
582 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
583 CHECK_EQ(
size_t(1), rex_function->size());
590 CHECK_EQ(arg_exprs.size(), size_t(1));
591 CHECK(arg_exprs.front());
592 const auto arg_expr_ti = arg_exprs.front()->get_type_info();
595 " expected LINESTRING argument. Received " +
596 arg_expr_ti.toString());
598 args.push_back(arg_exprs.front());
600 auto oper_ti = args.back()->get_type_info();
605 return {makeExpr<Analyzer::GeoOperator>(oper_ti, rex_function->getName(),
args)};
606 }
else if (rex_function->getName() ==
"ST_SRID"sv) {
607 CHECK_EQ(
size_t(1), rex_function->size());
608 const auto rex_scalar0 =
609 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
612 ": expects scalar as first argument");
620 }
else if (rex_function->getName() ==
"ST_SetSRID"sv) {
621 CHECK_EQ(
size_t(2), rex_function->size());
622 const auto rex_literal =
623 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
626 ": second argument is expected to be a literal");
630 if (!ce || !e->get_type_info().is_integer()) {
634 if (e->get_type_info().get_type() ==
kSMALLINT) {
635 srid =
static_cast<int32_t
>(ce->get_constval().smallintval);
636 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
637 srid =
static_cast<int32_t
>(ce->get_constval().tinyintval);
638 }
else if (e->get_type_info().get_type() ==
kINT) {
639 srid =
static_cast<int32_t
>(ce->get_constval().intval);
644 const auto rex_scalar0 =
645 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
648 ": expects scalar as first argument");
658 (try_to_compress && (srid == 4326)));
660 CHECK(!arg0.empty() && arg0.front());
666 if (
auto geo_expr = std::dynamic_pointer_cast<Analyzer::GeoExpr>(arg0.front())) {
668 auto ti = geo_expr->get_type_info();
669 ti.set_input_srid(srid);
670 ti.set_output_srid(srid);
671 return {geo_expr->add_cast(ti)};
674 }
else if (rex_function->getName() ==
"CastToGeography"sv) {
675 CHECK_EQ(
size_t(1), rex_function->size());
676 const auto rex_scalar0 =
677 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
680 ": expects scalar as first argument");
687 use_geo_expressions);
688 CHECK(!arg0.empty());
689 if (
auto geo_expr = std::dynamic_pointer_cast<Analyzer::GeoExpr>(arg0.front())) {
690 auto arg_ti = geo_expr->get_type_info();
692 return {geo_expr->add_cast(arg_ti)};
694 if (use_geo_expressions) {
695 arg_ti = arg0.front()->get_type_info();
697 arg0.front()->set_type_info(arg_ti);
704 " expects geometry with SRID=4326");
708 }
else if (rex_function->getName() ==
"ST_Point"sv) {
709 CHECK_EQ(
size_t(2), rex_function->size());
719 auto cast_coord1 = coord1->add_cast(d_ti);
720 auto cast_coord2 = coord2->add_cast(d_ti);
722 auto folded_coord1 =
fold_expr(cast_coord1.get());
723 auto folded_coord2 =
fold_expr(cast_coord2.get());
726 if (const_coord1 && const_coord2 && !use_geo_expressions) {
727 CHECK(const_coord1->get_type_info().get_type() ==
kDOUBLE);
728 CHECK(const_coord2->get_type_info().get_type() ==
kDOUBLE);
729 std::string wkt =
"POINT(" +
732 RexLiteral rex_literal{wkt,
kTEXT,
kNULLT, 0, 0, 0, 0};
738 if (!is_local_alloca || use_geo_expressions) {
739 if (try_to_compress) {
743 return {makeExpr<Analyzer::GeoOperator>(
745 rex_function->getName(),
746 std::vector<std::shared_ptr<Analyzer::Expr>>{folded_coord1, folded_coord2})};
752 if (try_to_compress) {
754 da_ti.set_subtype(
kINT);
756 da_ti.set_input_srid(4326);
757 da_ti.set_output_srid(4326);
759 da_ti.set_comp_param(32);
766 auto cast_coords = {folded_coord1, folded_coord2};
767 auto ae = makeExpr<Analyzer::ArrayExpr>(da_ti, cast_coords,
false, is_local_alloca);
770 return {makeExpr<Analyzer::UOper>(tia_ti,
false,
kCAST, ae)};
771 }
else if (rex_function->getName() ==
"ST_Centroid"sv) {
772 CHECK_EQ(
size_t(1), rex_function->size());
780 int legacy_transform_srid = 0;
787 CHECK_EQ(geoargs.size(), size_t(1));
793 if (try_to_compress) {
812 return {makeExpr<Analyzer::GeoOperator>(
814 rex_function->getName(),
815 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()},
816 legacy_transform_srid > 0 ? std::make_optional<int>(legacy_transform_srid)
818 }
else if (
func_resolve(rex_function->getName(),
"ST_ConvexHull"sv)) {
819 CHECK_EQ(
size_t(1), rex_function->size());
827 "ST_ConcaveHull"sv)) {
828 CHECK_EQ(
size_t(2), rex_function->size());
831 }
else if (
func_resolve(rex_function->getName(),
"ST_IsEmpty"sv,
"ST_IsValid"sv)) {
832 CHECK_EQ(
size_t(1), rex_function->size());
834 }
else if (
func_resolve(rex_function->getName(),
"ST_Equals"sv)) {
835 CHECK_EQ(
size_t(2), rex_function->size());
841 const auto rex_literal =
dynamic_cast<const RexLiteral*
>(rex_scalar);
843 if (use_geo_expressions) {
845 auto const translated_literal_type = translated_literal->get_type_info().get_type();
846 if (!
IS_STRING(translated_literal_type) && !
IS_GEO(translated_literal_type)) {
855 const auto constant_expr =
857 CHECK(constant_expr);
858 if (constant_expr->get_is_null()) {
862 const auto& datum = constant_expr->get_constval();
863 CHECK(datum.stringval);
864 const bool validate_with_geos_if_available =
false;
866 *datum.stringval, validate_with_geos_if_available);
867 CHECK(geospatial_base);
891 return {makeExpr<Analyzer::GeoConstant>(std::move(geospatial_base), ti)};
901 const bool with_bounds)
const {
904 const bool use_geo_projections = !(rex_function->
getName() ==
"ST_GeomFromText" ||
905 rex_function->
getName() ==
"ST_GeogFromText" ||
906 rex_function->
getName() ==
"ST_SetSRID");
912 use_geo_projections);
913 CHECK(!geoargs.empty());
914 if (std::dynamic_pointer_cast<const Analyzer::GeoExpr>(geoargs.front()) &&
915 !geoargs.front()->get_type_info().is_array()) {
916 if (rex_function->
getName() ==
"ST_Transform" &&
918 return makeExpr<Analyzer::GeoUOper>(
922 return geoargs.front();
924 bool allow_gdal_transform =
false;
925 if (rex_function->
getName() ==
"ST_Transform") {
928 if (rex_function0 &&
func_resolve(rex_function0->getName(),
934 "ST_ConvexHull"sv)) {
936 allow_gdal_transform =
true;
939 if (use_geo_projections && !allow_gdal_transform) {
940 throw std::runtime_error(
"Geospatial projection for function " +
942 " not yet supported in this context");
944 return makeExpr<Analyzer::GeoUOper>(
951 const bool with_bounds)
const {
954 " geo constructor requires enabled GEOS support");
957 if (rex_function->
getName() ==
"ST_Difference"sv) {
959 }
else if (rex_function->
getName() ==
"ST_Union"sv) {
961 }
else if (rex_function->
getName() ==
"ST_Buffer"sv) {
963 }
else if (rex_function->
getName() ==
"ST_ConcaveHull"sv) {
976 "ST_ConcaveHull"sv)) {
1002 " geo constructor requires arguments with matching srids");
1008 if (param_expr->get_type_info().get_type() !=
kDOUBLE) {
1009 param_expr = param_expr->add_cast(arg1_ti);
1011 geoargs1 = {param_expr};
1029 " requires its argument(s) to have a valid srid");
1038 return makeExpr<Analyzer::GeoBinOper>(op, arg_ti, arg0_ti, arg1_ti, geoargs0, geoargs1);
1044 const bool with_bounds)
const {
1047 " geo predicate requires enabled GEOS support");
1053 auto op = (rex_function->
getName() ==
"ST_IsEmpty"sv)
1056 return makeExpr<Analyzer::GeoUOper>(op, ti, arg_ti, geoargs);
1062 const bool with_bounds)
const {
1063 if (rex_function->
getName() !=
"ST_Equals"sv) {
1068 " geo predicate requires enabled GEOS support");
1078 return makeExpr<Analyzer::GeoBinOper>(op, ti, arg0_ti, arg1_ti, geoargs0, geoargs1);
1084 const bool with_bounds)
const {
1087 " geo constructor requires enabled GEOS support");
1120 " requires its argument(s) to have a valid srid");
1129 return makeExpr<Analyzer::GeoUOper>(op, arg_ti, arg0_ti, geoargs0);
1136 std::string specialized_geofunc{rex_function->
getName()};
1140 if (rex_function->
getName() ==
"ST_NRings"sv) {
1150 " expects a POLYGON or MULTIPOLYGON");
1152 CHECK_EQ(geoargs.size(), size_t(1));
1153 arg_ti = rex_function->
getType();
1154 return makeExpr<Analyzer::GeoOperator>(
1157 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()});
1158 }
else if (rex_function->
getName() ==
"ST_NumGeometries"sv) {
1169 CHECK_EQ(geoargs.size(), size_t(1));
1170 arg_ti = rex_function->
getType();
1171 return makeExpr<Analyzer::GeoOperator>(
1174 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()});
1175 }
else if (rex_function->
getName() ==
"ST_NPoints"sv) {
1183 CHECK_EQ(geoargs.size(), size_t(1));
1184 return makeExpr<Analyzer::GeoOperator>(
1187 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()});
1190 int legacy_transform_srid = 0;
1197 CHECK_EQ(geoargs.size(), size_t(1));
1204 arg_ti = geoargs.front()->get_type_info();
1208 " expects a POLYGON or MULTIPOLYGON");
1210 return makeExpr<Analyzer::GeoOperator>(
1213 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()},
1214 legacy_transform_srid > 0 ? std::make_optional<int>(legacy_transform_srid)
1227 " expects a POLYGON or MULTIPOLYGON");
1230 geoargs.erase(geoargs.begin(), geoargs.end() - 1);
1232 return makeExpr<Analyzer::FunctionOper>(
1233 rex_function->
getType(), specialized_geofunc, geoargs);
1246 CHECK_EQ(new_geoargs.size(), size_t(1));
1247 CHECK(new_geoargs.front());
1248 const auto& arg_expr_ti = new_geoargs.front()->get_type_info();
1249 if (arg_expr_ti.get_type() !=
kPOINT) {
1252 auto function_ti = rex_function->
getType();
1253 if (std::dynamic_pointer_cast<Analyzer::GeoOperator>(new_geoargs.front())) {
1256 if (std::dynamic_pointer_cast<Analyzer::GeoConstant>(new_geoargs.front())) {
1258 function_ti.set_notnull(
true);
1260 return makeExpr<Analyzer::GeoOperator>(
1263 std::vector<std::shared_ptr<Analyzer::Expr>>{new_geoargs.front()});
1268 bool with_bounds =
true;
1272 if (rex_function->
getName() ==
"ST_SRID"sv) {
1275 return makeExpr<Analyzer::Constant>(
kINT,
false, output_srid);
1279 rex_function->
getName(),
"ST_XMin"sv,
"ST_YMin"sv,
"ST_XMax"sv,
"ST_YMax"sv)) {
1283 geoargs.erase(geoargs.begin(), geoargs.end() - 1);
1288 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
1291 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1293 specialized_geofunc +=
"_Bounds"s;
1294 return makeExpr<Analyzer::FunctionOper>(
1295 rex_function->
getType(), specialized_geofunc, geoargs);
1301 auto discard_after_arg = 1;
1303 if (rex_function->
getName() ==
"ST_Length"sv) {
1306 " expects LINESTRING or MULTILINESTRING");
1309 auto ti0 = geoargs[0]->get_type_info();
1312 discard_after_arg = 2;
1319 " Geodesic is not supported for MULTILINESTRING");
1321 specialized_geofunc +=
"_Geodesic"s;
1325 geoargs.erase(geoargs.begin() + discard_after_arg, geoargs.end());
1329 Datum input_compression;
1331 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1334 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
1339 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1341 return makeExpr<Analyzer::FunctionOper>(
1342 rex_function->
getType(), specialized_geofunc, geoargs);
1347 auto function_name = rex_function->
getName();
1348 auto return_type = rex_function->
getType();
1350 if (function_name ==
"ST_IntersectsBox"sv) {
1354 auto extract_geo_bounds_from_input =
1355 [
this, &rex_function](
const size_t index) -> std::shared_ptr<Analyzer::Expr> {
1356 const auto rex_input =
1363 throw std::runtime_error(
1364 "ST_IntersectsBox is not supported for point arguments.");
1366 return exprs.back();
1369 throw std::runtime_error(
1370 "Only inputs are supported as arguments to ST_IntersectsBox for now.");
1373 std::vector<std::shared_ptr<Analyzer::Expr>> geo_args;
1374 geo_args.push_back(extract_geo_bounds_from_input(0));
1375 geo_args.push_back(extract_geo_bounds_from_input(1));
1377 return makeExpr<Analyzer::FunctionOper>(return_type, function_name, geo_args);
1380 if (function_name ==
"ST_Distance"sv || function_name ==
"ST_MaxDistance"sv) {
1382 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1383 int legacy_transform_srid = 0;
1384 for (
size_t i = 0; i < rex_function->
size(); i++) {
1396 CHECK(legacy_transform_srid == 0 ||
1400 args.insert(args.end(), geoargs.begin(), geoargs.end());
1402 return makeExpr<Analyzer::GeoOperator>(
1406 legacy_transform_srid > 0 ? std::make_optional<int>(legacy_transform_srid)
1410 bool swap_args =
false;
1411 bool with_bounds =
false;
1412 bool negate_result =
false;
1415 if (function_name ==
"ST_DWithin"sv) {
1417 function_name =
"ST_Distance";
1421 }
else if (function_name ==
"ST_Equals"sv) {
1424 function_name =
"ST_Distance";
1426 threshold_expr =
nullptr;
1429 compare_expr = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, d);
1430 }
else if (function_name ==
"ST_DFullyWithin"sv) {
1432 function_name =
"ST_MaxDistance";
1435 threshold_expr =
nullptr;
1436 }
else if (function_name ==
"ST_Distance"sv) {
1438 threshold_expr =
nullptr;
1439 }
else if (function_name ==
"ST_MaxDistance"sv) {
1442 threshold_expr =
nullptr;
1446 if (function_name ==
"ST_Within"sv) {
1447 function_name =
"ST_Contains";
1449 }
else if (function_name ==
"ST_Disjoint"sv) {
1450 function_name =
"ST_Intersects";
1451 negate_result =
true;
1454 function_name,
"ST_Contains"sv,
"ST_Intersects"sv,
"ST_Approx_Overlaps"sv)) {
1458 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
1472 try_to_compress_arg0);
1473 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1477 bool try_to_compress_arg1 =
1479 func_resolve(function_name,
"ST_Contains"sv,
"ST_Intersects"sv) &&
1489 try_to_compress_arg1);
1490 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1494 " accepts either two GEOGRAPHY or two GEOMETRY arguments");
1523 threshold_expr = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, tolerance);
1524 compare_expr = threshold_expr;
1528 " unable to calculate compression tolerance for arguments");
1534 " currently doesn't support this argument combination");
1537 auto can_use_compressed_coords = [](
const SQLTypeInfo& i0_ti,
1541 const bool i0_is_poly =
1543 const bool i1_is_point = i1_ti.get_type() ==
kPOINT;
1544 const bool i1_is_literal =
1546 i1_operands.front()) !=
nullptr;
1547 return (i0_is_poly && !i1_is_literal && i1_is_point &&
1551 i1_ti.get_input_srid() == i1_ti.get_output_srid());
1554 if (can_use_compressed_coords(arg0_ti, geoargs0, arg1_ti, geoargs1)) {
1556 function_name =
"ST_cContains";
1560 if (can_use_compressed_coords(arg0_ti, geoargs0, arg1_ti, geoargs1)) {
1562 function_name =
"ST_cIntersects";
1563 }
else if (can_use_compressed_coords(arg1_ti, geoargs1, arg0_ti, geoargs0)) {
1565 function_name =
"ST_cIntersects";
1567 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1568 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1569 auto tmp_ti = arg0_ti;
1575 std::string specialized_geofunc{function_name +
suffix(arg0_ti.
get_type()) +
1580 if (function_name ==
"ST_Distance"sv) {
1585 specialized_geofunc +=
"_Geodesic"s;
1588 " currently doesn't accept non-POINT geographies");
1590 }
else if (rex_function->
getName() ==
"ST_Contains"sv) {
1596 }
else if (function_name ==
"ST_Distance"sv && rex_function->
size() == 3) {
1599 specialized_geofunc +=
"_Squared"s;
1605 Datum input_compression0;
1607 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression0));
1610 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid0));
1614 Datum input_compression1;
1616 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression1));
1619 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid1));
1624 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1634 if (threshold_expr) {
1635 if (threshold_expr->get_type_info().get_type() !=
kDOUBLE) {
1637 threshold_expr = threshold_expr->add_cast(threshold_ti);
1639 threshold_expr =
fold_expr(threshold_expr.get());
1643 threshold_expr = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, d);
1645 geoargs.push_back(threshold_expr);
1649 makeExpr<Analyzer::FunctionOper>(return_type, specialized_geofunc, geoargs);
1650 if (negate_result) {
1665 if (distance_expr->get_type_info().get_type() !=
kDOUBLE) {
1666 distance_expr = distance_expr->add_cast(distance_ti);
1669 auto function_name = rex_function->
getName();
1670 if (function_name ==
"ST_DWithin"sv) {
1671 auto return_type = rex_function->
getType();
1672 bool swap_args =
false;
1673 bool with_bounds =
true;
1683 " cannot accept mixed GEOMETRY/GEOGRAPHY arguments");
1685 auto is_geodesic =
false;
1692 " in geodesic form can only accept POINT GEOGRAPHY arguments");
1710 Datum input_compression0;
1717 Datum input_compression1;
1726 std::string specialized_geofunc{function_name};
1727 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
1730 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1731 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1732 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression1));
1733 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid1));
1734 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression0));
1735 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid0));
1739 specialized_geofunc +=
"_Geodesic"s;
1741 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1742 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1743 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression0));
1744 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid0));
1745 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression1));
1746 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid1));
1748 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1750 geoargs.push_back(distance_expr);
1753 makeExpr<Analyzer::FunctionOper>(return_type, specialized_geofunc, geoargs);
1761 return makeExpr<Analyzer::BinOper>(
kBOOLEAN,
kLE,
kONE, geo_distance, distance_expr);
1766 if (rex_operator->
size() != size_t(2)) {
1772 if (func_oper && func_oper->getName() ==
"ST_Distance"sv) {
1775 if (distance_expr->get_type_info().get_type() !=
kDOUBLE) {
1776 distance_expr = distance_expr->add_cast(distance_ti);
1778 distance_expr =
fold_expr(distance_expr.get());
1779 return makeExpr<Analyzer::BinOper>(
1787 std::string specialized_geofunc{rex_function->
getName()};
1789 "convert_meters_to_pixel_width"sv,
1790 "convert_meters_to_pixel_height"sv)) {
1793 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1798 if (arg_ti.get_type() !=
kPOINT) {
1800 " expects a point for the second argument");
1803 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1806 Datum input_compression;
1808 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1809 if (arg_ti.get_input_srid() != 4326) {
1812 " currently only supports points of with SRID WGS84/EPSG:4326");
1815 input_srid.
intval = arg_ti.get_input_srid();
1816 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
1821 arg_ti.get_output_srid() != 900913 ? 900913 : arg_ti.get_output_srid();
1822 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1828 return makeExpr<Analyzer::FunctionOper>(
1829 rex_function->
getType(), specialized_geofunc,
args);
1830 }
else if (rex_function->
getName() ==
"is_point_in_view"sv) {
1833 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1837 if (arg_ti.get_type() !=
kPOINT) {
1839 " expects a point for the second argument");
1842 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1845 Datum input_compression;
1847 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1848 if (arg_ti.get_input_srid() != 4326) {
1851 " currently only supports points of with SRID WGS84/EPSG:4326");
1857 return makeExpr<Analyzer::FunctionOper>(
1858 rex_function->
getType(), specialized_geofunc,
args);
1859 }
else if (rex_function->
getName() ==
"is_point_size_in_view"sv) {
1862 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1866 if (arg_ti.get_type() !=
kPOINT) {
1868 " expects a point for the second argument");
1871 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1874 Datum input_compression;
1876 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1877 if (arg_ti.get_input_srid() != 4326) {
1880 " currently only supports points of with SRID WGS84/EPSG:4326");
1887 return makeExpr<Analyzer::FunctionOper>(
1888 rex_function->
getType(), specialized_geofunc,
args);
1898 auto translate_input =
1899 [&](
const RexScalar* operand) -> std::shared_ptr<Analyzer::Expr> {
1900 const auto input =
dynamic_cast<const RexInput*
>(operand);
1907 return exprs.front();
1909 return exprs.back();
1919 translate_input(rex_operator->
getOperand(1)),
1920 translate_input(rex_operator->
getOperand(0)));
HOST DEVICE SQLTypes get_subtype() const
void set_compression(EncodingType c)
std::vector< std::shared_ptr< Analyzer::Expr > > translateGeoColumn(const RexInput *, SQLTypeInfo &, const bool with_bounds, const bool expand_geo_col) const
std::shared_ptr< Analyzer::Expr > translateBinaryGeoPredicate(const RexFunctionOperator *, SQLTypeInfo &, const bool with_bounds) const
class for a per-database catalog. also includes metadata for the current database and the current use...
#define SPIMAP_GEO_PHYSICAL_INPUT(c, i)
std::shared_ptr< Analyzer::Expr > translateScalarRex(const RexScalar *rex) const
const SQLTypeInfo & getType() const
const RexScalar * getOperand(const size_t idx) const
int32_t get_compression_scheme(const SQLTypeInfo &ti)
HOST DEVICE void set_subtype(SQLTypes st)
std::shared_ptr< Analyzer::Expr > ExpressionPtr
bool g_enable_geo_ops_on_uncompressed_coords
HOST DEVICE SQLTypes get_type() const
std::shared_ptr< Analyzer::Expr > translateGeoProjection(const RexFunctionOperator *, SQLTypeInfo &, const bool with_bounds) const
#define TOLERANCE_GEOINT32
std::string suffix(SQLTypes type)
std::shared_ptr< Analyzer::Expr > translateInput(const RexInput *) const
std::shared_ptr< Analyzer::Expr > translateUnaryGeoFunction(const RexFunctionOperator *) const
std::vector< std::shared_ptr< Analyzer::Expr > > translateGeoLiteral(const RexLiteral *, SQLTypeInfo &, bool) const
void set_input_srid(int d)
std::vector< uint8_t > compress_coords(const std::vector< double > &coords, const SQLTypeInfo &ti)
static std::shared_ptr< Analyzer::Expr > translateLiteral(const RexLiteral *)
SQLOps getOperator() const
static bool getGeoColumns(const std::string &wkt_or_wkb_hex, SQLTypeInfo &ti, std::vector< double > &coords, std::vector< double > &bounds, std::vector< int > &ring_sizes, std::vector< int > &poly_rings, const bool validate_with_geos_if_available)
void set_output_srid(int s)
const std::unordered_map< const RelAlgNode *, int > input_to_nest_level_
void set_comp_param(int p)
std::shared_ptr< Analyzer::Expr > translateUnaryGeoPredicate(const RexFunctionOperator *, SQLTypeInfo &, const bool with_bounds) const
HOST DEVICE EncodingType get_compression() const
static std::unique_ptr< GeoBase > createGeoType(const std::string &wkt_or_wkb_hex, const bool validate_with_geos_if_available)
std::shared_ptr< Analyzer::Expr > translateUnaryGeoConstructor(const RexFunctionOperator *, SQLTypeInfo &, const bool with_bounds) const
bool is_projection(const RelAlgExecutionUnit &ra_exe_unit)
static RelRexToStringConfig defaults()
std::vector< std::shared_ptr< Analyzer::Expr > > translateGeoFunctionArg(const RexScalar *rex_scalar, SQLTypeInfo &arg_ti, const bool with_bounds, const bool expand_geo_col, const bool is_projection=false, const bool use_geo_expressions=false, const bool try_to_compress=false, const bool allow_gdal_transforms=false) const
HOST DEVICE int get_comp_param() const
HOST DEVICE int get_input_srid() const
std::shared_ptr< Analyzer::Expr > translateTernaryGeoFunction(const RexFunctionOperator *) const
std::shared_ptr< Analyzer::Expr > translateBinaryGeoFunction(const RexFunctionOperator *) const
std::vector< ExpressionPtr > ExpressionPtrVector
std::string toString(RelRexToStringConfig config=RelRexToStringConfig::defaults()) const override
std::shared_ptr< Analyzer::Expr > translateFunctionWithGeoArg(const RexFunctionOperator *) const
const std::string & getName() const
std::shared_ptr< Analyzer::Expr > translateGeoComparison(const RexOperator *) const
int get_physical_coord_cols() const
std::shared_ptr< Analyzer::Expr > translateBinaryGeoConstructor(const RexFunctionOperator *, SQLTypeInfo &, const bool with_bounds) const
SQLTypes get_ti_from_geo(const Geospatial::GeoBase *geo)
std::shared_ptr< Analyzer::Expr > fold_expr(const Analyzer::Expr *expr)
std::shared_ptr< Analyzer::Expr > translateGeoBoundingBoxIntersectOper(const RexOperator *) const
HOST DEVICE int get_output_srid() const
virtual GeoType getType() const =0
HOST DEVICE void set_type(SQLTypes t)