diff --git a/Cargo.lock b/Cargo.lock index 50843d6e06ec1..66631453445f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2972,7 +2972,7 @@ dependencies = [ "databend-common-arrow", "databend-common-ast", "geos", - "geozero", + "geozero 0.13.0", "http 1.1.0", "opendal", "parquet", @@ -3015,7 +3015,7 @@ dependencies = [ "futures", "geo", "geos", - "geozero", + "geozero 0.13.0", "goldenfile", "hex", "itertools 0.10.5", @@ -3060,7 +3060,7 @@ dependencies = [ "databend-storages-common-blocks", "databend-storages-common-table-meta", "geos", - "geozero", + "geozero 0.13.0", "hex", "jsonb", "lexical-core", @@ -3104,7 +3104,7 @@ dependencies = [ "geo-types", "geohash", "geos", - "geozero", + "geozero 0.13.0", "goldenfile", "h3o", "hex", @@ -3195,14 +3195,13 @@ dependencies = [ "ethnum", "geo", "geos", - "geozero", + "geozero 0.13.0", "lexical-core", "micromarshal 0.5.0", "ordered-float 4.2.0", "rand 0.8.5", "rmp-serde", "roaring", - "scroll 0.12.0", "serde", "wkt", ] @@ -4797,7 +4796,7 @@ dependencies = [ "arrow", "chrono", "databend-client", - "geozero", + "geozero 0.12.0", "glob", "hex", "itertools 0.12.1", @@ -6406,12 +6405,27 @@ name = "geozero" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61d25cc15c7e5b86cd8dadea56bb78c46f346d4fb09022e7cbba0839c890d0a1" +dependencies = [ + "geo-types", + "geojson", + "log", + "scroll", + "serde_json", + "thiserror", + "wkt", +] + +[[package]] +name = "geozero" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cd8fb67347739a057fd607b6d8b43ba4ed93619ed84b8f429fa3296f8ae504c" dependencies = [ "geo-types", "geojson", "geos", "log", - "scroll 0.11.0", + "scroll", "serde_json", "thiserror", "wkt", @@ -12472,12 +12486,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -[[package]] -name = "scroll" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" - [[package]] name = "scrypt" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index 148ecdc727327..ad170e52174a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -162,7 +162,7 @@ ethnum = { version = "1.5.0" } feature-set = { version = "0.1.1" } geo = { version = "0.27.0", features = ["use-serde"] } geos = { version = "8.3", features = ["static", "geo", "geo-types"] } -geozero = { version = "0.12.0", features = ["default", "with-wkb", "with-geos", "with-geojson"] } +geozero = { version = "0.13.0", features = ["default", "with-wkb", "with-geos", "with-geojson"] } itertools = "0.10.5" match-template = "0.0.1" mysql_async = { version = "0.34", default-features = false, features = ["rustls-tls"] } diff --git a/src/common/io/Cargo.toml b/src/common/io/Cargo.toml index ef2f3fe6e4f28..693bafc1770c2 100644 --- a/src/common/io/Cargo.toml +++ b/src/common/io/Cargo.toml @@ -30,7 +30,6 @@ lexical-core = "0.8.5" micromarshal = "0.5.0" ordered-float = { workspace = true } roaring = { version = "0.10.1", features = ["serde"] } -scroll = "0.12.0" serde = { workspace = true } wkt = "0.10.3" diff --git a/src/common/io/src/geometry.rs b/src/common/io/src/geometry.rs index f95701aca46d2..f597150ac51e5 100644 --- a/src/common/io/src/geometry.rs +++ b/src/common/io/src/geometry.rs @@ -13,8 +13,6 @@ // limitations under the License. use std::fmt::Display; -use std::io; -use std::io::Read; use std::str::FromStr; use databend_common_exception::ErrorCode; @@ -26,14 +24,10 @@ use geozero::GeozeroGeometry; use geozero::ToJson; use geozero::ToWkb; use geozero::ToWkt; -use scroll::Endian; -use scroll::IOread; use serde::Deserialize; use serde::Serialize; use wkt::TryFromWkt; -const GEO_TYPE_ID_MASK: u32 = 0x2000_0000; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] pub enum GeometryDataType { WKB, @@ -44,6 +38,18 @@ pub enum GeometryDataType { GEOJSON, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Axis { + X, + Y, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Extremum { + Max, + Min, +} + impl FromStr for GeometryDataType { type Err = ErrorCode; @@ -168,21 +174,6 @@ pub fn parse_to_subtype(buf: &[u8]) -> Result { } } } - -pub fn read_ewkb_srid(raw: &mut R) -> std::result::Result, io::Error> { - let byte_order = raw.ioread::()?; - let is_little_endian = byte_order != 0; - let endian = Endian::from(is_little_endian); - let type_id = raw.ioread_with::(endian)?; - let srid = if type_id & GEO_TYPE_ID_MASK == GEO_TYPE_ID_MASK { - Some(raw.ioread_with::(endian)?) - } else { - None - }; - - Ok(srid) -} - pub trait GeometryFormatOutput { fn format(self, data_type: GeometryDataType) -> Result; } diff --git a/src/common/io/src/lib.rs b/src/common/io/src/lib.rs index 03062ee9d5236..c8548ef97d53a 100644 --- a/src/common/io/src/lib.rs +++ b/src/common/io/src/lib.rs @@ -50,5 +50,6 @@ pub use escape::escape_string_with_quote; pub use geometry::geometry_format; pub use geometry::parse_to_ewkb; pub use geometry::parse_to_subtype; -pub use geometry::read_ewkb_srid; +pub use geometry::Axis; +pub use geometry::Extremum; pub use geometry::GeometryDataType; diff --git a/src/query/expression/src/utils/display.rs b/src/query/expression/src/utils/display.rs index 70b4723553b6d..57f83bdde676f 100755 --- a/src/query/expression/src/utils/display.rs +++ b/src/query/expression/src/utils/display.rs @@ -15,15 +15,15 @@ use std::fmt::Debug; use std::fmt::Display; use std::fmt::Formatter; -use std::io; use chrono_tz::Tz; use comfy_table::Cell; use comfy_table::Table; use databend_common_io::display_decimal_128; use databend_common_io::display_decimal_256; -use databend_common_io::read_ewkb_srid; use geozero::wkb::Ewkb; +use geozero::GeozeroGeometry; +use geozero::ToGeos; use geozero::ToWkt; use itertools::Itertools; use num_traits::FromPrimitive; @@ -167,9 +167,9 @@ impl<'a> Debug for ScalarRef<'a> { Ok(()) } ScalarRef::Geometry(s) => { - let geom = Ewkb(s.to_vec()) - .to_ewkt(read_ewkb_srid(&mut io::Cursor::new(s)).unwrap()) - .unwrap(); + let ewkb = Ewkb(s.to_vec()); + let geos = ewkb.to_geos().unwrap(); + let geom = geos.to_ewkt(geos.srid()).unwrap(); write!(f, "{geom:?}") } } @@ -258,9 +258,9 @@ impl<'a> Display for ScalarRef<'a> { write!(f, "'{value}'") } ScalarRef::Geometry(s) => { - let geom = Ewkb(s.to_vec()) - .to_ewkt(read_ewkb_srid(&mut io::Cursor::new(s)).unwrap()) - .unwrap(); + let ewkb = Ewkb(s.to_vec()); + let geos = ewkb.to_geos().unwrap(); + let geom = geos.to_ewkt(geos.srid()).unwrap(); write!(f, "'{geom}'") } } diff --git a/src/query/formats/src/field_encoder/values.rs b/src/query/formats/src/field_encoder/values.rs index dc8405d52e5ee..ba2e540f65fba 100644 --- a/src/query/formats/src/field_encoder/values.rs +++ b/src/query/formats/src/field_encoder/values.rs @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::io; - use bstr::ByteSlice; use chrono_tz::Tz; use databend_common_arrow::arrow::bitmap::Bitmap; @@ -35,10 +33,11 @@ use databend_common_io::constants::NAN_BYTES_LOWER; use databend_common_io::constants::NAN_BYTES_SNAKE; use databend_common_io::constants::NULL_BYTES_UPPER; use databend_common_io::constants::TRUE_BYTES_NUM; -use databend_common_io::read_ewkb_srid; use databend_common_io::GeometryDataType; use geozero::wkb::Ewkb; use geozero::CoordDimensions; +use geozero::GeozeroGeometry; +use geozero::ToGeos; use geozero::ToJson; use geozero::ToWkb; use geozero::ToWkt; @@ -318,11 +317,11 @@ impl FieldEncoderValues { .to_vec(), GeometryDataType::WKT => Ewkb(v.to_vec()).to_wkt().unwrap().as_bytes().to_vec(), GeometryDataType::EWKB => hex::encode_upper(v).as_bytes().to_vec(), - GeometryDataType::EWKT => Ewkb(v.to_vec()) - .to_ewkt(read_ewkb_srid(&mut io::Cursor::new(&v)).unwrap()) - .unwrap() - .as_bytes() - .to_vec(), + GeometryDataType::EWKT => { + let ewkb = Ewkb(v.to_vec()); + let geos = ewkb.to_geos().unwrap(); + geos.to_ewkt(geos.srid()).unwrap().as_bytes().to_vec() + } GeometryDataType::GEOJSON => Ewkb(v.to_vec()).to_json().unwrap().as_bytes().to_vec(), }; diff --git a/src/query/functions/src/scalars/geometry.rs b/src/query/functions/src/scalars/geometry.rs index 85f1aaa1e0f45..216998a1b3602 100644 --- a/src/query/functions/src/scalars/geometry.rs +++ b/src/query/functions/src/scalars/geometry.rs @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::io; - use databend_common_exception::ErrorCode; use databend_common_expression::types::geometry::GeometryType; use databend_common_expression::types::BinaryType; @@ -30,12 +28,12 @@ use databend_common_expression::FunctionRegistry; use databend_common_io::geometry_format; use databend_common_io::parse_to_ewkb; use databend_common_io::parse_to_subtype; -use databend_common_io::read_ewkb_srid; +use databend_common_io::Axis; +use databend_common_io::Extremum; use databend_common_io::GeometryDataType; use geo::dimensions::Dimensions; use geo::BoundingRect; use geo::HasDimensions; -use geo::MultiPoint; use geo::Point; use geo_types::Polygon; use geohash::decode_bbox; @@ -43,13 +41,14 @@ use geohash::encode; use geos::geo_types; use geos::geo_types::Coord; use geos::geo_types::LineString; -use geos::Geom; use geos::Geometry; use geozero::geojson::GeoJson; use geozero::wkb::Ewkb; use geozero::wkb::Wkb; use geozero::CoordDimensions; +use geozero::GeozeroGeometry; use geozero::ToGeo; +use geozero::ToGeos; use geozero::ToJson; use geozero::ToWkb; use geozero::ToWkt; @@ -115,20 +114,8 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } - - let srid = match read_ewkb_srid(&mut io::Cursor::new(&geometry)) { - Ok(srid) => srid, - _ => { - ctx.set_error( - builder.len(), - ErrorCode::GeometryError("input geometry must has the correct SRID") - .to_string(), - ); - builder.commit_row(); - return; - } - }; - + let ewkb = Ewkb(geometry); + let srid = ewkb.to_geos().unwrap().srid(); match Ewkb(geometry).to_ewkb(CoordDimensions::xy(), srid) { Ok(wkb) => builder.put_slice(wkb.as_slice()), Err(e) => { @@ -177,18 +164,7 @@ pub fn register(registry: &mut FunctionRegistry) { } } - let srid = match read_ewkb_srid(&mut io::Cursor::new(&geometry)) { - Ok(srid) => srid, - _ => { - ctx.set_error( - builder.len(), - ErrorCode::GeometryError("input geometry must has the correct SRID") - .to_string(), - ); - builder.commit_row(); - return; - } - }; + let srid = Ewkb(geometry).to_geo().unwrap().srid(); match Ewkb(geometry).to_ewkt(srid) { Ok(ewkt) => builder.put_str(&ewkt), @@ -234,19 +210,9 @@ pub fn register(registry: &mut FunctionRegistry) { } } - let geo: geo_types::Geometry = match Ewkb(geometry).to_geo() { - Ok(geo) => geo, - Err(e) => { - ctx.set_error( - builder.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ); - builder.commit_row(); - return; - } - }; - - let point = match >::try_into(geo) { + let point = match >::try_into( + Ewkb(geometry).to_geo().unwrap(), + ) { Ok(line_string) => line_string.points().last().unwrap(), Err(e) => { ctx.set_error( @@ -282,19 +248,9 @@ pub fn register(registry: &mut FunctionRegistry) { } } - let geo: geo_types::Geometry = match Ewkb(geometry).to_geo() { - Ok(geo) => geo, - Err(e) => { - ctx.set_error( - builder.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ); - builder.commit_row(); - return; - } - }; - - let point = match >::try_into(geo) { + let point = match >::try_into( + Ewkb(geometry).to_geo().unwrap(), + ) { Ok(line_string) => { let len = line_string.0.len() as i32; if index >= -len && index < len && index != 0 { @@ -340,34 +296,22 @@ pub fn register(registry: &mut FunctionRegistry) { registry.register_combine_nullable_1_arg::( "st_dimension", - |_, _| FunctionDomain::MayThrow, - vectorize_with_builder_1_arg::>( - |ewkb, output, ctx| { - let geo: geo_types::Geometry = match Ewkb(ewkb).to_geo() { - Ok(geo) => geo, - Err(e) => { - ctx.set_error( - output.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ); - output.push_null(); - return; - } - }; - - let dimension: Option = match geo.dimensions() { - Dimensions::Empty => None, - Dimensions::ZeroDimensional => Some(0), - Dimensions::OneDimensional => Some(1), - Dimensions::TwoDimensional => Some(2), - }; + |_, _| FunctionDomain::Full, + vectorize_with_builder_1_arg::>(|ewkb, output, _| { + let geo: geo_types::Geometry = Ewkb(ewkb).to_geo().unwrap(); + + let dimension: Option = match geo.dimensions() { + Dimensions::Empty => None, + Dimensions::ZeroDimensional => Some(0), + Dimensions::OneDimensional => Some(1), + Dimensions::TwoDimensional => Some(2), + }; - match dimension { - Some(dimension) => output.push(dimension), - None => output.push_null(), - } - }, - ), + match dimension { + Some(dimension) => output.push(dimension), + None => output.push_null(), + } + }), ); registry.register_passthrough_nullable_1_arg::( @@ -469,14 +413,7 @@ pub fn register(registry: &mut FunctionRegistry) { } } let geom = geo::Geometry::from(Point::new(longitude.0, latitude.0)); - match geom.to_wkb(CoordDimensions::xy()) { - Ok(data) => { - builder.put_slice(data.as_slice()) - }, - Err(e) => { - ctx.set_error(builder.len(), e.to_string()) - } - } + builder.put_slice(geom.to_wkb(CoordDimensions::xy()).unwrap().as_slice()); builder.commit_row(); }) ); @@ -492,19 +429,10 @@ pub fn register(registry: &mut FunctionRegistry) { } } - let line_string = match Wkb(wkb).to_geo() { - Ok(geo) => geo.try_into(), - Err(e) => { - ctx.set_error( - builder.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ); - builder.commit_row(); - return; - } - }; - - let polygon = line_string + let polygon = Wkb(wkb) + .to_geo() + .unwrap() + .try_into() .map_err(|e: geo_types::Error| ErrorCode::GeometryError(e.to_string())) .and_then(|line_string: LineString| { let points = line_string.into_points(); @@ -536,7 +464,7 @@ pub fn register(registry: &mut FunctionRegistry) { registry.register_passthrough_nullable_2_arg::( "st_makeline", - |_, _, _| FunctionDomain::Full, + |_, _, _| FunctionDomain::MayThrow, vectorize_with_builder_2_arg::( |left_ewkb, right_ewkb, builder, ctx| { if let Some(validity) = &ctx.validity { @@ -545,68 +473,32 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } - let srid: Option; - let params = &vec![left_ewkb, right_ewkb]; - let geos: Vec = - match binary_to_geos(params) - { - Ok(geos) => { - match get_shared_srid(&geos){ - Ok(s) => { - srid = s; - geos - }, - Err(e) => { - ctx.set_error(builder.len(), ErrorCode::GeometryError(e).to_string()); - builder.commit_row(); - return; - } - } - }, - Err(e) => { - ctx.set_error(builder.len(), ErrorCode::GeometryError(e.to_string()).to_string()); - builder.commit_row(); - return; - } - }; + let left_geo = Ewkb(left_ewkb); + let right_geo = Ewkb(right_ewkb); + let geos = &vec![left_geo.to_geos().unwrap(), right_geo.to_geos().unwrap()]; + // check srid + let srid = match get_shared_srid(geos) { + Ok(srid) => srid, + Err(e) => { + ctx.set_error(builder.len(), ErrorCode::GeometryError(e).to_string()); + builder.commit_row(); + return; + } + }; let mut coords: Vec = vec![]; - for geometry in geos.into_iter() { - let g : geo_types::Geometry = (&geometry).try_into().unwrap(); + for geometry in geos.iter() { + let g : geo_types::Geometry = geometry.try_into().unwrap(); match g { - geo_types::Geometry::Point(_) => { - let point: Point = match g.try_into() { - Ok(point) => point, - Err(e) => { - ctx.set_error(builder.len(), ErrorCode::GeometryError(e.to_string()).to_string()); - builder.commit_row(); - return; - } - }; - coords.push(point.into()); + geo_types::Geometry::Point(point) => { + coords.push(point.0); }, - geo_types::Geometry::LineString(_)=> { - let line: LineString = match g.try_into() { - Ok(line) => line, - Err(e) => { - ctx.set_error(builder.len(), ErrorCode::GeometryError(e.to_string()).to_string()); - builder.commit_row(); - return; - } - }; - coords.append(&mut line.into_inner()); + geo_types::Geometry::LineString(line)=> { + coords.append(&mut line.clone().into_inner()); }, - geo_types::Geometry::MultiPoint(_)=> { - let multi_point: MultiPoint = match g.try_into() { - Ok(multi_point) => multi_point, - Err(e) => { - ctx.set_error(builder.len(), ErrorCode::GeometryError(e.to_string()).to_string()); - builder.commit_row(); - return; - } - }; + geo_types::Geometry::MultiPoint(multi_point)=> { for point in multi_point.into_iter() { - coords.push(point.into()); + coords.push(point.0); } }, _ => { @@ -699,8 +591,8 @@ pub fn register(registry: &mut FunctionRegistry) { } } - let binary = match hex::decode(str) { - Ok(binary) => binary, + let ewkb = match hex::decode(str) { + Ok(binary) => Ewkb(binary), Err(e) => { ctx.set_error( builder.len(), @@ -710,21 +602,19 @@ pub fn register(registry: &mut FunctionRegistry) { return; } }; - - let srid = match read_ewkb_srid(&mut io::Cursor::new(&binary)) { - Ok(srid) => srid, - _ => { + let geos = match ewkb.to_geos() { + Ok(geos) => geos, + Err(e) => { ctx.set_error( builder.len(), - ErrorCode::GeometryError("input geometry must has the correct SRID") - .to_string(), + ErrorCode::GeometryError(e.to_string()).to_string(), ); builder.commit_row(); return; } }; - match Ewkb(binary).to_ewkb(CoordDimensions::xy(), srid) { + match geos.to_ewkb(CoordDimensions::xy(), geos.srid()) { Ok(ewkb) => { builder.put_slice(ewkb.as_slice()); } @@ -749,13 +639,29 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } + let ewkb = Ewkb(binary); + let geos = match ewkb.to_geos() { + Ok(geos) => geos, + Err(e) => { + ctx.set_error( + builder.len(), + ErrorCode::GeometryError(e.to_string()).to_string(), + ); + builder.commit_row(); + return; + } + }; - match binary_to_geometry_impl(binary, None) { - Ok(data) => builder.put_slice(data.as_slice()), - Err(e) => ctx.set_error( - builder.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ), + match geos.to_ewkb(CoordDimensions::xy(), geos.srid()) { + Ok(ewkb) => { + builder.put_slice(ewkb.as_slice()); + } + Err(e) => { + ctx.set_error( + builder.len(), + ErrorCode::GeometryError(e.to_string()).to_string(), + ); + } } builder.commit_row(); }), @@ -811,12 +717,29 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } - match binary_to_geometry_impl(binary, Some(srid)) { - Ok(data) => builder.put_slice(data.as_slice()), - Err(e) => ctx.set_error( - builder.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ), + let ewkb = Ewkb(binary); + let geos = match ewkb.to_geos() { + Ok(geos) => geos, + Err(e) => { + ctx.set_error( + builder.len(), + ErrorCode::GeometryError(e.to_string()).to_string(), + ); + builder.commit_row(); + return; + } + }; + + match geos.to_ewkb(CoordDimensions::xy(), Some(srid)) { + Ok(ewkb) => { + builder.put_slice(ewkb.as_slice()); + } + Err(e) => { + ctx.set_error( + builder.len(), + ErrorCode::GeometryError(e.to_string()).to_string(), + ); + } } builder.commit_row(); }, @@ -833,6 +756,7 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } + match parse_to_ewkb(wkt.as_bytes(), None) { Ok(data) => builder.put_slice(data.as_slice()), Err(e) => ctx.set_error( @@ -878,19 +802,9 @@ pub fn register(registry: &mut FunctionRegistry) { } } - let geo: geo_types::Geometry = match Ewkb(geometry).to_geo() { - Ok(geo) => geo, - Err(e) => { - ctx.set_error( - builder.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ); - builder.commit_row(); - return; - } - }; - - let point = match >::try_into(geo) { + let point = match >::try_into( + Ewkb(geometry).to_geo().unwrap(), + ) { Ok(line_string) => line_string.points().next().unwrap(), Err(e) => { ctx.set_error( @@ -925,19 +839,9 @@ pub fn register(registry: &mut FunctionRegistry) { } } - let geo: geo_types::Geometry = match Ewkb(geometry).to_geo() { - Ok(geo) => geo, - Err(e) => { - ctx.set_error( - builder.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ); - builder.push_null(); - return; - } - }; - - match >::try_into(geo) { + match >::try_into( + Ewkb(geometry).to_geo().unwrap(), + ) { Ok(point) => builder.push(F64::from(AsPrimitive::::as_(point.x()))), Err(e) => ctx.set_error( builder.len(), @@ -960,19 +864,9 @@ pub fn register(registry: &mut FunctionRegistry) { } } - let geo: geo_types::Geometry = match Ewkb(geometry).to_geo() { - Ok(geo) => geo, - Err(e) => { - ctx.set_error( - builder.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ); - builder.push_null(); - return; - } - }; - - match >::try_into(geo) { + match >::try_into( + Ewkb(geometry).to_geo().unwrap(), + ) { Ok(point) => builder.push(F64::from(AsPrimitive::::as_(point.y()))), Err(e) => ctx.set_error( builder.len(), @@ -985,7 +879,7 @@ pub fn register(registry: &mut FunctionRegistry) { registry.register_combine_nullable_1_arg::( "st_srid", - |_, _| FunctionDomain::MayThrow, + |_, _| FunctionDomain::Full, vectorize_with_builder_1_arg::>( |geometry, output, ctx| { if let Some(validity) = &ctx.validity { @@ -994,25 +888,35 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } - match read_ewkb_srid(&mut io::Cursor::new(&geometry)) { - Ok(srid) => { - output.push(srid.unwrap_or(4326)); - } - Err(e) => { - ctx.set_error( - output.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ); - output.push(0); + + output.push(Ewkb(geometry).to_geos().unwrap().srid().unwrap_or(4326)); + }, + ), + ); + + registry.register_combine_nullable_1_arg::, _, _>( + "st_xmax", + |_, _| FunctionDomain::Full, + vectorize_with_builder_1_arg::>>( + |geometry, builder, ctx| { + if let Some(validity) = &ctx.validity { + if !validity.get_bit(builder.len()) { + builder.push_null(); + return; } + } + + match st_extreme(&Ewkb(geometry).to_geo().unwrap(), Axis::X, Extremum::Max) { + None => builder.push_null(), + Some(x_max) => builder.push(F64::from(AsPrimitive::::as_(x_max))), }; }, ), ); registry.register_combine_nullable_1_arg::, _, _>( - "st_xmax", - |_, _| FunctionDomain::MayThrow, + "st_xmin", + |_, _| FunctionDomain::Full, vectorize_with_builder_1_arg::>>( |geometry, builder, ctx| { if let Some(validity) = &ctx.validity { @@ -1021,22 +925,49 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } + match st_extreme(&Ewkb(geometry).to_geo().unwrap(), Axis::X, Extremum::Min) { + None => builder.push_null(), + Some(x_min) => builder.push(F64::from(AsPrimitive::::as_(x_min))), + }; + }, + ), + ); - let geo: geo_types::Geometry = match Ewkb(geometry).to_geo() { - Ok(geo) => geo, - Err(e) => { - ctx.set_error( - builder.len(), - ErrorCode::GeometryError(e.to_string()).to_string(), - ); + registry.register_combine_nullable_1_arg::, _, _>( + "st_ymax", + |_, _| FunctionDomain::Full, + vectorize_with_builder_1_arg::>>( + |geometry, builder, ctx| { + if let Some(validity) = &ctx.validity { + if !validity.get_bit(builder.len()) { builder.push_null(); return; } + } + + match st_extreme(&Ewkb(geometry).to_geo().unwrap(), Axis::Y, Extremum::Max) { + None => builder.push_null(), + Some(y_max) => builder.push(F64::from(AsPrimitive::::as_(y_max))), }; + }, + ), + ); - match st_xmax(&geo) { + registry.register_combine_nullable_1_arg::, _, _>( + "st_ymin", + |_, _| FunctionDomain::Full, + vectorize_with_builder_1_arg::>>( + |geometry, builder, ctx| { + if let Some(validity) = &ctx.validity { + if !validity.get_bit(builder.len()) { + builder.push_null(); + return; + } + } + + match st_extreme(&Ewkb(geometry).to_geo().unwrap(), Axis::Y, Extremum::Min) { None => builder.push_null(), - Some(x_max) => builder.push(F64::from(AsPrimitive::::as_(x_max))), + Some(y_min) => builder.push(F64::from(AsPrimitive::::as_(y_min))), }; }, ), @@ -1120,21 +1051,21 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } - let srid = match read_ewkb_srid(&mut io::Cursor::new(&binary)) { - Ok(srid) => srid, - _ => { + let ewkb = Ewkb(binary); + let geos = match ewkb.to_geos() { + Ok(geos) => geos, + Err(e) => { ctx.set_error( builder.len(), - ErrorCode::GeometryError("input geometry must has the correct SRID") - .to_string(), + ErrorCode::GeometryError(e.to_string()).to_string(), ); builder.commit_row(); return; } }; - match binary_to_geometry_impl(binary, srid) { - Ok(data) => builder.put_slice(data.as_slice()), + match geos.to_ewkb(CoordDimensions::xy(), geos.srid()) { + Ok(ewkb) => builder.put_slice(ewkb.as_slice()), Err(e) => ctx.set_error( builder.len(), ErrorCode::GeometryError(e.to_string()).to_string(), @@ -1156,13 +1087,25 @@ pub fn register(registry: &mut FunctionRegistry) { } } - match binary_to_geometry_impl(binary, Some(srid)) { - Ok(data) => builder.put_slice(data.as_slice()), + let geo = match Ewkb(binary).to_geo() { + Ok(geo) => geo, + Err(e) => { + ctx.set_error( + builder.len(), + ErrorCode::GeometryError(e.to_string()).to_string(), + ); + builder.commit_row(); + return; + } + }; + + match geo.to_ewkb(CoordDimensions::xy(), Some(srid)) { + Ok(ewkb) => builder.put_slice(ewkb.as_slice()), Err(e) => ctx.set_error( builder.len(), ErrorCode::GeometryError(e.to_string()).to_string(), ), - } + }; builder.commit_row(); }, ), @@ -1315,18 +1258,19 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } - let srid = match read_ewkb_srid(&mut io::Cursor::new(&binary)) { - Ok(srid) => srid, + let ewkb = Ewkb(binary); + let geos = match ewkb.to_geos() { + Ok(geos) => geos, Err(_) => { output.push_null(); return; } }; - match binary_to_geometry_impl(binary, srid) { - Ok(data) => { + match geos.to_ewkb(CoordDimensions::xy(), geos.srid()) { + Ok(ewkb) => { output.validity.push(true); - output.builder.put_slice(data.as_slice()); + output.builder.put_slice(ewkb.as_slice()); output.builder.commit_row(); } Err(_) => output.push_null(), @@ -1346,11 +1290,18 @@ pub fn register(registry: &mut FunctionRegistry) { return; } } + let geo = match Ewkb(binary).to_geo() { + Ok(geo) => geo, + Err(_) => { + output.push_null(); + return; + } + }; - match binary_to_geometry_impl(binary, Some(srid)) { - Ok(data) => { + match geo.to_ewkb(CoordDimensions::xy(), Some(srid)) { + Ok(ewkb) => { output.validity.push(true); - output.builder.put_slice(data.as_slice()); + output.builder.put_slice(ewkb.as_slice()); output.builder.commit_row(); } Err(_) => output.push_null(), @@ -1463,36 +1414,13 @@ pub fn register(registry: &mut FunctionRegistry) { // format!("EPSG:{}", srid) // } -#[inline] -fn binary_to_geos<'a>(binaries: &'a Vec<&'a [u8]>) -> Result>, String> { - let mut geos: Vec = Vec::with_capacity(binaries.len()); - let mut srid: Option = None; - for (index, binary) in binaries.iter().enumerate() { - match Geometry::new_from_wkb(binary) { - Ok(data) => { - if index == 0 { - srid = data.get_srid().map_or_else(|_| None, |v| Some(v as i32)); - } else { - let t_srid = data.get_srid().map_or_else(|_| None, |v| Some(v as i32)); - if !srid.eq(&t_srid) { - return Err("Srid does not match!".to_string()); - } - } - geos.push(data) - } - Err(e) => return Err(e.to_string()), - }; - } - Ok(geos) -} - #[inline] fn get_shared_srid(geometries: &Vec) -> Result, String> { let mut srid: Option = None; let mut error_srid: String = String::new(); let check_srid = geometries.windows(2).all(|w| { - let v1 = w[0].get_srid().map_or_else(|_| None, |v| Some(v as i32)); - let v2 = w[1].get_srid().map_or_else(|_| None, |v| Some(v as i32)); + let v1 = w[0].srid(); + let v2 = w[1].srid(); match v1.eq(&v2) { true => { srid = v1; @@ -1512,29 +1440,15 @@ fn get_shared_srid(geometries: &Vec) -> Result, String> { pub fn ewkb_to_json(buf: &[u8]) -> databend_common_exception::Result { Ewkb(buf) - .to_geo() + .to_geos() .map_err(|e| ErrorCode::GeometryError(e.to_string())) - .and_then(|geo| { - geo.to_json() + .and_then(|geos| { + geos.to_json() .map_err(|e| ErrorCode::GeometryError(e.to_string())) .map(|json: String| json) }) } -fn binary_to_geometry_impl( - binary: &[u8], - srid: Option, -) -> databend_common_exception::Result> { - let ewkb_srid = match read_ewkb_srid(&mut io::Cursor::new(&binary)) { - Ok(srid) => srid, - Err(e) => return Err(ErrorCode::GeometryError(e.to_string())), - }; - match Ewkb(&binary).to_ewkb(CoordDimensions::xy(), srid.or(ewkb_srid)) { - Ok(ewkb) => Ok(ewkb), - Err(e) => Err(ErrorCode::GeometryError(e.to_string())), - } -} - /// The argument str must be a string expression that represents a valid geometric object in one of the following formats: /// /// WKT (well-known text). @@ -1550,24 +1464,23 @@ fn str_to_geometry_impl( Ok(geo_types) => geo_types, Err(e) => return Err(ErrorCode::GeometryError(e.to_string())), }; - let ewkb = match geo_type { GeometryDataType::WKT | GeometryDataType::EWKT => parse_to_ewkb(str.as_bytes(), srid), GeometryDataType::GEOJSON => GeoJson(str) .to_ewkb(CoordDimensions::xy(), srid) .map_err(|e| ErrorCode::GeometryError(e.to_string())), GeometryDataType::WKB | GeometryDataType::EWKB => { - let binary = match hex::decode(str) { - Ok(binary) => binary, + let ewkb = match hex::decode(str) { + Ok(binary) => Ewkb(binary), Err(e) => return Err(ErrorCode::GeometryError(e.to_string())), }; - let ewkb_srid = match read_ewkb_srid(&mut io::Cursor::new(&binary)) { - Ok(ewkb_srid) => ewkb_srid, + let geos = match ewkb.to_geos() { + Ok(geos) => geos, Err(e) => return Err(ErrorCode::GeometryError(e.to_string())), }; - Ewkb(binary) - .to_ewkb(CoordDimensions::xy(), srid.or(ewkb_srid)) + + geos.to_ewkb(CoordDimensions::xy(), srid.or(geos.srid())) .map_err(|e| ErrorCode::GeometryError(e.to_string())) } }; @@ -1609,67 +1522,150 @@ fn point_to_geohash( } } -fn st_xmax(geometry: &geo_types::Geometry) -> Option { +fn st_extreme(geometry: &geo_types::Geometry, axis: Axis, extremum: Extremum) -> Option { match geometry { - geo_types::Geometry::Point(point) => Some(point.x()), + geo_types::Geometry::Point(point) => { + let coord = match axis { + Axis::X => point.x(), + Axis::Y => point.y(), + }; + Some(coord) + } geo_types::Geometry::MultiPoint(multi_point) => { - let mut xmax: Option = None; + let mut extreme_coord: Option = None; for point in multi_point { - if let Some(x) = st_xmax(&geo_types::Geometry::Point(*point)) { - if let Some(existing_xmax) = xmax { - xmax = Some(existing_xmax.max(x)); - } else { - xmax = Some(x); - } + if let Some(coord) = st_extreme(&geo_types::Geometry::Point(*point), axis, extremum) + { + extreme_coord = match extreme_coord { + Some(existing) => match extremum { + Extremum::Max => Some(existing.max(coord)), + Extremum::Min => Some(existing.min(coord)), + }, + None => Some(coord), + }; } } - xmax + extreme_coord + } + geo_types::Geometry::Line(line) => { + let bounding_rect = line.bounding_rect(); + let coord = match axis { + Axis::X => match extremum { + Extremum::Max => bounding_rect.max().x, + Extremum::Min => bounding_rect.min().x, + }, + Axis::Y => match extremum { + Extremum::Max => bounding_rect.max().y, + Extremum::Min => bounding_rect.min().y, + }, + }; + Some(coord) } - geo_types::Geometry::Line(line) => Some(line.bounding_rect().max().x), geo_types::Geometry::MultiLineString(multi_line) => { - let mut xmax: Option = None; + let mut extreme_coord: Option = None; for line in multi_line { - if let Some(x) = st_xmax(&geo_types::Geometry::LineString(line.clone())) { - if let Some(existing_xmax) = xmax { - xmax = Some(existing_xmax.max(x)); - } else { - xmax = Some(x); - } + if let Some(coord) = st_extreme( + &geo_types::Geometry::LineString(line.clone()), + axis, + extremum, + ) { + extreme_coord = match extreme_coord { + Some(existing) => match extremum { + Extremum::Max => Some(existing.max(coord)), + Extremum::Min => Some(existing.min(coord)), + }, + None => Some(coord), + }; } } - xmax + extreme_coord + } + geo_types::Geometry::Polygon(polygon) => { + let bounding_rect = polygon.bounding_rect().unwrap(); + let coord = match axis { + Axis::X => match extremum { + Extremum::Max => bounding_rect.max().x, + Extremum::Min => bounding_rect.min().x, + }, + Axis::Y => match extremum { + Extremum::Max => bounding_rect.max().y, + Extremum::Min => bounding_rect.min().y, + }, + }; + Some(coord) } - geo_types::Geometry::Polygon(polygon) => Some(polygon.bounding_rect().unwrap().max().x), geo_types::Geometry::MultiPolygon(multi_polygon) => { - let mut xmax: Option = None; + let mut extreme_coord: Option = None; for polygon in multi_polygon { - if let Some(x) = st_xmax(&geo_types::Geometry::Polygon(polygon.clone())) { - if let Some(existing_xmax) = xmax { - xmax = Some(existing_xmax.max(x)); - } else { - xmax = Some(x); - } + if let Some(coord) = st_extreme( + &geo_types::Geometry::Polygon(polygon.clone()), + axis, + extremum, + ) { + extreme_coord = match extreme_coord { + Some(existing) => match extremum { + Extremum::Max => Some(existing.max(coord)), + Extremum::Min => Some(existing.min(coord)), + }, + None => Some(coord), + }; } } - xmax + extreme_coord } geo_types::Geometry::GeometryCollection(geometry_collection) => { - let mut xmax: Option = None; + let mut extreme_coord: Option = None; for geometry in geometry_collection { - if let Some(x) = st_xmax(geometry) { - if let Some(existing_xmax) = xmax { - xmax = Some(existing_xmax.max(x)); - } else { - xmax = Some(x); - } + if let Some(coord) = st_extreme(geometry, axis, extremum) { + extreme_coord = match extreme_coord { + Some(existing) => match extremum { + Extremum::Max => Some(existing.max(coord)), + Extremum::Min => Some(existing.min(coord)), + }, + None => Some(coord), + }; } } - xmax + extreme_coord } geo_types::Geometry::LineString(line_string) => { - line_string.bounding_rect().map(|rect| rect.max().x) + line_string.bounding_rect().map(|rect| match axis { + Axis::X => match extremum { + Extremum::Max => rect.max().x, + Extremum::Min => rect.min().x, + }, + Axis::Y => match extremum { + Extremum::Max => rect.max().y, + Extremum::Min => rect.min().y, + }, + }) + } + geo_types::Geometry::Rect(rect) => { + let coord = match axis { + Axis::X => match extremum { + Extremum::Max => rect.max().x, + Extremum::Min => rect.min().x, + }, + Axis::Y => match extremum { + Extremum::Max => rect.max().y, + Extremum::Min => rect.min().y, + }, + }; + Some(coord) + } + geo_types::Geometry::Triangle(triangle) => { + let bounding_rect = triangle.bounding_rect(); + let coord = match axis { + Axis::X => match extremum { + Extremum::Max => bounding_rect.max().x, + Extremum::Min => bounding_rect.min().x, + }, + Axis::Y => match extremum { + Extremum::Max => bounding_rect.max().y, + Extremum::Min => bounding_rect.min().y, + }, + }; + Some(coord) } - geo_types::Geometry::Rect(rect) => Some(rect.max().x), - geo_types::Geometry::Triangle(triangle) => Some(triangle.bounding_rect().max().x), } } diff --git a/src/query/functions/tests/it/scalars/geometry.rs b/src/query/functions/tests/it/scalars/geometry.rs index 7ad6f52f95c36..5c5c2ee7d4944 100644 --- a/src/query/functions/tests/it/scalars/geometry.rs +++ b/src/query/functions/tests/it/scalars/geometry.rs @@ -50,6 +50,9 @@ fn test_geometry() { test_st_geometryfromwkb(file); test_st_geometryfromwkt(file); test_st_xmax(file); + test_st_xmin(file); + test_st_ymax(file); + test_st_ymin(file); // test_st_transform(file); } @@ -475,7 +478,79 @@ fn test_st_xmax(file: &mut impl Write) { ); run_ast( file, - "st_xmax(to_geometry('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)'))", + "st_xmax(to_geometry('MULTILINESTRING((10 10, 20 20, 10 40), EMPTY)'))", + &[], + ); +} + +fn test_st_xmin(file: &mut impl Write) { + run_ast(file, "st_xmin(to_geometry('POINT(-180 0)'))", &[]); + run_ast( + file, + "st_xmin(to_geometry('LINESTRING(-179 0, 179 0)'))", + &[], + ); + run_ast( + file, + "st_xmin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))'))", + &[], + ); + run_ast( + file, + "st_xmin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)'))", + &[], + ); + run_ast( + file, + "st_xmin(to_geometry('MULTILINESTRING((10 10, 20 20, 10 40), EMPTY)'))", + &[], + ); +} + +fn test_st_ymax(file: &mut impl Write) { + run_ast(file, "st_ymax(to_geometry('POINT(-180 0)'))", &[]); + run_ast( + file, + "st_ymax(to_geometry('LINESTRING(-179 1, 179 20)'))", + &[], + ); + run_ast( + file, + "st_ymax(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))'))", + &[], + ); + run_ast( + file, + "st_ymax(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)'))", + &[], + ); + run_ast( + file, + "st_ymax(to_geometry('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)'))", + &[], + ); +} + +fn test_st_ymin(file: &mut impl Write) { + run_ast(file, "st_ymin(to_geometry('POINT(-180 0)'))", &[]); + run_ast( + file, + "st_ymin(to_geometry('LINESTRING(-179 1, 179 20)'))", + &[], + ); + run_ast( + file, + "st_ymin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))'))", + &[], + ); + run_ast( + file, + "st_ymin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)'))", + &[], + ); + run_ast( + file, + "st_ymin(to_geometry('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)'))", &[], ); } diff --git a/src/query/functions/tests/it/scalars/testdata/function_list.txt b/src/query/functions/tests/it/scalars/testdata/function_list.txt index fd840cdff97f6..952d380d2c615 100644 --- a/src/query/functions/tests/it/scalars/testdata/function_list.txt +++ b/src/query/functions/tests/it/scalars/testdata/function_list.txt @@ -3567,8 +3567,14 @@ Functions overloads: 1 st_x(Geometry NULL) :: Float64 NULL 0 st_xmax(Geometry) :: Float64 NULL 1 st_xmax(Geometry NULL) :: Float64 NULL +0 st_xmin(Geometry) :: Float64 NULL +1 st_xmin(Geometry NULL) :: Float64 NULL 0 st_y(Geometry) :: Float64 NULL 1 st_y(Geometry NULL) :: Float64 NULL +0 st_ymax(Geometry) :: Float64 NULL +1 st_ymax(Geometry NULL) :: Float64 NULL +0 st_ymin(Geometry) :: Float64 NULL +1 st_ymin(Geometry NULL) :: Float64 NULL 0 strcmp(String, String) :: Int8 1 strcmp(String NULL, String NULL) :: Int8 NULL 0 string_to_h3(String) :: UInt64 diff --git a/src/query/functions/tests/it/scalars/testdata/geometry.txt b/src/query/functions/tests/it/scalars/testdata/geometry.txt index 5b2d4fd56f12d..cc4cd0fa0cb3d 100644 --- a/src/query/functions/tests/it/scalars/testdata/geometry.txt +++ b/src/query/functions/tests/it/scalars/testdata/geometry.txt @@ -10,10 +10,10 @@ output : 0101000020E61000006666666666965EC06666666666C64240 ast : st_asewkb(to_geometry('SRID=0;LINESTRING(0.75 0.75, -10 20)')) raw expr : st_asewkb(to_geometry('SRID=0;LINESTRING(0.75 0.75, -10 20)')) checked expr : st_asewkb(to_geometry("SRID=0;LINESTRING(0.75 0.75, -10 20)")) -optimized expr : 01020000200000000002000000000000000000E83F000000000000E83F00000000000024C00000000000003440 +optimized expr : 010200000002000000000000000000E83F000000000000E83F00000000000024C00000000000003440 output type : Binary output domain : Undefined -output : 01020000200000000002000000000000000000E83F000000000000E83F00000000000024C00000000000003440 +output : 010200000002000000000000000000E83F000000000000E83F00000000000024C00000000000003440 ast : st_aswkb(to_geometry('POINT(-122.35 37.55)')) @@ -892,12 +892,147 @@ output domain : {40..=40} output : 40 -ast : st_xmax(to_geometry('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) -raw expr : st_xmax(to_geometry('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) -checked expr : st_xmax(to_geometry("MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)")) +ast : st_xmax(to_geometry('MULTILINESTRING((10 10, 20 20, 10 40), EMPTY)')) +raw expr : st_xmax(to_geometry('MULTILINESTRING((10 10, 20 20, 10 40), EMPTY)')) +checked expr : st_xmax(to_geometry("MULTILINESTRING((10 10, 20 20, 10 40), EMPTY)")) +optimized expr : 20_f64 +output type : Float64 NULL +output domain : {20..=20} +output : 20 + + +ast : st_xmin(to_geometry('POINT(-180 0)')) +raw expr : st_xmin(to_geometry('POINT(-180 0)')) +checked expr : st_xmin(to_geometry("POINT(-180 0)")) +optimized expr : -180_f64 +output type : Float64 NULL +output domain : {-180..=-180} +output : -180 + + +ast : st_xmin(to_geometry('LINESTRING(-179 0, 179 0)')) +raw expr : st_xmin(to_geometry('LINESTRING(-179 0, 179 0)')) +checked expr : st_xmin(to_geometry("LINESTRING(-179 0, 179 0)")) +optimized expr : -179_f64 +output type : Float64 NULL +output domain : {-179..=-179} +output : -179 + + +ast : st_xmin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))')) +raw expr : st_xmin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))')) +checked expr : st_xmin(to_geometry("GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))")) +optimized expr : 10_f64 +output type : Float64 NULL +output domain : {10..=10} +output : 10 + + +ast : st_xmin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)')) +raw expr : st_xmin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)')) +checked expr : st_xmin(to_geometry("GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)")) +optimized expr : 10_f64 +output type : Float64 NULL +output domain : {10..=10} +output : 10 + + +ast : st_xmin(to_geometry('MULTILINESTRING((10 10, 20 20, 10 40), EMPTY)')) +raw expr : st_xmin(to_geometry('MULTILINESTRING((10 10, 20 20, 10 40), EMPTY)')) +checked expr : st_xmin(to_geometry("MULTILINESTRING((10 10, 20 20, 10 40), EMPTY)")) +optimized expr : 10_f64 +output type : Float64 NULL +output domain : {10..=10} +output : 10 + + +ast : st_ymax(to_geometry('POINT(-180 0)')) +raw expr : st_ymax(to_geometry('POINT(-180 0)')) +checked expr : st_ymax(to_geometry("POINT(-180 0)")) +optimized expr : 0_f64 +output type : Float64 NULL +output domain : {0..=0} +output : 0 + + +ast : st_ymax(to_geometry('LINESTRING(-179 1, 179 20)')) +raw expr : st_ymax(to_geometry('LINESTRING(-179 1, 179 20)')) +checked expr : st_ymax(to_geometry("LINESTRING(-179 1, 179 20)")) optimized expr : 20_f64 output type : Float64 NULL output domain : {20..=20} output : 20 +ast : st_ymax(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))')) +raw expr : st_ymax(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))')) +checked expr : st_ymax(to_geometry("GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))")) +optimized expr : 45_f64 +output type : Float64 NULL +output domain : {45..=45} +output : 45 + + +ast : st_ymax(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)')) +raw expr : st_ymax(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)')) +checked expr : st_ymax(to_geometry("GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)")) +optimized expr : 40_f64 +output type : Float64 NULL +output domain : {40..=40} +output : 40 + + +ast : st_ymax(to_geometry('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) +raw expr : st_ymax(to_geometry('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) +checked expr : st_ymax(to_geometry("MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)")) +optimized expr : 40_f64 +output type : Float64 NULL +output domain : {40..=40} +output : 40 + + +ast : st_ymin(to_geometry('POINT(-180 0)')) +raw expr : st_ymin(to_geometry('POINT(-180 0)')) +checked expr : st_ymin(to_geometry("POINT(-180 0)")) +optimized expr : 0_f64 +output type : Float64 NULL +output domain : {0..=0} +output : 0 + + +ast : st_ymin(to_geometry('LINESTRING(-179 1, 179 20)')) +raw expr : st_ymin(to_geometry('LINESTRING(-179 1, 179 20)')) +checked expr : st_ymin(to_geometry("LINESTRING(-179 1, 179 20)")) +optimized expr : 1_f64 +output type : Float64 NULL +output domain : {1..=1} +output : 1 + + +ast : st_ymin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))')) +raw expr : st_ymin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))')) +checked expr : st_ymin(to_geometry("GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))")) +optimized expr : 10_f64 +output type : Float64 NULL +output domain : {10..=10} +output : 10 + + +ast : st_ymin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)')) +raw expr : st_ymin(to_geometry('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)')) +checked expr : st_ymin(to_geometry("GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)")) +optimized expr : 10_f64 +output type : Float64 NULL +output domain : {10..=10} +output : 10 + + +ast : st_ymin(to_geometry('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) +raw expr : st_ymin(to_geometry('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) +checked expr : st_ymin(to_geometry("MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)")) +optimized expr : 10_f64 +output type : Float64 NULL +output domain : {10..=10} +output : 10 + + diff --git a/tests/sqllogictests/suites/query/functions/02_0060_function_geometry.test b/tests/sqllogictests/suites/query/functions/02_0060_function_geometry.test index 357effd9b0c31..981591af887da 100644 --- a/tests/sqllogictests/suites/query/functions/02_0060_function_geometry.test +++ b/tests/sqllogictests/suites/query/functions/02_0060_function_geometry.test @@ -361,7 +361,7 @@ query T SELECT UPPER(TO_HEX(ST_ASEWKB(g))) FROM t1 ---- 0101000020E61000006666666666965EC06666666666C64240 -01020000200000000002000000000000000000E83F000000000000E83F00000000000024C00000000000003440 +010200000002000000000000000000E83F000000000000E83F00000000000024C00000000000003440 # srid=0 has't supported by geozero crate.See also: https://github.com/georust/geozero/pull/210/files query T @@ -483,6 +483,81 @@ SELECT ST_XMAX(TO_GEOMETRY('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) ---- 20.0 +query T +SELECT ST_XMIN(TO_GEOMETRY('POINT(-180 0)')) +---- +-180.0 + +query T +SELECT ST_XMIN(TO_GEOMETRY('LINESTRING(-179 0, 179 0)')) +---- +-179.0 + +query T +SELECT ST_XMIN(TO_GEOMETRY('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))')) +---- +10.0 + +query T +SELECT ST_XMIN(TO_GEOMETRY('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)')) +---- +10.0 + +query T +SELECT ST_XMIN(TO_GEOMETRY('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) +---- +10.0 + +query T +SELECT ST_YMAX(TO_GEOMETRY('POINT(-180 0)')) +---- +0.0 + +query T +SELECT ST_YMAX(TO_GEOMETRY('LINESTRING(-179 10, 179 22)')) +---- +22.0 + +query T +SELECT ST_YMAX(TO_GEOMETRY('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))')) +---- +45.0 + +query T +SELECT ST_YMAX(TO_GEOMETRY('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)')) +---- +40.0 + +query T +SELECT ST_YMAX(TO_GEOMETRY('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) +---- +40.0 + +query T +SELECT ST_YMIN(TO_GEOMETRY('POINT(-180 0)')) +---- +0.0 + +query T +SELECT ST_YMIN(TO_GEOMETRY('LINESTRING(-179 10, 179 22)')) +---- +10.0 + +query T +SELECT ST_YMIN(TO_GEOMETRY('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POLYGON((40 40,20 45,45 30,40 40)))')) +---- +10.0 + +query T +SELECT ST_YMIN(TO_GEOMETRY('GEOMETRYCOLLECTION(POINT(40 10),LINESTRING(10 10,20 20,10 40),POINT EMPTY)')) +---- +10.0 + +query T +SELECT ST_YMIN(TO_GEOMETRY('MULTILINESTRING ((10 10, 20 20, 10 40), EMPTY)')) +---- +10.0 + statement ok SET enable_geo_create_table=0