31 const bool with_bounds,
32 const bool with_render_group,
33 const bool expand_geo_col)
const {
34 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
38 const int rte_idx = it_rte_idx->second;
39 const auto& in_metainfo = source->getOutputMetainfo();
45 const auto scan_source =
dynamic_cast<const RelScan*
>(source);
49 CHECK(in_metainfo.empty());
51 const auto td = scan_source->getTableDescriptor();
52 table_id = td->tableId;
54 catalog = &scan_source->getCatalog();
55 db_id = catalog->getDatabaseId();
57 catalog->getMetadataForColumnBySpi(table_id, rex_input->
getIndex() + 1);
60 column_id = gcd->columnId;
65 table_id = -source->getId();
67 if (with_bounds || with_render_group) {
69 "Geospatial columns not yet supported in intermediate results.");
72 CHECK(!in_metainfo.empty());
75 CHECK_LT(static_cast<size_t>(column_id), in_metainfo.size());
76 ti = in_metainfo[column_id].get_type_info();
77 if (expand_geo_col && ti.is_geometry()) {
79 "Geospatial columns not yet supported in this temporary table context.");
85 "Geospatial expression and operator require geospatial column as their input "
95 const auto pcd = catalog->getMetadataForColumnBySpi(
97 auto pcol_ti = pcd->columnType;
98 args.push_back(std::make_shared<Analyzer::ColumnVar>(
102 args.push_back(std::make_shared<Analyzer::ColumnVar>(
107 const auto bounds_cd = catalog->getMetadataForColumnBySpi(
111 auto bounds_ti = bounds_cd->columnType;
112 args.push_back(std::make_shared<Analyzer::ColumnVar>(
117 const auto render_group_cd = catalog->getMetadataForColumnBySpi(
121 auto render_group_ti = render_group_cd->columnType;
122 args.push_back(std::make_shared<Analyzer::ColumnVar>(
131 const RexLiteral* rex_literal,
133 bool with_bounds)
const {
135 if (rex_literal->getType() !=
kTEXT) {
136 throw std::runtime_error(
"Geo literals must be strings");
143 std::vector<double> coords;
144 std::vector<double> bounds;
145 std::vector<int> ring_sizes;
146 std::vector<int> poly_rings;
149 *wkt->get_constval().stringval, ti, coords, bounds, ring_sizes, poly_rings)) {
161 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
164 std::list<std::shared_ptr<Analyzer::Expr>> compressed_coords_exprs;
165 for (
auto cc : compressed_coords) {
168 auto e = makeExpr<Analyzer::Constant>(
kTINYINT,
false, d);
169 compressed_coords_exprs.push_back(e);
173 arr_ti.
set_size(compressed_coords.size() *
sizeof(int8_t));
176 args.push_back(makeExpr<Analyzer::Constant>(arr_ti,
false, compressed_coords_exprs));
181 std::list<std::shared_ptr<Analyzer::Expr>> ring_size_exprs;
182 for (
auto c : ring_sizes) {
185 auto e = makeExpr<Analyzer::Constant>(
kINT,
false, d);
186 ring_size_exprs.push_back(e);
190 arr_ti.
set_size(ring_sizes.size() *
sizeof(int32_t));
191 args.push_back(makeExpr<Analyzer::Constant>(arr_ti,
false, ring_size_exprs));
195 std::list<std::shared_ptr<Analyzer::Expr>> poly_rings_exprs;
196 for (
auto c : poly_rings) {
199 auto e = makeExpr<Analyzer::Constant>(
kINT,
false, d);
200 poly_rings_exprs.push_back(e);
204 arr_ti.
set_size(poly_rings.size() *
sizeof(int32_t));
205 args.push_back(makeExpr<Analyzer::Constant>(arr_ti,
false, poly_rings_exprs));
211 std::list<std::shared_ptr<Analyzer::Expr>> bounds_exprs;
212 for (
auto b : bounds) {
215 auto e = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, d);
216 bounds_exprs.push_back(e);
220 arr_ti.
set_size(bounds.size() *
sizeof(double));
221 args.push_back(makeExpr<Analyzer::Constant>(arr_ti,
false, bounds_exprs));
231 return std::string(
"_Point");
234 return std::string(
"_MultiPoint");
237 return std::string(
"_LineString");
240 return std::string(
"_MultiLineString");
243 return std::string(
"_Polygon");
246 return std::string(
"_MultiPolygon");
283 const bool with_bounds,
284 const bool with_render_group,
285 const bool expand_geo_col,
287 const bool use_geo_expressions,
288 const bool try_to_compress,
289 const bool allow_gdal_transforms)
const {
290 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
292 const auto rex_input =
dynamic_cast<const RexInput*
>(rex_scalar);
296 if (!column || !column->get_type_info().is_geometry()) {
299 if (use_geo_expressions) {
300 arg_ti = column->get_type_info();
301 return {makeExpr<Analyzer::GeoColumnVar>(column, with_bounds, with_render_group)};
304 rex_input, arg_ti, with_bounds, with_render_group, expand_geo_col);
308 if (rex_function->getName() ==
"ST_Transform"sv) {
309 CHECK_EQ(
size_t(2), rex_function->size());
310 const auto rex_scalar0 =
311 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
313 throw QueryNotSupported(rex_function->getName() +
": unexpected first argument");
316 const auto rex_literal =
317 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
320 ": second argument is expected to be a literal");
324 if (!ce || !e->get_type_info().is_integer()) {
328 if (e->get_type_info().get_type() ==
kSMALLINT) {
329 srid =
static_cast<int32_t
>(ce->get_constval().smallintval);
330 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
331 srid =
static_cast<int32_t
>(ce->get_constval().tinyintval);
332 }
else if (e->get_type_info().get_type() ==
kINT) {
333 srid =
static_cast<int32_t
>(ce->get_constval().intval);
337 bool allow_result_gdal_transform =
false;
339 if (rex_function0 &&
func_resolve(rex_function0->getName(),
345 "ST_ConvexHull"sv)) {
356 if (!allow_gdal_transforms && !allow_result_gdal_transform) {
357 if (srid != 900913 && ((use_geo_expressions || is_projection) && srid != 4326 &&
364 bool arg0_use_geo_expressions = is_projection ?
true : use_geo_expressions;
365 if (allow_gdal_transforms) {
366 arg0_use_geo_expressions =
false;
374 arg0_use_geo_expressions);
376 if (use_geo_expressions) {
378 auto arg0_ti = arg0.front()->get_type_info();
379 arg0_ti.set_output_srid(srid);
380 if (arg0_ti.get_type() ==
kPOINT) {
383 const auto input_srid = arg0_ti.get_input_srid();
384 arg0_ti.set_input_srid(srid);
387 arg0_ti.set_comp_param(0);
392 return {makeExpr<Analyzer::GeoTransformOperator>(
393 arg0_ti, rex_function->getName(), arg0, input_srid, srid)};
395 if (
auto geo_constant =
396 std::dynamic_pointer_cast<Analyzer::GeoConstant>(arg0.front())) {
398 auto cast_geo_constant = geo_constant->add_cast(arg0_ti);
400 arg_ti = cast_geo_constant->get_type_info();
401 return {cast_geo_constant};
402 }
else if (
auto col_var =
403 std::dynamic_pointer_cast<Analyzer::ColumnVar>(arg0.front())) {
404 const auto& col_ti = col_var->get_type_info();
405 CHECK(col_ti.is_geometry());
406 if (col_ti.get_type() !=
kPOINT) {
411 if (!allow_gdal_transforms && !allow_result_gdal_transform) {
412 throw std::runtime_error(
413 "Transform on non-POINT geospatial types not yet supported in this "
421 if (!allow_gdal_transforms && !allow_result_gdal_transform) {
424 ": unsupported input SRID " +
429 if (allow_result_gdal_transform) {
439 ": unexpected input SRID, unable to transform");
443 rex_function->getName(),
"ST_GeomFromText"sv,
"ST_GeogFromText"sv)) {
444 CHECK(rex_function->size() == size_t(1) || rex_function->size() == size_t(2));
445 if (use_geo_expressions) {
447 if (rex_function->size() == 2) {
449 const auto rex_literal =
450 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
453 ": second argument is expected to be a literal");
457 if (!ce || !e->get_type_info().is_integer()) {
460 if (e->get_type_info().get_type() ==
kSMALLINT) {
461 srid =
static_cast<int32_t
>(ce->get_constval().smallintval);
462 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
463 srid =
static_cast<int32_t
>(ce->get_constval().tinyintval);
464 }
else if (e->get_type_info().get_type() ==
kINT) {
465 srid =
static_cast<int32_t
>(ce->get_constval().intval);
469 if (srid != 0 && srid != 4326 && srid != 900913) {
477 if (rex_function->getName() ==
"ST_GeogFromText"sv) {
489 use_geo_expressions);
490 CHECK_GE(func_args.size(), size_t(1));
496 if (rex_function->size() == 2) {
497 const auto rex_literal =
498 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
501 ": second argument is expected to be a literal");
505 if (!ce || !e->get_type_info().is_integer()) {
508 if (e->get_type_info().get_type() ==
kSMALLINT) {
509 srid =
static_cast<int32_t
>(ce->get_constval().smallintval);
510 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
511 srid =
static_cast<int32_t
>(ce->get_constval().tinyintval);
512 }
else if (e->get_type_info().get_type() ==
kINT) {
513 srid =
static_cast<int32_t
>(ce->get_constval().intval);
517 if (srid != 0 && srid != 4326 && srid != 900913) {
525 const auto rex_literal =
526 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(0));
529 " expects a string literal as first argument");
535 }
else if (rex_function->getName() ==
"ST_PointN"sv) {
537 const auto rex_scalar0 =
538 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
541 ": expects scalar as first argument");
552 if (arg0.front()->get_type_info().get_type() !=
kLINESTRING) {
554 " expects LINESTRING as first argument");
556 const auto rex_literal =
557 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
560 ": second argument is expected to be a literal");
564 if (!ce || !e->get_type_info().is_integer()) {
566 ": expecting integer index as second argument");
569 if (e->get_type_info().get_type() ==
kSMALLINT) {
570 index =
static_cast<int32_t
>(ce->get_constval().smallintval);
571 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
572 index =
static_cast<int32_t
>(ce->get_constval().tinyintval);
573 }
else if (e->get_type_info().get_type() ==
kINT) {
574 index =
static_cast<int32_t
>(ce->get_constval().intval);
584 arg0.front()->get_type_info();
586 oper_ti.set_notnull(
false);
590 return {makeExpr<Analyzer::GeoOperator>(oper_ti, rex_function->getName(), arg0)};
592 }
else if (rex_function->getName() ==
"ST_StartPoint"sv ||
593 rex_function->getName() ==
"ST_EndPoint"sv) {
594 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
595 CHECK_EQ(
size_t(1), rex_function->size());
603 CHECK_EQ(arg_exprs.size(), size_t(1));
604 CHECK(arg_exprs.front());
605 const auto arg_expr_ti = arg_exprs.front()->get_type_info();
608 " expected LINESTRING argument. Received " +
609 arg_expr_ti.toString());
611 args.push_back(arg_exprs.front());
613 auto oper_ti = args.back()->get_type_info();
618 return {makeExpr<Analyzer::GeoOperator>(oper_ti, rex_function->getName(),
args)};
619 }
else if (rex_function->getName() ==
"ST_SRID"sv) {
620 CHECK_EQ(
size_t(1), rex_function->size());
621 const auto rex_scalar0 =
622 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
625 ": expects scalar as first argument");
628 rex_scalar0, arg_ti, with_bounds, with_render_group, expand_geo_col);
633 }
else if (rex_function->getName() ==
"ST_SetSRID"sv) {
634 CHECK_EQ(
size_t(2), rex_function->size());
635 const auto rex_literal =
636 dynamic_cast<const RexLiteral*
>(rex_function->getOperand(1));
639 ": second argument is expected to be a literal");
643 if (!ce || !e->get_type_info().is_integer()) {
647 if (e->get_type_info().get_type() ==
kSMALLINT) {
648 srid =
static_cast<int32_t
>(ce->get_constval().smallintval);
649 }
else if (e->get_type_info().get_type() ==
kTINYINT) {
650 srid =
static_cast<int32_t
>(ce->get_constval().tinyintval);
651 }
else if (e->get_type_info().get_type() ==
kINT) {
652 srid =
static_cast<int32_t
>(ce->get_constval().intval);
657 const auto rex_scalar0 =
658 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
661 ": expects scalar as first argument");
672 (try_to_compress && (srid == 4326)));
674 CHECK(!arg0.empty() && arg0.front());
680 if (
auto geo_expr = std::dynamic_pointer_cast<Analyzer::GeoExpr>(arg0.front())) {
682 auto ti = geo_expr->get_type_info();
683 ti.set_input_srid(srid);
684 ti.set_output_srid(srid);
685 return {geo_expr->add_cast(ti)};
688 }
else if (rex_function->getName() ==
"CastToGeography"sv) {
689 CHECK_EQ(
size_t(1), rex_function->size());
690 const auto rex_scalar0 =
691 dynamic_cast<const RexScalar*
>(rex_function->getOperand(0));
694 ": expects scalar as first argument");
702 use_geo_expressions);
703 CHECK(!arg0.empty());
704 if (
auto geo_expr = std::dynamic_pointer_cast<Analyzer::GeoExpr>(arg0.front())) {
705 auto arg_ti = geo_expr->get_type_info();
707 return {geo_expr->add_cast(arg_ti)};
709 if (use_geo_expressions) {
710 arg_ti = arg0.front()->get_type_info();
712 arg0.front()->set_type_info(arg_ti);
719 " expects geometry with SRID=4326");
723 }
else if (rex_function->getName() ==
"ST_Point"sv) {
724 CHECK_EQ(
size_t(2), rex_function->size());
734 auto cast_coord1 = coord1->add_cast(d_ti);
735 auto cast_coord2 = coord2->add_cast(d_ti);
737 auto folded_coord1 =
fold_expr(cast_coord1.get());
738 auto folded_coord2 =
fold_expr(cast_coord2.get());
741 if (const_coord1 && const_coord2 && !use_geo_expressions) {
742 CHECK(const_coord1->get_type_info().get_type() ==
kDOUBLE);
743 CHECK(const_coord2->get_type_info().get_type() ==
kDOUBLE);
744 std::string wkt =
"POINT(" +
747 RexLiteral rex_literal{wkt,
kTEXT,
kNULLT, 0, 0, 0, 0};
753 if (!is_local_alloca || use_geo_expressions) {
754 if (try_to_compress) {
758 return {makeExpr<Analyzer::GeoOperator>(
760 rex_function->getName(),
761 std::vector<std::shared_ptr<Analyzer::Expr>>{folded_coord1, folded_coord2})};
767 if (try_to_compress) {
769 da_ti.set_subtype(
kINT);
771 da_ti.set_input_srid(4326);
772 da_ti.set_output_srid(4326);
774 da_ti.set_comp_param(32);
781 auto cast_coords = {folded_coord1, folded_coord2};
782 auto ae = makeExpr<Analyzer::ArrayExpr>(da_ti, cast_coords,
false, is_local_alloca);
785 return {makeExpr<Analyzer::UOper>(tia_ti,
false,
kCAST, ae)};
786 }
else if (rex_function->getName() ==
"ST_Centroid"sv) {
787 CHECK_EQ(
size_t(1), rex_function->size());
795 int legacy_transform_srid = 0;
803 CHECK_EQ(geoargs.size(), size_t(1));
809 if (try_to_compress) {
828 return {makeExpr<Analyzer::GeoOperator>(
830 rex_function->getName(),
831 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()},
832 legacy_transform_srid > 0 ? std::make_optional<int>(legacy_transform_srid)
834 }
else if (
func_resolve(rex_function->getName(),
"ST_ConvexHull"sv)) {
835 CHECK_EQ(
size_t(1), rex_function->size());
843 "ST_ConcaveHull"sv)) {
844 CHECK_EQ(
size_t(2), rex_function->size());
847 }
else if (
func_resolve(rex_function->getName(),
"ST_IsEmpty"sv,
"ST_IsValid"sv)) {
848 CHECK_EQ(
size_t(1), rex_function->size());
850 }
else if (
func_resolve(rex_function->getName(),
"ST_Equals"sv)) {
851 CHECK_EQ(
size_t(2), rex_function->size());
857 const auto rex_literal =
dynamic_cast<const RexLiteral*
>(rex_scalar);
859 if (use_geo_expressions) {
861 auto const translated_literal_type = translated_literal->get_type_info().get_type();
862 if (!
IS_STRING(translated_literal_type) && !
IS_GEO(translated_literal_type)) {
871 const auto constant_expr =
873 CHECK(constant_expr);
874 if (constant_expr->get_is_null()) {
878 const auto& datum = constant_expr->get_constval();
879 CHECK(datum.stringval);
881 CHECK(geospatial_base);
905 return {makeExpr<Analyzer::GeoConstant>(std::move(geospatial_base), ti)};
915 const bool with_bounds)
const {
918 const bool use_geo_projections = !(rex_function->
getName() ==
"ST_GeomFromText" ||
919 rex_function->
getName() ==
"ST_GeogFromText" ||
920 rex_function->
getName() ==
"ST_SetSRID");
927 use_geo_projections);
928 CHECK(!geoargs.empty());
929 if (std::dynamic_pointer_cast<const Analyzer::GeoExpr>(geoargs.front()) &&
930 !geoargs.front()->get_type_info().is_array()) {
931 if (rex_function->
getName() ==
"ST_Transform" &&
933 return makeExpr<Analyzer::GeoUOper>(
937 return geoargs.front();
939 bool allow_gdal_transform =
false;
940 if (rex_function->
getName() ==
"ST_Transform") {
943 if (rex_function0 &&
func_resolve(rex_function0->getName(),
949 "ST_ConvexHull"sv)) {
951 allow_gdal_transform =
true;
954 if (use_geo_projections && !allow_gdal_transform) {
955 throw std::runtime_error(
"Geospatial projection for function " +
957 " not yet supported in this context");
959 return makeExpr<Analyzer::GeoUOper>(
966 const bool with_bounds)
const {
969 " geo constructor requires enabled GEOS support");
972 if (rex_function->
getName() ==
"ST_Difference"sv) {
974 }
else if (rex_function->
getName() ==
"ST_Union"sv) {
976 }
else if (rex_function->
getName() ==
"ST_Buffer"sv) {
978 }
else if (rex_function->
getName() ==
"ST_ConcaveHull"sv) {
991 "ST_ConcaveHull"sv)) {
1004 "ST_Intersection"sv,
1019 " geo constructor requires arguments with matching srids");
1025 if (param_expr->get_type_info().get_type() !=
kDOUBLE) {
1026 param_expr = param_expr->add_cast(arg1_ti);
1028 geoargs1 = {param_expr};
1046 " requires its argument(s) to have a valid srid");
1055 return makeExpr<Analyzer::GeoBinOper>(op, arg_ti, arg0_ti, arg1_ti, geoargs0, geoargs1);
1061 const bool with_bounds)
const {
1064 " geo predicate requires enabled GEOS support");
1068 rex_function->
getOperand(0), arg_ti,
false,
false,
true,
true);
1070 auto op = (rex_function->
getName() ==
"ST_IsEmpty"sv)
1073 return makeExpr<Analyzer::GeoUOper>(op, ti, arg_ti, geoargs);
1079 const bool with_bounds)
const {
1080 if (rex_function->
getName() !=
"ST_Equals"sv) {
1085 " geo predicate requires enabled GEOS support");
1089 rex_function->
getOperand(0), arg0_ti,
false,
false,
true,
true);
1092 rex_function->
getOperand(1), arg1_ti,
false,
false,
true,
true);
1095 return makeExpr<Analyzer::GeoBinOper>(op, ti, arg0_ti, arg1_ti, geoargs0, geoargs1);
1101 const bool with_bounds)
const {
1104 " geo constructor requires enabled GEOS support");
1138 " requires its argument(s) to have a valid srid");
1147 return makeExpr<Analyzer::GeoUOper>(op, arg_ti, arg0_ti, geoargs0);
1154 std::string specialized_geofunc{rex_function->
getName()};
1158 if (rex_function->
getName() ==
"ST_NRings"sv) {
1169 " expects a POLYGON or MULTIPOLYGON");
1171 CHECK_EQ(geoargs.size(), size_t(1));
1172 arg_ti = rex_function->
getType();
1173 return makeExpr<Analyzer::GeoOperator>(
1176 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()});
1177 }
else if (rex_function->
getName() ==
"ST_NumGeometries"sv) {
1189 CHECK_EQ(geoargs.size(), size_t(1));
1190 arg_ti = rex_function->
getType();
1191 return makeExpr<Analyzer::GeoOperator>(
1194 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()});
1195 }
else if (rex_function->
getName() ==
"ST_NPoints"sv) {
1204 CHECK_EQ(geoargs.size(), size_t(1));
1205 return makeExpr<Analyzer::GeoOperator>(
1208 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()});
1211 int legacy_transform_srid = 0;
1219 CHECK_EQ(geoargs.size(), size_t(1));
1226 arg_ti = geoargs.front()->get_type_info();
1230 " expects a POLYGON or MULTIPOLYGON");
1232 return makeExpr<Analyzer::GeoOperator>(
1235 std::vector<std::shared_ptr<Analyzer::Expr>>{geoargs.front()},
1236 legacy_transform_srid > 0 ? std::make_optional<int>(legacy_transform_srid)
1249 " expects a POLYGON or MULTIPOLYGON");
1252 geoargs.erase(geoargs.begin(), geoargs.end() - 1);
1254 return makeExpr<Analyzer::FunctionOper>(
1255 rex_function->
getType(), specialized_geofunc, geoargs);
1264 " expects a POLYGON or MULTIPOLYGON");
1267 geoargs.erase(geoargs.begin(), geoargs.end() - 1);
1269 return makeExpr<Analyzer::FunctionOper>(
1270 rex_function->
getType(), specialized_geofunc, geoargs);
1280 " expects a POLYGON or MULTIPOLYGON");
1284 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1287 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1290 Datum input_compression;
1292 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1296 auto rex_function_type = rex_function->
getType();
1300 return makeExpr<Analyzer::FunctionOper>(rex_function_type, specialized_geofunc,
args);
1309 " expects a POLYGON or MULTIPOLYGON");
1314 if (geoargs.size() == 3) {
1315 geoargs.erase(geoargs.end() - 1);
1317 geoargs.erase(geoargs.begin());
1321 auto rex_function_type = rex_function->
getType();
1325 return makeExpr<Analyzer::FunctionOper>(
1326 rex_function_type, specialized_geofunc, geoargs);
1339 geoargs.erase(geoargs.begin());
1340 geoargs.erase(geoargs.begin());
1344 auto rex_function_type = rex_function->
getType();
1348 return makeExpr<Analyzer::FunctionOper>(
1349 rex_function_type, specialized_geofunc, geoargs);
1363 CHECK_EQ(new_geoargs.size(), size_t(1));
1364 CHECK(new_geoargs.front());
1365 const auto& arg_expr_ti = new_geoargs.front()->get_type_info();
1366 if (arg_expr_ti.get_type() !=
kPOINT) {
1369 auto function_ti = rex_function->
getType();
1370 if (std::dynamic_pointer_cast<Analyzer::GeoOperator>(new_geoargs.front())) {
1373 if (std::dynamic_pointer_cast<Analyzer::GeoConstant>(new_geoargs.front())) {
1375 function_ti.set_notnull(
true);
1377 return makeExpr<Analyzer::GeoOperator>(
1380 std::vector<std::shared_ptr<Analyzer::Expr>>{new_geoargs.front()});
1385 bool with_bounds =
true;
1387 rex_function->
getOperand(0), arg_ti, with_bounds,
false,
false);
1389 if (rex_function->
getName() ==
"ST_SRID"sv) {
1392 return makeExpr<Analyzer::Constant>(
kINT,
false, output_srid);
1396 rex_function->
getName(),
"ST_XMin"sv,
"ST_YMin"sv,
"ST_XMax"sv,
"ST_YMax"sv)) {
1400 geoargs.erase(geoargs.begin(), geoargs.end() - 1);
1405 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
1408 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1410 specialized_geofunc +=
"_Bounds"s;
1411 return makeExpr<Analyzer::FunctionOper>(
1412 rex_function->
getType(), specialized_geofunc, geoargs);
1418 auto discard_after_arg = 1;
1420 if (rex_function->
getName() ==
"ST_Length"sv) {
1423 " expects LINESTRING or MULTILINESTRING");
1426 auto ti0 = geoargs[0]->get_type_info();
1429 discard_after_arg = 2;
1436 " Geodesic is not supported for MULTILINESTRING");
1438 specialized_geofunc +=
"_Geodesic"s;
1442 geoargs.erase(geoargs.begin() + discard_after_arg, geoargs.end());
1446 Datum input_compression;
1448 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1451 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
1456 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1458 return makeExpr<Analyzer::FunctionOper>(
1459 rex_function->
getType(), specialized_geofunc, geoargs);
1464 auto function_name = rex_function->
getName();
1465 auto return_type = rex_function->
getType();
1467 if (function_name ==
"ST_Overlaps"sv) {
1470 auto extract_geo_bounds_from_input =
1471 [
this, &rex_function](
const size_t index) -> std::shared_ptr<Analyzer::Expr> {
1472 const auto rex_input =
1479 throw std::runtime_error(
"ST_Overlaps is not supported for point arguments.");
1481 return exprs.back();
1484 throw std::runtime_error(
1485 "Only inputs are supported as arguments to ST_Overlaps for now.");
1488 std::vector<std::shared_ptr<Analyzer::Expr>> geo_args;
1489 geo_args.push_back(extract_geo_bounds_from_input(0));
1490 geo_args.push_back(extract_geo_bounds_from_input(1));
1492 return makeExpr<Analyzer::FunctionOper>(return_type, function_name, geo_args);
1495 if (function_name ==
"ST_Distance"sv || function_name ==
"ST_MaxDistance"sv) {
1497 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1498 int legacy_transform_srid = 0;
1499 for (
size_t i = 0; i < rex_function->
size(); i++) {
1512 CHECK(legacy_transform_srid == 0 ||
1516 args.insert(args.end(), geoargs.begin(), geoargs.end());
1518 return makeExpr<Analyzer::GeoOperator>(
1522 legacy_transform_srid > 0 ? std::make_optional<int>(legacy_transform_srid)
1526 bool swap_args =
false;
1527 bool with_bounds =
false;
1528 bool negate_result =
false;
1531 if (function_name ==
"ST_DWithin"sv) {
1533 function_name =
"ST_Distance";
1537 }
else if (function_name ==
"ST_Equals"sv) {
1540 function_name =
"ST_Distance";
1542 threshold_expr =
nullptr;
1545 compare_expr = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, d);
1546 }
else if (function_name ==
"ST_DFullyWithin"sv) {
1548 function_name =
"ST_MaxDistance";
1551 threshold_expr =
nullptr;
1552 }
else if (function_name ==
"ST_Distance"sv) {
1554 threshold_expr =
nullptr;
1555 }
else if (function_name ==
"ST_MaxDistance"sv) {
1558 threshold_expr =
nullptr;
1562 if (function_name ==
"ST_Within"sv) {
1563 function_name =
"ST_Contains";
1565 }
else if (function_name ==
"ST_Disjoint"sv) {
1566 function_name =
"ST_Intersects";
1567 negate_result =
true;
1570 function_name,
"ST_Contains"sv,
"ST_Intersects"sv,
"ST_Approx_Overlaps"sv)) {
1574 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
1589 try_to_compress_arg0);
1590 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1594 bool try_to_compress_arg1 =
1596 func_resolve(function_name,
"ST_Contains"sv,
"ST_Intersects"sv) &&
1607 try_to_compress_arg1);
1608 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1612 " accepts either two GEOGRAPHY or two GEOMETRY arguments");
1641 threshold_expr = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, tolerance);
1642 compare_expr = threshold_expr;
1646 " unable to calculate compression tolerance for arguments");
1652 " currently doesn't support this argument combination");
1655 auto can_use_compressed_coords = [](
const SQLTypeInfo& i0_ti,
1659 const bool i0_is_poly =
1661 const bool i1_is_point = i1_ti.get_type() ==
kPOINT;
1662 const bool i1_is_literal =
1664 i1_operands.front()) !=
nullptr;
1665 return (i0_is_poly && !i1_is_literal && i1_is_point &&
1669 i1_ti.get_input_srid() == i1_ti.get_output_srid());
1672 if (can_use_compressed_coords(arg0_ti, geoargs0, arg1_ti, geoargs1)) {
1674 function_name =
"ST_cContains";
1678 if (can_use_compressed_coords(arg0_ti, geoargs0, arg1_ti, geoargs1)) {
1680 function_name =
"ST_cIntersects";
1681 }
else if (can_use_compressed_coords(arg1_ti, geoargs1, arg0_ti, geoargs0)) {
1683 function_name =
"ST_cIntersects";
1685 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1686 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1687 auto tmp_ti = arg0_ti;
1693 std::string specialized_geofunc{function_name +
suffix(arg0_ti.
get_type()) +
1698 if (function_name ==
"ST_Distance"sv) {
1703 specialized_geofunc +=
"_Geodesic"s;
1706 " currently doesn't accept non-POINT geographies");
1708 }
else if (rex_function->
getName() ==
"ST_Contains"sv) {
1714 }
else if (function_name ==
"ST_Distance"sv && rex_function->
size() == 3) {
1717 specialized_geofunc +=
"_Squared"s;
1723 Datum input_compression0;
1725 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression0));
1728 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid0));
1732 Datum input_compression1;
1734 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression1));
1737 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid1));
1742 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1752 if (threshold_expr) {
1753 if (threshold_expr->get_type_info().get_type() !=
kDOUBLE) {
1755 threshold_expr = threshold_expr->add_cast(threshold_ti);
1757 threshold_expr =
fold_expr(threshold_expr.get());
1761 threshold_expr = makeExpr<Analyzer::Constant>(
kDOUBLE,
false, d);
1763 geoargs.push_back(threshold_expr);
1767 makeExpr<Analyzer::FunctionOper>(return_type, specialized_geofunc, geoargs);
1768 if (negate_result) {
1783 if (distance_expr->get_type_info().get_type() !=
kDOUBLE) {
1784 distance_expr = distance_expr->add_cast(distance_ti);
1787 auto function_name = rex_function->
getName();
1788 if (function_name ==
"ST_DWithin"sv) {
1789 auto return_type = rex_function->
getType();
1790 bool swap_args =
false;
1791 bool with_bounds =
true;
1796 rex_function->
getOperand(0), arg0_ti, with_bounds,
false,
false);
1798 rex_function->
getOperand(1), arg1_ti, with_bounds,
false,
false);
1801 " cannot accept mixed GEOMETRY/GEOGRAPHY arguments");
1803 auto is_geodesic =
false;
1810 " in geodesic form can only accept POINT GEOGRAPHY arguments");
1828 Datum input_compression0;
1835 Datum input_compression1;
1844 std::string specialized_geofunc{function_name};
1845 std::vector<std::shared_ptr<Analyzer::Expr>> geoargs;
1848 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1849 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1850 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression1));
1851 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid1));
1852 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression0));
1853 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid0));
1857 specialized_geofunc +=
"_Geodesic"s;
1859 geoargs.insert(geoargs.end(), geoargs0.begin(), geoargs0.end());
1860 geoargs.insert(geoargs.end(), geoargs1.begin(), geoargs1.end());
1861 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression0));
1862 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid0));
1863 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression1));
1864 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid1));
1866 geoargs.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1868 geoargs.push_back(distance_expr);
1871 makeExpr<Analyzer::FunctionOper>(return_type, specialized_geofunc, geoargs);
1879 return makeExpr<Analyzer::BinOper>(
kBOOLEAN,
kLE,
kONE, geo_distance, distance_expr);
1884 if (rex_operator->
size() != size_t(2)) {
1890 if (func_oper && func_oper->getName() ==
"ST_Distance"sv) {
1893 if (distance_expr->get_type_info().get_type() !=
kDOUBLE) {
1894 distance_expr = distance_expr->add_cast(distance_ti);
1896 distance_expr =
fold_expr(distance_expr.get());
1897 return makeExpr<Analyzer::BinOper>(
1905 std::string specialized_geofunc{rex_function->
getName()};
1907 "convert_meters_to_pixel_width"sv,
1908 "convert_meters_to_pixel_height"sv)) {
1911 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1916 if (arg_ti.get_type() !=
kPOINT) {
1918 " expects a point for the second argument");
1921 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1924 Datum input_compression;
1926 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1927 if (arg_ti.get_input_srid() != 4326) {
1930 " currently only supports points of with SRID WGS84/EPSG:4326");
1933 input_srid.
intval = arg_ti.get_input_srid();
1934 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_srid));
1939 arg_ti.get_output_srid() != 900913 ? 900913 : arg_ti.get_output_srid();
1940 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, output_srid));
1946 return makeExpr<Analyzer::FunctionOper>(
1947 rex_function->
getType(), specialized_geofunc,
args);
1948 }
else if (rex_function->
getName() ==
"is_point_in_view"sv) {
1951 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1955 if (arg_ti.get_type() !=
kPOINT) {
1957 " expects a point for the second argument");
1960 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1963 Datum input_compression;
1965 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1966 if (arg_ti.get_input_srid() != 4326) {
1969 " currently only supports points of with SRID WGS84/EPSG:4326");
1975 return makeExpr<Analyzer::FunctionOper>(
1976 rex_function->
getType(), specialized_geofunc,
args);
1977 }
else if (rex_function->
getName() ==
"is_point_size_in_view"sv) {
1980 std::vector<std::shared_ptr<Analyzer::Expr>>
args;
1984 if (arg_ti.get_type() !=
kPOINT) {
1986 " expects a point for the second argument");
1989 args.insert(args.end(), geoargs.begin(), geoargs.begin() + 1);
1992 Datum input_compression;
1994 args.push_back(makeExpr<Analyzer::Constant>(
kINT,
false, input_compression));
1995 if (arg_ti.get_input_srid() != 4326) {
1998 " currently only supports points of with SRID WGS84/EPSG:4326");
2005 return makeExpr<Analyzer::FunctionOper>(
2006 rex_function->
getType(), specialized_geofunc,
args);
2016 auto translate_input =
2017 [&](
const RexScalar* operand) -> std::shared_ptr<Analyzer::Expr> {
2018 const auto input =
dynamic_cast<const RexInput*
>(operand);
2025 return exprs.front();
2027 return exprs.back();
2037 translate_input(rex_operator->
getOperand(1)),
2038 translate_input(rex_operator->
getOperand(0)));
HOST DEVICE SQLTypes get_subtype() const
void set_compression(EncodingType c)
static std::unique_ptr< GeoBase > createGeoType(const std::string &wkt_or_wkb_hex)
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...
std::vector< std::shared_ptr< Analyzer::Expr > > translateGeoFunctionArg(const RexScalar *rex_scalar, SQLTypeInfo &arg_ti, const bool with_bounds, const bool with_render_group, 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
#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
bool has_render_group() const
std::shared_ptr< Analyzer::Expr > translateGeoOverlapsOper(const RexOperator *) 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
void set_output_srid(int s)
const std::unordered_map< const RelAlgNode *, int > input_to_nest_level_
void set_comp_param(int p)
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 promote_poly_to_mpoly=false)
std::shared_ptr< Analyzer::Expr > translateUnaryGeoPredicate(const RexFunctionOperator *, SQLTypeInfo &, const bool with_bounds) const
HOST DEVICE EncodingType get_compression() const
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()
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::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
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)
HOST DEVICE int get_output_srid() const
virtual GeoType getType() const =0
HOST DEVICE void set_type(SQLTypes t)