@@ -329,6 +329,61 @@ struct PointCasts {
329329 return true ;
330330 }
331331
332+ // ------------------------------------------------------------------------------------------------------------------
333+ // POINT_4D -> VARCHAR
334+ // ------------------------------------------------------------------------------------------------------------------
335+ static bool ToVarcharCast4D (Vector &source, Vector &result, idx_t count, CastParameters ¶meters) {
336+ CoreVectorOperations::Point4DToVarchar (source, result, count);
337+ return true ;
338+ }
339+
340+ // ------------------------------------------------------------------------------------------------------------------
341+ // POINT_4D -> GEOMETRY
342+ // ------------------------------------------------------------------------------------------------------------------
343+ static bool ToGeometryCast4D (Vector &source, Vector &result, idx_t count, CastParameters ¶meters) {
344+ using POINT_TYPE = StructTypeQuaternary<double , double , double , double >;
345+ using GEOMETRY_TYPE = PrimitiveType<string_t >;
346+
347+ auto &lstate = LocalState::ResetAndGet (parameters);
348+
349+ GenericExecutor::ExecuteUnary<POINT_TYPE, GEOMETRY_TYPE>(source, result, count, [&](const POINT_TYPE &point) {
350+ const double buffer[4 ] = {point.a_val , point.b_val , point.c_val , point.d_val };
351+ sgl::geometry geom (sgl::geometry_type::POINT, true , true );
352+ geom.set_vertex_array (buffer, 1 );
353+
354+ return lstate.Serialize (result, geom);
355+ });
356+ return true ;
357+ }
358+
359+ // ------------------------------------------------------------------------------------------------------------------
360+ // GEOMETRY -> POINT_4D
361+ // ------------------------------------------------------------------------------------------------------------------
362+ static bool FromGeometryCast4D (Vector &source, Vector &result, idx_t count, CastParameters ¶meters) {
363+ using POINT_TYPE = StructTypeQuaternary<double , double , double , double >;
364+ using GEOMETRY_TYPE = PrimitiveType<string_t >;
365+
366+ auto &lstate = LocalState::ResetAndGet (parameters);
367+
368+ GenericExecutor::ExecuteUnary<GEOMETRY_TYPE, POINT_TYPE>(source, result, count, [&](const GEOMETRY_TYPE &blob) {
369+ sgl::geometry geom;
370+ lstate.Deserialize (blob.val , geom);
371+
372+ if (geom.get_type () != sgl::geometry_type::POINT) {
373+ throw ConversionException (" Cannot cast non-point GEOMETRY to POINT_4D" );
374+ }
375+ if (geom.is_empty ()) {
376+ // TODO: Maybe make this return NULL instead
377+ throw ConversionException (" Cannot cast empty point GEOMETRY to POINT_4D" );
378+ }
379+ const auto vertex = geom.get_vertex_xyzm (0 );
380+ return POINT_TYPE {vertex.x , vertex.y , vertex.z , vertex.m };
381+ });
382+
383+ return true ;
384+ }
385+
386+
332387 // ------------------------------------------------------------------------------------------------------------------
333388 // Register
334389 // ------------------------------------------------------------------------------------------------------------------
@@ -351,8 +406,17 @@ struct PointCasts {
351406 BoundCastInfo (FromGeometryCast3D, nullptr , LocalState::InitCast), 1 );
352407 // POINT_3D -> POINT_2D
353408 loader.RegisterCastFunction (GeoTypes::POINT_3D (), GeoTypes::POINT_2D (), ToPoint2DCast, 1 );
409+
410+ // POINT_4D -> VARCHAR
411+ loader.RegisterCastFunction (GeoTypes::POINT_4D (), LogicalType::VARCHAR, BoundCastInfo (ToVarcharCast4D), 1 );
354412 // POINT_4D -> POINT_2D
355413 loader.RegisterCastFunction (GeoTypes::POINT_4D (), GeoTypes::POINT_2D (), ToPoint2DCast, 1 );
414+ // POINT_4D -> GEOMETRY
415+ loader.RegisterCastFunction (GeoTypes::POINT_4D (), GeoTypes::GEOMETRY (),
416+ BoundCastInfo (ToGeometryCast4D, nullptr , LocalState::InitCast), 1 );
417+ // GEOMETRY -> POINT_4D
418+ loader.RegisterCastFunction (GeoTypes::GEOMETRY (), GeoTypes::POINT_4D (),
419+ BoundCastInfo (FromGeometryCast4D, nullptr , LocalState::InitCast), 1 );
356420 }
357421};
358422
@@ -947,6 +1011,27 @@ void CoreVectorOperations::Point3DToVarchar(Vector &source, Vector &result, idx_
9471011 });
9481012}
9491013
1014+ // ------------------------------------------------------------------------------
1015+ // POINT_4D -> VARCHAR
1016+ // ------------------------------------------------------------------------------
1017+ void CoreVectorOperations::Point4DToVarchar (Vector &source, Vector &result, idx_t count) {
1018+ using POINT_TYPE = StructTypeQuaternary<double , double , double , double >;
1019+ using VARCHAR_TYPE = PrimitiveType<string_t >;
1020+
1021+ GenericExecutor::ExecuteUnary<POINT_TYPE, VARCHAR_TYPE>(source, result, count, [&](POINT_TYPE &point) {
1022+ auto x = point.a_val ;
1023+ auto y = point.b_val ;
1024+ auto z = point.c_val ;
1025+ auto m = point.d_val ;
1026+
1027+ if (std::isnan (x) || std::isnan (y) || std::isnan (z) || std::isnan (m)) {
1028+ return StringVector::AddString (result, " POINT EMPTY" );
1029+ }
1030+
1031+ return StringVector::AddString (result, StringUtil::Format (" POINT ZM (%s)" , MathUtil::format_coord (x, y, z, m)));
1032+ });
1033+ }
1034+
9501035// ------------------------------------------------------------------------------
9511036// LINESTRING_2D -> VARCHAR
9521037// ------------------------------------------------------------------------------
0 commit comments