diff --git a/Cargo.lock b/Cargo.lock index 55e8ca8e4b..e7f180eb17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1997,6 +1997,7 @@ dependencies = [ "common-version", "datafusion", "datatypes", + "derive_more", "geohash", "h3o", "jsonb", @@ -3413,6 +3414,27 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", + "unicode-xid", +] + [[package]] name = "diff" version = "0.1.13" diff --git a/src/common/function/Cargo.toml b/src/common/function/Cargo.toml index b2e9c5a98b..e9a3dd6b55 100644 --- a/src/common/function/Cargo.toml +++ b/src/common/function/Cargo.toml @@ -27,6 +27,7 @@ common-time.workspace = true common-version.workspace = true datafusion.workspace = true datatypes.workspace = true +derive_more = { version = "1", default-features = false, features = ["display"] } geohash = { version = "0.13", optional = true } h3o = { version = "0.6", optional = true } jsonb.workspace = true diff --git a/src/common/function/src/scalars/geo.rs b/src/common/function/src/scalars/geo.rs index 4b126f20f0..9e415a3fdd 100644 --- a/src/common/function/src/scalars/geo.rs +++ b/src/common/function/src/scalars/geo.rs @@ -17,7 +17,6 @@ mod geohash; mod h3; use geohash::GeohashFunction; -use h3::H3Function; use crate::function_registry::FunctionRegistry; @@ -25,7 +24,20 @@ pub(crate) struct GeoFunctions; impl GeoFunctions { pub fn register(registry: &FunctionRegistry) { + // geohash registry.register(Arc::new(GeohashFunction)); - registry.register(Arc::new(H3Function)); + // h3 family + registry.register(Arc::new(h3::H3LatLngToCell)); + registry.register(Arc::new(h3::H3LatLngToCellString)); + registry.register(Arc::new(h3::H3CellBase)); + registry.register(Arc::new(h3::H3CellCenterChild)); + registry.register(Arc::new(h3::H3CellCenterLat)); + registry.register(Arc::new(h3::H3CellCenterLng)); + registry.register(Arc::new(h3::H3CellIsPentagon)); + registry.register(Arc::new(h3::H3CellParent)); + registry.register(Arc::new(h3::H3CellResolution)); + registry.register(Arc::new(h3::H3CellToString)); + registry.register(Arc::new(h3::H3IsNeighbour)); + registry.register(Arc::new(h3::H3StringToCell)); } } diff --git a/src/common/function/src/scalars/geo/h3.rs b/src/common/function/src/scalars/geo/h3.rs index 26ec246997..672fbfd714 100644 --- a/src/common/function/src/scalars/geo/h3.rs +++ b/src/common/function/src/scalars/geo/h3.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::fmt; +use std::str::FromStr; use common_error::ext::{BoxedError, PlainError}; use common_error::status_code::StatusCode; @@ -22,23 +22,118 @@ use datafusion::logical_expr::Volatility; use datatypes::prelude::ConcreteDataType; use datatypes::scalars::ScalarVectorBuilder; use datatypes::value::Value; -use datatypes::vectors::{MutableVector, StringVectorBuilder, VectorRef}; -use h3o::{LatLng, Resolution}; +use datatypes::vectors::{ + BooleanVectorBuilder, Float64VectorBuilder, MutableVector, StringVectorBuilder, + UInt64VectorBuilder, UInt8VectorBuilder, VectorRef, +}; +use derive_more::Display; +use h3o::{CellIndex, LatLng, Resolution}; use snafu::{ensure, ResultExt}; use crate::function::{Function, FunctionContext}; -/// Function that returns [h3] encoding string for a given geospatial coordinate. +/// Function that returns [h3] encoding cellid for a given geospatial coordinate. /// /// [h3]: https://h3geo.org/ -#[derive(Clone, Debug, Default)] -pub struct H3Function; +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3LatLngToCell; -const NAME: &str = "h3"; - -impl Function for H3Function { +impl Function for H3LatLngToCell { fn name(&self) -> &str { - NAME + "h3_latlng_to_cell" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::uint64_datatype()) + } + + fn signature(&self) -> Signature { + let mut signatures = Vec::new(); + for coord_type in &[ + ConcreteDataType::float32_datatype(), + ConcreteDataType::float64_datatype(), + ] { + for resolution_type in &[ + ConcreteDataType::int8_datatype(), + ConcreteDataType::int16_datatype(), + ConcreteDataType::int32_datatype(), + ConcreteDataType::int64_datatype(), + ConcreteDataType::uint8_datatype(), + ConcreteDataType::uint16_datatype(), + ConcreteDataType::uint32_datatype(), + ConcreteDataType::uint64_datatype(), + ] { + signatures.push(TypeSignature::Exact(vec![ + // latitude + coord_type.clone(), + // longitude + coord_type.clone(), + // resolution + resolution_type.clone(), + ])); + } + } + Signature::one_of(signatures, Volatility::Stable) + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 3, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 3, provided : {}", + columns.len() + ), + } + ); + + let lat_vec = &columns[0]; + let lon_vec = &columns[1]; + let resolution_vec = &columns[2]; + + let size = lat_vec.len(); + let mut results = UInt64VectorBuilder::with_capacity(size); + + for i in 0..size { + let lat = lat_vec.get(i).as_f64_lossy(); + let lon = lon_vec.get(i).as_f64_lossy(); + let r = value_to_resolution(resolution_vec.get(i))?; + + let result = match (lat, lon) { + (Some(lat), Some(lon)) => { + let coord = LatLng::new(lat, lon) + .map_err(|e| { + BoxedError::new(PlainError::new( + format!("H3 error: {}", e), + StatusCode::EngineExecuteQuery, + )) + }) + .context(error::ExecuteSnafu)?; + let encoded: u64 = coord.to_cell(r).into(); + Some(encoded) + } + _ => None, + }; + + results.push(result); + } + + Ok(results.to_vector()) + } +} + +/// Function that returns [h3] encoding cellid in string form for a given +/// geospatial coordinate. +/// +/// [h3]: https://h3geo.org/ +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3LatLngToCellString; + +impl Function for H3LatLngToCellString { + fn name(&self) -> &str { + "h3_latlng_to_cell_string" } fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { @@ -95,17 +190,7 @@ impl Function for H3Function { for i in 0..size { let lat = lat_vec.get(i).as_f64_lossy(); let lon = lon_vec.get(i).as_f64_lossy(); - let r = match resolution_vec.get(i) { - Value::Int8(v) => v as u8, - Value::Int16(v) => v as u8, - Value::Int32(v) => v as u8, - Value::Int64(v) => v as u8, - Value::UInt8(v) => v, - Value::UInt16(v) => v as u8, - Value::UInt32(v) => v as u8, - Value::UInt64(v) => v as u8, - _ => unreachable!(), - }; + let r = value_to_resolution(resolution_vec.get(i))?; let result = match (lat, lon) { (Some(lat), Some(lon)) => { @@ -117,14 +202,6 @@ impl Function for H3Function { )) }) .context(error::ExecuteSnafu)?; - let r = Resolution::try_from(r) - .map_err(|e| { - BoxedError::new(PlainError::new( - format!("H3 error: {}", e), - StatusCode::EngineExecuteQuery, - )) - }) - .context(error::ExecuteSnafu)?; let encoded = coord.to_cell(r).to_string(); Some(encoded) } @@ -138,8 +215,585 @@ impl Function for H3Function { } } -impl fmt::Display for H3Function { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", NAME) +/// Function that converts cell id to its string form +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3CellToString; + +impl Function for H3CellToString { + fn name(&self) -> &str { + "h3_cell_to_string" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::string_datatype()) + } + + fn signature(&self) -> Signature { + signature_of_cell() + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 1, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 1, provided : {}", + columns.len() + ), + } + ); + + let cell_vec = &columns[0]; + let size = cell_vec.len(); + let mut results = StringVectorBuilder::with_capacity(size); + + for i in 0..size { + let cell_id_string = cell_from_value(cell_vec.get(i))?.map(|c| c.to_string()); + + results.push(cell_id_string.as_deref()); + } + + Ok(results.to_vector()) } } + +/// Function that converts cell string id to uint64 number +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3StringToCell; + +impl Function for H3StringToCell { + fn name(&self) -> &str { + "h3_string_to_cell" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::uint64_datatype()) + } + + fn signature(&self) -> Signature { + Signature::new( + TypeSignature::Exact(vec![ConcreteDataType::string_datatype()]), + Volatility::Stable, + ) + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 1, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 1, provided : {}", + columns.len() + ), + } + ); + + let string_vec = &columns[0]; + let size = string_vec.len(); + let mut results = UInt64VectorBuilder::with_capacity(size); + + for i in 0..size { + let cell = string_vec.get(i); + + let cell_id = match cell { + Value::String(v) => Some( + CellIndex::from_str(v.as_utf8()) + .map_err(|e| { + BoxedError::new(PlainError::new( + format!("H3 error: {}", e), + StatusCode::EngineExecuteQuery, + )) + }) + .context(error::ExecuteSnafu)? + .into(), + ), + _ => None, + }; + + results.push(cell_id); + } + + Ok(results.to_vector()) + } +} + +/// Function that returns centroid latitude of given cell id +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3CellCenterLat; + +impl Function for H3CellCenterLat { + fn name(&self) -> &str { + "h3_cell_center_lat" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::float64_datatype()) + } + + fn signature(&self) -> Signature { + signature_of_cell() + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 1, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 1, provided : {}", + columns.len() + ), + } + ); + + let cell_vec = &columns[0]; + let size = cell_vec.len(); + let mut results = Float64VectorBuilder::with_capacity(size); + + for i in 0..size { + let cell = cell_from_value(cell_vec.get(i))?; + let lat = cell.map(|cell| LatLng::from(cell).lat()); + + results.push(lat); + } + + Ok(results.to_vector()) + } +} + +/// Function that returns centroid longitude of given cell id +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3CellCenterLng; + +impl Function for H3CellCenterLng { + fn name(&self) -> &str { + "h3_cell_center_lng" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::float64_datatype()) + } + + fn signature(&self) -> Signature { + signature_of_cell() + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 1, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 1, provided : {}", + columns.len() + ), + } + ); + + let cell_vec = &columns[0]; + let size = cell_vec.len(); + let mut results = Float64VectorBuilder::with_capacity(size); + + for i in 0..size { + let cell = cell_from_value(cell_vec.get(i))?; + let lat = cell.map(|cell| LatLng::from(cell).lng()); + + results.push(lat); + } + + Ok(results.to_vector()) + } +} + +/// Function that returns resolution of given cell id +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3CellResolution; + +impl Function for H3CellResolution { + fn name(&self) -> &str { + "h3_cell_resolution" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::uint8_datatype()) + } + + fn signature(&self) -> Signature { + signature_of_cell() + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 1, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 1, provided : {}", + columns.len() + ), + } + ); + + let cell_vec = &columns[0]; + let size = cell_vec.len(); + let mut results = UInt8VectorBuilder::with_capacity(size); + + for i in 0..size { + let cell = cell_from_value(cell_vec.get(i))?; + let res = cell.map(|cell| cell.resolution().into()); + + results.push(res); + } + + Ok(results.to_vector()) + } +} + +/// Function that returns base cell of given cell id +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3CellBase; + +impl Function for H3CellBase { + fn name(&self) -> &str { + "h3_cell_base" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::uint8_datatype()) + } + + fn signature(&self) -> Signature { + signature_of_cell() + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 1, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 1, provided : {}", + columns.len() + ), + } + ); + + let cell_vec = &columns[0]; + let size = cell_vec.len(); + let mut results = UInt8VectorBuilder::with_capacity(size); + + for i in 0..size { + let cell = cell_from_value(cell_vec.get(i))?; + let res = cell.map(|cell| cell.base_cell().into()); + + results.push(res); + } + + Ok(results.to_vector()) + } +} + +/// Function that check if given cell id is a pentagon +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3CellIsPentagon; + +impl Function for H3CellIsPentagon { + fn name(&self) -> &str { + "h3_cell_is_pentagon" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::boolean_datatype()) + } + + fn signature(&self) -> Signature { + signature_of_cell() + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 1, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 1, provided : {}", + columns.len() + ), + } + ); + + let cell_vec = &columns[0]; + let size = cell_vec.len(); + let mut results = BooleanVectorBuilder::with_capacity(size); + + for i in 0..size { + let cell = cell_from_value(cell_vec.get(i))?; + let res = cell.map(|cell| cell.is_pentagon()); + + results.push(res); + } + + Ok(results.to_vector()) + } +} + +/// Function that returns center child cell of given cell id +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3CellCenterChild; + +impl Function for H3CellCenterChild { + fn name(&self) -> &str { + "h3_cell_center_child" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::uint64_datatype()) + } + + fn signature(&self) -> Signature { + signature_of_cell_and_resolution() + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 2, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 2, provided : {}", + columns.len() + ), + } + ); + + let cell_vec = &columns[0]; + let res_vec = &columns[1]; + let size = cell_vec.len(); + let mut results = UInt64VectorBuilder::with_capacity(size); + + for i in 0..size { + let cell = cell_from_value(cell_vec.get(i))?; + let res = value_to_resolution(res_vec.get(i))?; + let result = cell + .and_then(|cell| cell.center_child(res)) + .map(|c| c.into()); + + results.push(result); + } + + Ok(results.to_vector()) + } +} + +/// Function that returns parent cell of given cell id and resolution +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3CellParent; + +impl Function for H3CellParent { + fn name(&self) -> &str { + "h3_cell_parent" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::uint64_datatype()) + } + + fn signature(&self) -> Signature { + signature_of_cell_and_resolution() + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 2, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 2, provided : {}", + columns.len() + ), + } + ); + + let cell_vec = &columns[0]; + let res_vec = &columns[1]; + let size = cell_vec.len(); + let mut results = UInt64VectorBuilder::with_capacity(size); + + for i in 0..size { + let cell = cell_from_value(cell_vec.get(i))?; + let res = value_to_resolution(res_vec.get(i))?; + let result = cell.and_then(|cell| cell.parent(res)).map(|c| c.into()); + + results.push(result); + } + + Ok(results.to_vector()) + } +} + +/// Function that checks if two cells are neighbour +#[derive(Clone, Debug, Default, Display)] +#[display("{}", self.name())] +pub struct H3IsNeighbour; + +impl Function for H3IsNeighbour { + fn name(&self) -> &str { + "h3_is_neighbour" + } + + fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result { + Ok(ConcreteDataType::boolean_datatype()) + } + + fn signature(&self) -> Signature { + signature_of_double_cell() + } + + fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result { + ensure!( + columns.len() == 2, + InvalidFuncArgsSnafu { + err_msg: format!( + "The length of the args is not correct, expect 2, provided : {}", + columns.len() + ), + } + ); + + let cell_vec = &columns[0]; + let cell2_vec = &columns[1]; + let size = cell_vec.len(); + let mut results = BooleanVectorBuilder::with_capacity(size); + + for i in 0..size { + let result = match ( + cell_from_value(cell_vec.get(i))?, + cell_from_value(cell2_vec.get(i))?, + ) { + (Some(cell_this), Some(cell_that)) => { + let is_neighbour = cell_this + .is_neighbor_with(cell_that) + .map_err(|e| { + BoxedError::new(PlainError::new( + format!("H3 error: {}", e), + StatusCode::EngineExecuteQuery, + )) + }) + .context(error::ExecuteSnafu)?; + Some(is_neighbour) + } + _ => None, + }; + + results.push(result); + } + + Ok(results.to_vector()) + } +} + +fn value_to_resolution(v: Value) -> Result { + let r = match v { + Value::Int8(v) => v as u8, + Value::Int16(v) => v as u8, + Value::Int32(v) => v as u8, + Value::Int64(v) => v as u8, + Value::UInt8(v) => v, + Value::UInt16(v) => v as u8, + Value::UInt32(v) => v as u8, + Value::UInt64(v) => v as u8, + _ => unreachable!(), + }; + Resolution::try_from(r) + .map_err(|e| { + BoxedError::new(PlainError::new( + format!("H3 error: {}", e), + StatusCode::EngineExecuteQuery, + )) + }) + .context(error::ExecuteSnafu) +} + +fn signature_of_cell() -> Signature { + let mut signatures = Vec::new(); + for cell_type in &[ + ConcreteDataType::uint64_datatype(), + ConcreteDataType::int64_datatype(), + ] { + signatures.push(TypeSignature::Exact(vec![cell_type.clone()])); + } + + Signature::one_of(signatures, Volatility::Stable) +} + +fn signature_of_double_cell() -> Signature { + let mut signatures = Vec::new(); + let cell_types = &[ + ConcreteDataType::uint64_datatype(), + ConcreteDataType::int64_datatype(), + ]; + for cell_type in cell_types { + for cell_type2 in cell_types { + signatures.push(TypeSignature::Exact(vec![ + cell_type.clone(), + cell_type2.clone(), + ])); + } + } + + Signature::one_of(signatures, Volatility::Stable) +} + +fn signature_of_cell_and_resolution() -> Signature { + let mut signatures = Vec::new(); + for cell_type in &[ + ConcreteDataType::uint64_datatype(), + ConcreteDataType::int64_datatype(), + ] { + for resolution_type in &[ + ConcreteDataType::int8_datatype(), + ConcreteDataType::int16_datatype(), + ConcreteDataType::int32_datatype(), + ConcreteDataType::int64_datatype(), + ConcreteDataType::uint8_datatype(), + ConcreteDataType::uint16_datatype(), + ConcreteDataType::uint32_datatype(), + ConcreteDataType::uint64_datatype(), + ] { + signatures.push(TypeSignature::Exact(vec![ + cell_type.clone(), + resolution_type.clone(), + ])); + } + } + Signature::one_of(signatures, Volatility::Stable) +} + +fn cell_from_value(v: Value) -> Result> { + let cell = match v { + Value::Int64(v) => Some( + CellIndex::try_from(v as u64) + .map_err(|e| { + BoxedError::new(PlainError::new( + format!("H3 error: {}", e), + StatusCode::EngineExecuteQuery, + )) + }) + .context(error::ExecuteSnafu)?, + ), + Value::UInt64(v) => Some( + CellIndex::try_from(v) + .map_err(|e| { + BoxedError::new(PlainError::new( + format!("H3 error: {}", e), + StatusCode::EngineExecuteQuery, + )) + }) + .context(error::ExecuteSnafu)?, + ), + _ => None, + }; + Ok(cell) +} diff --git a/tests/cases/standalone/common/function/geo.result b/tests/cases/standalone/common/function/geo.result index 6d44c3ac04..3a63b5890b 100644 --- a/tests/cases/standalone/common/function/geo.result +++ b/tests/cases/standalone/common/function/geo.result @@ -1,98 +1,136 @@ -SELECT h3(37.76938, -122.3889, 0); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 0), h3_latlng_to_cell_string(37.76938, -122.3889, 0);; -+---------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),Int64(0)) | -+---------------------------------------------------+ -| 8029fffffffffff | -+---------------------------------------------------+ ++------------------------------------------------------------------+-------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),Int64(0)) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),Int64(0)) | ++------------------------------------------------------------------+-------------------------------------------------------------------------+ +| 577199624117288959 | 8029fffffffffff | ++------------------------------------------------------------------+-------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 1); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 1), h3_latlng_to_cell_string(37.76938, -122.3889, 1); -+---------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),Int64(1)) | -+---------------------------------------------------+ -| 81283ffffffffff | -+---------------------------------------------------+ ++------------------------------------------------------------------+-------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),Int64(1)) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),Int64(1)) | ++------------------------------------------------------------------+-------------------------------------------------------------------------+ +| 581672437419081727 | 81283ffffffffff | ++------------------------------------------------------------------+-------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 8); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8), h3_latlng_to_cell_string(37.76938, -122.3889, 8); -+---------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),Int64(8)) | -+---------------------------------------------------+ -| 88283082e7fffff | -+---------------------------------------------------+ ++------------------------------------------------------------------+-------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),Int64(8)) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),Int64(8)) | ++------------------------------------------------------------------+-------------------------------------------------------------------------+ +| 613196570438926335 | 88283082e7fffff | ++------------------------------------------------------------------+-------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 100); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 100), h3_latlng_to_cell_string(37.76938, -122.3889, 100); Error: 3001(EngineExecuteQuery), H3 error: invalid resolution (got Some(100)): out of range -SELECT h3(37.76938, -122.3889, -1); +SELECT h3_latlng_to_cell(37.76938, -122.3889, -1), h3_latlng_to_cell_string(37.76938, -122.3889, -1); Error: 3001(EngineExecuteQuery), H3 error: invalid resolution (got Some(255)): out of range -SELECT h3(37.76938, -122.3889, 8::Int8); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::Int8), h3_latlng_to_cell_string(37.76938, -122.3889, 8::Int8); -+---------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),Int64(8)) | -+---------------------------------------------------+ -| 88283082e7fffff | -+---------------------------------------------------+ ++------------------------------------------------------------------+-------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),Int64(8)) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),Int64(8)) | ++------------------------------------------------------------------+-------------------------------------------------------------------------+ +| 613196570438926335 | 88283082e7fffff | ++------------------------------------------------------------------+-------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 8::Int16); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::Int16), h3_latlng_to_cell_string(37.76938, -122.3889, 8::Int16); -+-----------------------------------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("Int16"))) | -+-----------------------------------------------------------------------------+ -| 88283082e7fffff | -+-----------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("Int16"))) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("Int16"))) | ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| 613196570438926335 | 88283082e7fffff | ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 8::Int32); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::Int32), h3_latlng_to_cell_string(37.76938, -122.3889, 8::Int32); -+-----------------------------------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("Int32"))) | -+-----------------------------------------------------------------------------+ -| 88283082e7fffff | -+-----------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("Int32"))) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("Int32"))) | ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| 613196570438926335 | 88283082e7fffff | ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 8::Int64); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::Int64), h3_latlng_to_cell_string(37.76938, -122.3889, 8::Int64); -+-----------------------------------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("Int64"))) | -+-----------------------------------------------------------------------------+ -| 88283082e7fffff | -+-----------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("Int64"))) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("Int64"))) | ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| 613196570438926335 | 88283082e7fffff | ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 8::UInt8); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt8), h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt8); -+-----------------------------------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt8"))) | -+-----------------------------------------------------------------------------+ -| 88283082e7fffff | -+-----------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt8"))) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt8"))) | ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| 613196570438926335 | 88283082e7fffff | ++--------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 8::UInt16); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt16), h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt8); -+------------------------------------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt16"))) | -+------------------------------------------------------------------------------+ -| 88283082e7fffff | -+------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt16"))) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt8"))) | ++---------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ +| 613196570438926335 | 88283082e7fffff | ++---------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 8::UInt32); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt32), h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt32); -+------------------------------------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt32"))) | -+------------------------------------------------------------------------------+ -| 88283082e7fffff | -+------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt32"))) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt32"))) | ++---------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| 613196570438926335 | 88283082e7fffff | ++---------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ -SELECT h3(37.76938, -122.3889, 8::UInt64); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64), h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt64); -+------------------------------------------------------------------------------+ -| h3(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt64"))) | -+------------------------------------------------------------------------------+ -| 88283082e7fffff | -+------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| h3_latlng_to_cell(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt64"))) | h3_latlng_to_cell_string(Float64(37.76938),Float64(-122.3889),arrow_cast(Int64(8),Utf8("UInt64"))) | ++---------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ +| 613196570438926335 | 88283082e7fffff | ++---------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+ + +SELECT h3_cell_to_string(h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64)) AS cell_str, h3_string_to_cell(h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt64)) AS cell_index; + ++-----------------+--------------------+ +| cell_str | cell_index | ++-----------------+--------------------+ +| 88283082e7fffff | 613196570438926335 | ++-----------------+--------------------+ + +SELECT h3_cell_center_lat(h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64)) AS cell_center_lat, h3_cell_center_lng(h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64)) AS cell_center_lng; + ++-------------------+---------------------+ +| cell_center_lat | cell_center_lng | ++-------------------+---------------------+ +| 37.77246152245501 | -122.39010997087324 | ++-------------------+---------------------+ + +SELECT + h3_cell_resolution(cell) AS resolution, + h3_cell_base(cell) AS base, + h3_cell_is_pentagon(cell) AS pentagon, + h3_cell_parent(cell, 6::UInt64) AS parent, +FROM (SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64) AS cell); + ++------------+------+----------+--------------------+ +| resolution | base | pentagon | parent | ++------------+------+----------+--------------------+ +| 8 | 20 | false | 604189371209351167 | ++------------+------+----------+--------------------+ + +SELECT h3_is_neighbour(cell1, cell2) +FROM (SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64) AS cell1, h3_latlng_to_cell(36.76938, -122.3889, 8::UInt64) AS cell2); + ++------------------------------+ +| h3_is_neighbour(cell1,cell2) | ++------------------------------+ +| false | ++------------------------------+ SELECT geohash(37.76938, -122.3889, 9); diff --git a/tests/cases/standalone/common/function/geo.sql b/tests/cases/standalone/common/function/geo.sql index 8f6f70f4a4..3a0e668acc 100644 --- a/tests/cases/standalone/common/function/geo.sql +++ b/tests/cases/standalone/common/function/geo.sql @@ -1,28 +1,43 @@ -SELECT h3(37.76938, -122.3889, 0); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 0), h3_latlng_to_cell_string(37.76938, -122.3889, 0);; -SELECT h3(37.76938, -122.3889, 1); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 1), h3_latlng_to_cell_string(37.76938, -122.3889, 1); -SELECT h3(37.76938, -122.3889, 8); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8), h3_latlng_to_cell_string(37.76938, -122.3889, 8); -SELECT h3(37.76938, -122.3889, 100); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 100), h3_latlng_to_cell_string(37.76938, -122.3889, 100); -SELECT h3(37.76938, -122.3889, -1); +SELECT h3_latlng_to_cell(37.76938, -122.3889, -1), h3_latlng_to_cell_string(37.76938, -122.3889, -1); -SELECT h3(37.76938, -122.3889, 8::Int8); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::Int8), h3_latlng_to_cell_string(37.76938, -122.3889, 8::Int8); -SELECT h3(37.76938, -122.3889, 8::Int16); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::Int16), h3_latlng_to_cell_string(37.76938, -122.3889, 8::Int16); -SELECT h3(37.76938, -122.3889, 8::Int32); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::Int32), h3_latlng_to_cell_string(37.76938, -122.3889, 8::Int32); -SELECT h3(37.76938, -122.3889, 8::Int64); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::Int64), h3_latlng_to_cell_string(37.76938, -122.3889, 8::Int64); -SELECT h3(37.76938, -122.3889, 8::UInt8); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt8), h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt8); -SELECT h3(37.76938, -122.3889, 8::UInt16); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt16), h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt8); -SELECT h3(37.76938, -122.3889, 8::UInt32); +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt32), h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt32); + +SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64), h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt64); + +SELECT h3_cell_to_string(h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64)) AS cell_str, h3_string_to_cell(h3_latlng_to_cell_string(37.76938, -122.3889, 8::UInt64)) AS cell_index; + +SELECT h3_cell_center_lat(h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64)) AS cell_center_lat, h3_cell_center_lng(h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64)) AS cell_center_lng; + +SELECT + h3_cell_resolution(cell) AS resolution, + h3_cell_base(cell) AS base, + h3_cell_is_pentagon(cell) AS pentagon, + h3_cell_parent(cell, 6::UInt64) AS parent, +FROM (SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64) AS cell); + +SELECT h3_is_neighbour(cell1, cell2) +FROM (SELECT h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64) AS cell1, h3_latlng_to_cell(36.76938, -122.3889, 8::UInt64) AS cell2); -SELECT h3(37.76938, -122.3889, 8::UInt64); SELECT geohash(37.76938, -122.3889, 9);