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 !shared::is_any<kSMALLINT, kTINYINT, kINT>(e->get_type_info().get_type())) {
554 " expecting integer index as second argument");
558 arg0.front()->get_type_info();
560 oper_ti.set_notnull(
false);
564 return {makeExpr<Analyzer::GeoOperator>(oper_ti, rex_function->getName(), arg0)};
566 }
else if (rex_function->getName() ==
"ST_StartPoint"sv ||
567 rex_function->getName() ==
"ST_EndPoint"sv) {
568 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
569 CHECK_EQ(
size_t(1), rex_function->size());
576 CHECK_EQ(arg_exprs.size(), size_t(1));
577 CHECK(arg_exprs.front());
578 const auto arg_expr_ti = arg_exprs.front()->get_type_info();
581 " expected LINESTRING argument. Received " +
582 arg_expr_ti.toString());
584 args.push_back(arg_exprs.front());
586 auto oper_ti = args.back()->get_type_info();
591 return {makeExpr<Analyzer::GeoOperator>(oper_ti, rex_function->getName(),
args)};
592 }
else if (rex_function->getName() ==
"ST_SRID"sv) {
593 CHECK_EQ(
size_t(1), rex_function->size());
594 const auto rex_scalar0 =
595 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
598 ": expects scalar as first argument");
606 }
else if (rex_function->getName() ==
"ST_SetSRID"sv) {
607 CHECK_EQ(
size_t(2), rex_function->size());
608 const auto rex_literal =
609 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
612 ": second argument is expected to be a literal");
616 if (!ce || !e->get_type_info().is_integer()) {
620 if (e->get_type_info().get_type() ==
kSMALLINT) {
621 srid =
static_cast<int32_t
>(ce->get_constval().smallintval);
622 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
623 srid =
static_cast<int32_t
>(ce->get_constval().tinyintval);
624 }
else if (e->get_type_info().get_type() ==
kINT) {
625 srid =
static_cast<int32_t
>(ce->get_constval().intval);
630 const auto rex_scalar0 =
631 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
634 ": expects scalar as first argument");
644 (try_to_compress && (srid == 4326)));
646 CHECK(!arg0.empty() && arg0.front());
652 if (
auto geo_expr = std::dynamic_pointer_cast<Analyzer::GeoExpr>(arg0.front())) {
654 auto ti = geo_expr->get_type_info();
655 ti.set_input_srid(srid);
656 ti.set_output_srid(srid);
657 return {geo_expr->add_cast(ti)};
660 }
else if (rex_function->getName() ==
"CastToGeography"sv) {
661 CHECK_EQ(
size_t(1), rex_function->size());
662 const auto rex_scalar0 =
663 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
666 ": expects scalar as first argument");
673 use_geo_expressions);
674 CHECK(!arg0.empty());
675 if (
auto geo_expr = std::dynamic_pointer_cast<Analyzer::GeoExpr>(arg0.front())) {
676 auto arg_ti = geo_expr->get_type_info();
678 return {geo_expr->add_cast(arg_ti)};
680 if (use_geo_expressions) {
681 arg_ti = arg0.front()->get_type_info();
683 arg0.front()->set_type_info(arg_ti);
690 " expects geometry with SRID=4326");
694 }
else if (rex_function->getName() ==
"ST_Point"sv) {
695 CHECK_EQ(
size_t(2), rex_function->size());
705 auto cast_coord1 = coord1->add_cast(d_ti);
706 auto cast_coord2 = coord2->add_cast(d_ti);
708 auto folded_coord1 =
fold_expr(cast_coord1.get());
709 auto folded_coord2 =
fold_expr(cast_coord2.get());
712 if (const_coord1 && const_coord2 && !use_geo_expressions) {
713 CHECK(const_coord1->get_type_info().get_type() ==
kDOUBLE);
714 CHECK(const_coord2->get_type_info().get_type() ==
kDOUBLE);
715 std::string wkt =
"POINT(" +
718 RexLiteral rex_literal{wkt,
kTEXT,
kNULLT, 0, 0, 0, 0};
724 if (!is_local_alloca || use_geo_expressions) {
725 if (try_to_compress) {
729 return {makeExpr<Analyzer::GeoOperator>(
731 rex_function->getName(),
732 std::vector<std::shared_ptr<Analyzer::Expr>>{folded_coord1, folded_coord2})};
738 if (try_to_compress) {
740 da_ti.set_subtype(
kINT);
742 da_ti.set_input_srid(4326);
743 da_ti.set_output_srid(4326);
745 da_ti.set_comp_param(32);
752 auto cast_coords = {folded_coord1, folded_coord2};
753 auto ae = makeExpr<Analyzer::ArrayExpr>(da_ti, cast_coords,
false, is_local_alloca);
756 return {makeExpr<Analyzer::UOper>(tia_ti,
false,
kCAST, ae)};
757 }
else if (rex_function->getName() ==
"ST_Centroid"sv) {
758 CHECK_EQ(
size_t(1), rex_function->size());
766 int legacy_transform_srid = 0;
773 CHECK_EQ(geoargs.size(), size_t(1));
779 if (try_to_compress) {
798 return {makeExpr<Analyzer::GeoOperator>(
800 rex_function->getName(),
801 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()},
802 legacy_transform_srid > 0 ? std::make_optional<int>(legacy_transform_srid)
804 }
else if (
func_resolve(rex_function->getName(),
"ST_ConvexHull"sv)) {
805 CHECK_EQ(
size_t(1), rex_function->size());
813 "ST_ConcaveHull"sv)) {
814 CHECK_EQ(
size_t(2), rex_function->size());
817 }
else if (
func_resolve(rex_function->getName(),
"ST_IsEmpty"sv,
"ST_IsValid"sv)) {
818 CHECK_EQ(
size_t(1), rex_function->size());
820 }
else if (
func_resolve(rex_function->getName(),
"ST_Equals"sv)) {
821 CHECK_EQ(
size_t(2), rex_function->size());
827 const auto rex_literal =
dynamic_cast<const RexLiteral*
>(rex_scalar);
829 if (use_geo_expressions) {
831 auto const translated_literal_type = translated_literal->get_type_info().get_type();
832 if (!
IS_STRING(translated_literal_type) && !
IS_GEO(translated_literal_type)) {
841 const auto constant_expr =
843 CHECK(constant_expr);
844 if (constant_expr->get_is_null()) {
848 const auto& datum = constant_expr->get_constval();
849 CHECK(datum.stringval);
850 const bool validate_with_geos_if_available =
false;
852 *datum.stringval, validate_with_geos_if_available);
853 CHECK(geospatial_base);
877 return {makeExpr<Analyzer::GeoConstant>(std::move(geospatial_base), ti)};
887 const bool with_bounds)
const {
890 const bool use_geo_projections = !(rex_function->
getName() ==
"ST_GeomFromText" ||
891 rex_function->
getName() ==
"ST_GeogFromText" ||
892 rex_function->
getName() ==
"ST_SetSRID");
898 use_geo_projections);
899 CHECK(!geoargs.empty());
900 if (std::dynamic_pointer_cast<const Analyzer::GeoExpr>(geoargs.front()) &&
901 !geoargs.front()->get_type_info().is_array()) {
902 if (rex_function->
getName() ==
"ST_Transform" &&
904 return makeExpr<Analyzer::GeoUOper>(
908 return geoargs.front();
910 bool allow_gdal_transform =
false;
911 if (rex_function->
getName() ==
"ST_Transform") {
914 if (rex_function0 &&
func_resolve(rex_function0->getName(),
920 "ST_ConvexHull"sv)) {
922 allow_gdal_transform =
true;
925 if (use_geo_projections && !allow_gdal_transform) {
926 throw std::runtime_error(
"Geospatial projection for function " +
928 " not yet supported in this context");
930 return makeExpr<Analyzer::GeoUOper>(
937 const bool with_bounds)
const {
940 " geo constructor requires enabled GEOS support");
943 if (rex_function->
getName() ==
"ST_Difference"sv) {
945 }
else if (rex_function->
getName() ==
"ST_Union"sv) {
947 }
else if (rex_function->
getName() ==
"ST_Buffer"sv) {
949 }
else if (rex_function->
getName() ==
"ST_ConcaveHull"sv) {
962 "ST_ConcaveHull"sv)) {
988 " geo constructor requires arguments with matching srids");
994 if (param_expr->get_type_info().get_type() !=
kDOUBLE) {
995 param_expr = param_expr->add_cast(arg1_ti);
997 geoargs1 = {param_expr};
1015 " requires its argument(s) to have a valid srid");
1024 return makeExpr<Analyzer::GeoBinOper>(op, arg_ti, arg0_ti, arg1_ti, geoargs0, geoargs1);
1030 const bool with_bounds)
const {
1033 " geo predicate requires enabled GEOS support");
1039 auto op = (rex_function->
getName() ==
"ST_IsEmpty"sv)
1042 return makeExpr<Analyzer::GeoUOper>(op, ti, arg_ti, geoargs);
1048 const bool with_bounds)
const {
1049 if (rex_function->
getName() !=
"ST_Equals"sv) {
1054 " geo predicate requires enabled GEOS support");
1064 return makeExpr<Analyzer::GeoBinOper>(op, ti, arg0_ti, arg1_ti, geoargs0, geoargs1);
1070 const bool with_bounds)
const {
1073 " geo constructor requires enabled GEOS support");
1106 " requires its argument(s) to have a valid srid");
1115 return makeExpr<Analyzer::GeoUOper>(op, arg_ti, arg0_ti, geoargs0);
1122 std::string specialized_geofunc{rex_function->
getName()};
1126 if (rex_function->
getName() ==
"ST_NRings"sv) {
1136 " expects a POLYGON or MULTIPOLYGON");
1138 CHECK_EQ(geoargs.size(), size_t(1));
1139 arg_ti = rex_function->
getType();
1140 return makeExpr<Analyzer::GeoOperator>(
1143 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()});
1144 }
else if (rex_function->
getName() ==
"ST_NumGeometries"sv) {
1155 CHECK_EQ(geoargs.size(), size_t(1));
1156 arg_ti = rex_function->
getType();
1157 return makeExpr<Analyzer::GeoOperator>(
1160 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()});
1161 }
else if (rex_function->
getName() ==
"ST_NPoints"sv) {
1169 CHECK_EQ(geoargs.size(), size_t(1));
1170 auto expr_ti = rex_function->
getType();
1172 return makeExpr<Analyzer::GeoOperator>(
1175 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()});
1178 int legacy_transform_srid = 0;
1185 CHECK_EQ(geoargs.size(), size_t(1));
1192 arg_ti = geoargs.front()->get_type_info();
1196 " expects a POLYGON or MULTIPOLYGON");
1198 return makeExpr<Analyzer::GeoOperator>(
1201 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()},
1202 legacy_transform_srid > 0 ? std::make_optional<int>(legacy_transform_srid)
1215 " expects a POLYGON or MULTIPOLYGON");
1218 geoargs.erase(geoargs.begin(), geoargs.end() - 1);
1220 return makeExpr<Analyzer::FunctionOper>(
1221 rex_function->
getType(), specialized_geofunc, geoargs);
1234 CHECK_EQ(new_geoargs.size(), size_t(1));
1235 CHECK(new_geoargs.front());
1236 const auto& arg_expr_ti = new_geoargs.front()->get_type_info();
1237 if (arg_expr_ti.get_type() !=
kPOINT) {
1240 auto function_ti = rex_function->
getType();
1241 if (std::dynamic_pointer_cast<Analyzer::GeoOperator>(new_geoargs.front())) {
1244 if (std::dynamic_pointer_cast<Analyzer::GeoConstant>(new_geoargs.front())) {
1246 function_ti.set_notnull(
true);
1248 return makeExpr<Analyzer::GeoOperator>(
1251 std::vector<std::shared_ptr<Analyzer::Expr>>{new_geoargs.front()});
1256 bool with_bounds =
true;
1260 if (rex_function->
getName() ==
"ST_SRID"sv) {
1263 return makeExpr<Analyzer::Constant>(
kINT,
false, output_srid);
1267 rex_function->
getName(),
"ST_XMin"sv,
"ST_YMin"sv,
"ST_XMax"sv,
"ST_YMax"sv)) {
1271 geoargs.erase(geoargs.begin(), geoargs.end() - 1);
1276 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
1279 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1281 specialized_geofunc +=
"_Bounds"s;
1282 return makeExpr<Analyzer::FunctionOper>(
1283 rex_function->
getType(), specialized_geofunc, geoargs);
1289 auto discard_after_arg = 1;
1291 if (rex_function->
getName() ==
"ST_Length"sv) {
1294 " expects LINESTRING or MULTILINESTRING");
1297 auto ti0 = geoargs[0]->get_type_info();
1300 discard_after_arg = 2;
1307 " Geodesic is not supported for MULTILINESTRING");
1309 specialized_geofunc +=
"_Geodesic"s;
1313 geoargs.erase(geoargs.begin() + discard_after_arg, geoargs.end());
1317 Datum input_compression;
1319 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1322 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
1327 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1329 return makeExpr<Analyzer::FunctionOper>(
1330 rex_function->
getType(), specialized_geofunc, geoargs);
1335 auto function_name = rex_function->
getName();
1336 auto return_type = rex_function->
getType();
1338 if (function_name ==
"ST_IntersectsBox"sv) {
1342 auto extract_geo_bounds_from_input =
1343 [
this, &rex_function](
const size_t index) -> std::shared_ptr<Analyzer::Expr> {
1344 const auto rex_input =
1351 throw std::runtime_error(
1352 "ST_IntersectsBox is not supported for point arguments.");
1354 return exprs.back();
1357 throw std::runtime_error(
1358 "Only inputs are supported as arguments to ST_IntersectsBox for now.");
1361 std::vector<std::shared_ptr<Analyzer::Expr>> geo_args;
1362 geo_args.push_back(extract_geo_bounds_from_input(0));
1363 geo_args.push_back(extract_geo_bounds_from_input(1));
1365 return makeExpr<Analyzer::FunctionOper>(return_type, function_name, geo_args);
1368 if (function_name ==
"ST_Distance"sv || function_name ==
"ST_MaxDistance"sv) {
1370 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1371 int legacy_transform_srid = 0;
1372 for (
size_t i = 0; i < rex_function->
size(); i++) {
1384 CHECK(legacy_transform_srid == 0 ||
1388 args.insert(args.end(), geoargs.begin(), geoargs.end());
1390 return makeExpr<Analyzer::GeoOperator>(
1394 legacy_transform_srid > 0 ? std::make_optional<int>(legacy_transform_srid)
1398 bool swap_args =
false;
1399 bool with_bounds =
false;
1400 bool negate_result =
false;
1403 if (function_name ==
"ST_DWithin"sv) {
1405 function_name =
"ST_Distance";
1409 }
else if (function_name ==
"ST_Equals"sv) {
1412 function_name =
"ST_Distance";
1414 threshold_expr =
nullptr;
1417 compare_expr = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, d);
1418 }
else if (function_name ==
"ST_DFullyWithin"sv) {
1420 function_name =
"ST_MaxDistance";
1423 threshold_expr =
nullptr;
1424 }
else if (function_name ==
"ST_Distance"sv) {
1426 threshold_expr =
nullptr;
1427 }
else if (function_name ==
"ST_MaxDistance"sv) {
1430 threshold_expr =
nullptr;
1434 if (function_name ==
"ST_Within"sv) {
1435 function_name =
"ST_Contains";
1437 }
else if (function_name ==
"ST_Disjoint"sv) {
1438 function_name =
"ST_Intersects";
1439 negate_result =
true;
1442 function_name,
"ST_Contains"sv,
"ST_Intersects"sv,
"ST_Approx_Overlaps"sv)) {
1446 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
1460 try_to_compress_arg0);
1461 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1465 bool try_to_compress_arg1 =
1467 func_resolve(function_name,
"ST_Contains"sv,
"ST_Intersects"sv) &&
1477 try_to_compress_arg1);
1478 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1482 " accepts either two GEOGRAPHY or two GEOMETRY arguments");
1511 threshold_expr = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, tolerance);
1512 compare_expr = threshold_expr;
1516 " unable to calculate compression tolerance for arguments");
1522 " currently doesn't support this argument combination");
1525 auto can_use_compressed_coords = [](
const SQLTypeInfo& i0_ti,
1529 const bool i0_is_poly =
1531 const bool i1_is_point = i1_ti.get_type() ==
kPOINT;
1532 const bool i1_is_literal =
1534 i1_operands.front()) !=
nullptr;
1535 return (i0_is_poly && !i1_is_literal && i1_is_point &&
1539 i1_ti.get_input_srid() == i1_ti.get_output_srid());
1542 if (can_use_compressed_coords(arg0_ti, geoargs0, arg1_ti, geoargs1)) {
1544 function_name =
"ST_cContains";
1548 if (can_use_compressed_coords(arg0_ti, geoargs0, arg1_ti, geoargs1)) {
1550 function_name =
"ST_cIntersects";
1551 }
else if (can_use_compressed_coords(arg1_ti, geoargs1, arg0_ti, geoargs0)) {
1553 function_name =
"ST_cIntersects";
1555 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1556 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1557 auto tmp_ti = arg0_ti;
1563 std::string specialized_geofunc{function_name +
suffix(arg0_ti.
get_type()) +
1568 if (function_name ==
"ST_Distance"sv) {
1573 specialized_geofunc +=
"_Geodesic"s;
1576 " currently doesn't accept non-POINT geographies");
1578 }
else if (rex_function->
getName() ==
"ST_Contains"sv) {
1584 }
else if (function_name ==
"ST_Distance"sv && rex_function->
size() == 3) {
1587 specialized_geofunc +=
"_Squared"s;
1593 Datum input_compression0;
1595 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression0));
1598 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid0));
1602 Datum input_compression1;
1604 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression1));
1607 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid1));
1612 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1622 if (threshold_expr) {
1623 if (threshold_expr->get_type_info().get_type() !=
kDOUBLE) {
1625 threshold_expr = threshold_expr->add_cast(threshold_ti);
1627 threshold_expr =
fold_expr(threshold_expr.get());
1631 threshold_expr = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, d);
1633 geoargs.push_back(threshold_expr);
1637 makeExpr<Analyzer::FunctionOper>(return_type, specialized_geofunc, geoargs);
1638 if (negate_result) {
1653 if (distance_expr->get_type_info().get_type() !=
kDOUBLE) {
1654 distance_expr = distance_expr->add_cast(distance_ti);
1657 auto function_name = rex_function->
getName();
1658 if (function_name ==
"ST_DWithin"sv) {
1659 auto return_type = rex_function->
getType();
1660 bool swap_args =
false;
1661 bool with_bounds =
true;
1671 " cannot accept mixed GEOMETRY/GEOGRAPHY arguments");
1673 auto is_geodesic =
false;
1680 " in geodesic form can only accept POINT GEOGRAPHY arguments");
1698 Datum input_compression0;
1705 Datum input_compression1;
1714 std::string specialized_geofunc{function_name};
1715 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
1718 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1719 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1720 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression1));
1721 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid1));
1722 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression0));
1723 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid0));
1727 specialized_geofunc +=
"_Geodesic"s;
1729 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1730 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1731 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression0));
1732 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid0));
1733 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression1));
1734 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid1));
1736 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1738 geoargs.push_back(distance_expr);
1741 makeExpr<Analyzer::FunctionOper>(return_type, specialized_geofunc, geoargs);
1749 return makeExpr<Analyzer::BinOper>(
kBOOLEAN,
kLE,
kONE, geo_distance, distance_expr);
1754 if (rex_operator->
size() != size_t(2)) {
1760 if (func_oper && func_oper->getName() ==
"ST_Distance"sv) {
1763 if (distance_expr->get_type_info().get_type() !=
kDOUBLE) {
1764 distance_expr = distance_expr->add_cast(distance_ti);
1766 distance_expr =
fold_expr(distance_expr.get());
1767 return makeExpr<Analyzer::BinOper>(
1775 std::string specialized_geofunc{rex_function->
getName()};
1777 "convert_meters_to_pixel_width"sv,
1778 "convert_meters_to_pixel_height"sv)) {
1781 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1786 if (arg_ti.get_type() !=
kPOINT) {
1788 " expects a point for the second argument");
1791 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1794 Datum input_compression;
1796 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1797 if (arg_ti.get_input_srid() != 4326) {
1800 " currently only supports points of with SRID WGS84/EPSG:4326");
1803 input_srid.
intval = arg_ti.get_input_srid();
1804 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
1809 arg_ti.get_output_srid() != 900913 ? 900913 : arg_ti.get_output_srid();
1810 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1816 return makeExpr<Analyzer::FunctionOper>(
1817 rex_function->
getType(), specialized_geofunc,
args);
1818 }
else if (rex_function->
getName() ==
"is_point_in_view"sv) {
1821 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1825 if (arg_ti.get_type() !=
kPOINT) {
1827 " expects a point for the second argument");
1830 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1833 Datum input_compression;
1835 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1836 if (arg_ti.get_input_srid() != 4326) {
1839 " currently only supports points of with SRID WGS84/EPSG:4326");
1845 return makeExpr<Analyzer::FunctionOper>(
1846 rex_function->
getType(), specialized_geofunc,
args);
1847 }
else if (rex_function->
getName() ==
"is_point_size_in_view"sv) {
1850 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1854 if (arg_ti.get_type() !=
kPOINT) {
1856 " expects a point for the second argument");
1859 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1862 Datum input_compression;
1864 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1865 if (arg_ti.get_input_srid() != 4326) {
1868 " currently only supports points of with SRID WGS84/EPSG:4326");
1875 return makeExpr<Analyzer::FunctionOper>(
1876 rex_function->
getType(), specialized_geofunc,
args);
1886 auto translate_input =
1887 [&](
const RexScalar* operand) -> std::shared_ptr<Analyzer::Expr> {
1888 const auto input =
dynamic_cast<const RexInput*
>(operand);
1895 return exprs.front();
1897 return exprs.back();
1907 translate_input(rex_operator->
getOperand(1)),
1908 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
HOST DEVICE bool get_notnull() 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)