diff --git a/src/compute-types/tests/snapshots/func_registry.json b/src/compute-types/tests/snapshots/func_registry.json index f9de3fd89ea72..b813e2e304d37 100644 --- a/src/compute-types/tests/snapshots/func_registry.json +++ b/src/compute-types/tests/snapshots/func_registry.json @@ -336,7 +336,7 @@ "cast_list1_to_list2": {"variant":"CastList1ToList2","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":false,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["List { element_type: Int32, custom_id: None }:NotNull"],"output_type":"List { element_type: Int64, custom_id: None }:NotNull","sqlfunc_signature":null}, "cast_list_to_jsonb": {"variant":"CastListToJsonb","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":true,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["List { element_type: Int32, custom_id: None }:NotNull"],"output_type":"Jsonb:NotNull","sqlfunc_signature":null}, "cast_list_to_string": {"variant":"CastListToString","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":true,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["List { element_type: Int32, custom_id: None }:NotNull"],"output_type":"String:NotNull","sqlfunc_signature":null}, - "cast_map_to_string": {"variant":"CastMapToString","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":true,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["Map { value_type: Int32, custom_id: None }:NotNull"],"output_type":"String:NotNull","sqlfunc_signature":null}, + "cast_map_to_string": {"variant":"CastMapToString","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":true,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["Map { value_type: Int32, custom_id: None }:NotNull"],"output_type":"String:NotNull","sqlfunc_signature":"fn(ExcludeNull>) -> Result"}, "cast_mz_timestamp_to_string": {"variant":"CastMzTimestampToString","propagates_nulls":true,"introduces_nulls":false,"could_error":false,"preserves_uniqueness":true,"is_monotone":false,"is_eliminable_cast":false,"inverse":"cast_string_to_mz_timestamp","input_types":["MzTimestamp:NotNull"],"output_type":"String:NotNull","sqlfunc_signature":"fn(Timestamp) -> String"}, "cast_mz_timestamp_to_timestamp": {"variant":"CastMzTimestampToTimestamp","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":true,"is_monotone":false,"is_eliminable_cast":false,"inverse":"cast_timestamp_to_mz_timestamp","input_types":["MzTimestamp:NotNull"],"output_type":"Timestamp { precision: None }:NotNull","sqlfunc_signature":"fn(Timestamp) -> Result, EvalError>"}, "cast_mz_timestamp_to_timestamp_tz": {"variant":"CastMzTimestampToTimestampTz","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":true,"is_monotone":false,"is_eliminable_cast":false,"inverse":"cast_timestamp_tz_to_mz_timestamp","input_types":["MzTimestamp:NotNull"],"output_type":"TimestampTz { precision: None }:NotNull","sqlfunc_signature":"fn(Timestamp) -> Result>, EvalError>"}, @@ -506,7 +506,7 @@ "log10": {"variant":"Log10","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":false,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["Float64:NotNull"],"output_type":"Float64:NotNull","sqlfunc_signature":"fn(f64) -> Result"}, "log10_numeric": {"variant":"Log10Numeric","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":false,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["Numeric { max_scale: None }:NotNull"],"output_type":"Numeric { max_scale: None }:NotNull","sqlfunc_signature":"fn(Numeric) -> Result"}, "lower": {"variant":"Lower","propagates_nulls":true,"introduces_nulls":false,"could_error":false,"preserves_uniqueness":false,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["String:NotNull"],"output_type":"String:NotNull","sqlfunc_signature":"fn(&'a str) -> String"}, - "map_build_from_record_list": {"variant":"MapBuildFromRecordList","propagates_nulls":true,"introduces_nulls":true,"could_error":true,"preserves_uniqueness":false,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["List { element_type: Record { fields: [(ColumnName(\"a\"), SqlColumnType { scalar_type: Int32, nullable: false }), (ColumnName(\"b\"), SqlColumnType { scalar_type: String, nullable: true })], custom_id: None }, custom_id: None }:NotNull"],"output_type":"Map { value_type: Int32, custom_id: None }:Null","sqlfunc_signature":null}, + "map_build_from_record_list": {"variant":"MapBuildFromRecordList","propagates_nulls":true,"introduces_nulls":false,"could_error":false,"preserves_uniqueness":false,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["List { element_type: Record { fields: [(ColumnName(\"a\"), SqlColumnType { scalar_type: Int32, nullable: false }), (ColumnName(\"b\"), SqlColumnType { scalar_type: String, nullable: true })], custom_id: None }, custom_id: None }:NotNull"],"output_type":"Map { value_type: Int32, custom_id: None }:NotNull","sqlfunc_signature":"fn(DatumList<'a>) -> DatumMap<'a>"}, "map_length": {"variant":"MapLength","propagates_nulls":true,"introduces_nulls":false,"could_error":true,"preserves_uniqueness":false,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":[],"output_type":null,"sqlfunc_signature":"fn(DatumMap<'a>) -> Result"}, "mz_acl_item_grantee": {"variant":"MzAclItemGrantee","propagates_nulls":true,"introduces_nulls":false,"could_error":false,"preserves_uniqueness":false,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["MzAclItem:NotNull"],"output_type":"String:NotNull","sqlfunc_signature":"fn(MzAclItem) -> String"}, "mz_acl_item_grantor": {"variant":"MzAclItemGrantor","propagates_nulls":true,"introduces_nulls":false,"could_error":false,"preserves_uniqueness":false,"is_monotone":false,"is_eliminable_cast":false,"inverse":null,"input_types":["MzAclItem:NotNull"],"output_type":"String:NotNull","sqlfunc_signature":"fn(MzAclItem) -> String"}, diff --git a/src/compute-types/tests/snapshots/func_registry_digests.json b/src/compute-types/tests/snapshots/func_registry_digests.json index aa62ea47967fe..8a844e6f1d3b9 100644 --- a/src/compute-types/tests/snapshots/func_registry_digests.json +++ b/src/compute-types/tests/snapshots/func_registry_digests.json @@ -1,3 +1,3 @@ { - "1": "sha256:e1d5a5f3547a40492745310bbbdb515dd6eaf99a3c2c2bccf10edbbf1317e9f9" + "1": "sha256:1980be2d4867b47af5170137be1f1a34323a1ef3244786af1463b41a014d8f52" } diff --git a/src/compute-types/tests/snapshots/func_registry_source.json b/src/compute-types/tests/snapshots/func_registry_source.json index bcba52ada46e7..5c1cfb3d23c71 100644 --- a/src/compute-types/tests/snapshots/func_registry_source.json +++ b/src/compute-types/tests/snapshots/func_registry_source.json @@ -336,7 +336,7 @@ "cast_list1_to_list2": {"display":"list1tolist2","sqlfunc_decl":null,"body_fingerprint":null}, "cast_list_to_jsonb": {"display":"listtojsonb","sqlfunc_decl":null,"body_fingerprint":null}, "cast_list_to_string": {"display":"listtostr","sqlfunc_decl":null,"body_fingerprint":null}, - "cast_map_to_string": {"display":"maptostr","sqlfunc_decl":null,"body_fingerprint":null}, + "cast_map_to_string": {"display":"maptostr","sqlfunc_decl":"#[sqlfunc(CastMapToString, sqlname = \"maptostr\", preserves_uniqueness = true)] fn cast_map_to_string<'a>(&self, a: ExcludeNull>) -> Result","body_fingerprint":"57de61553fc8ac26"}, "cast_mz_timestamp_to_string": {"display":"mz_timestamp_to_text","sqlfunc_decl":"#[sqlfunc(sqlname = \"mz_timestamp_to_text\", preserves_uniqueness = true, inverse = super::CastStringToMzTimestamp)] fn cast_mz_timestamp_to_string(a: Timestamp) -> String","body_fingerprint":"01add8290ea7f57b"}, "cast_mz_timestamp_to_timestamp": {"display":"mz_timestamp_to_timestamp","sqlfunc_decl":"#[sqlfunc(sqlname = \"mz_timestamp_to_timestamp\", preserves_uniqueness = true, inverse = super::CastTimestampToMzTimestamp)] fn cast_mz_timestamp_to_timestamp(a: Timestamp,) -> Result, EvalError>","body_fingerprint":"bdf56920d511c8d8"}, "cast_mz_timestamp_to_timestamp_tz": {"display":"mz_timestamp_to_timestamp_tz","sqlfunc_decl":"#[sqlfunc(sqlname = \"mz_timestamp_to_timestamp_tz\", preserves_uniqueness = true, inverse = super::CastTimestampTzToMzTimestamp)] fn cast_mz_timestamp_to_timestamp_tz(a: Timestamp,) -> Result>, EvalError>","body_fingerprint":"caec6fa728d2239c"}, @@ -506,7 +506,7 @@ "log10": {"display":"log10f64","sqlfunc_decl":"#[sqlfunc(sqlname = \"log10f64\")] fn log10(a: f64) -> Result","body_fingerprint":"ccd831efbfc457f5"}, "log10_numeric": {"display":"log10numeric","sqlfunc_decl":"#[sqlfunc(sqlname = \"log10numeric\")] fn log10_numeric(a: Numeric) -> Result","body_fingerprint":"ca47f7b70533acd6"}, "lower": {"display":"lower","sqlfunc_decl":"#[sqlfunc] fn lower<'a>(a: &'a str) -> String","body_fingerprint":"fd3a40a33011f5b0"}, - "map_build_from_record_list": {"display":"map_build","sqlfunc_decl":null,"body_fingerprint":null}, + "map_build_from_record_list": {"display":"map_build","sqlfunc_decl":"#[sqlfunc(MapBuildFromRecordList, sqlname = \"map_build\", output_type_expr = SqlScalarType::Map {value_type: Box::new(self.value_type.clone()), custom_id: None,}.nullable(false))] fn map_build_from_record_list<'a>(&self, a: DatumList<'a>, temp_storage: &'a RowArena,) -> DatumMap<'a>","body_fingerprint":"a3259ba035c76a63"}, "map_length": {"display":"map_length","sqlfunc_decl":"#[sqlfunc(sqlname = \"map_length\")] fn map_length<'a>(a: DatumMap<'a>) -> Result","body_fingerprint":"c0b53fc331e8a78e"}, "mz_acl_item_grantee": {"display":"mz_aclitem_grantee","sqlfunc_decl":"#[sqlfunc(sqlname = \"mz_aclitem_grantee\")] fn mz_acl_item_grantee(mz_acl_item: MzAclItem) -> String","body_fingerprint":"e64db6b570bf5e97"}, "mz_acl_item_grantor": {"display":"mz_aclitem_grantor","sqlfunc_decl":"#[sqlfunc(sqlname = \"mz_aclitem_grantor\")] fn mz_acl_item_grantor(mz_acl_item: MzAclItem) -> String","body_fingerprint":"7c94944bbf658b02"}, diff --git a/src/expr/src/scalar/func.rs b/src/expr/src/scalar/func.rs index da6c2df7adb5e..f55528895ad7a 100644 --- a/src/expr/src/scalar/func.rs +++ b/src/expr/src/scalar/func.rs @@ -141,7 +141,6 @@ func_name! { CastList1ToList2 => "cast_list1_to_list2", CastListToJsonb => "cast_list_to_jsonb", CastListToString => "cast_list_to_string", - CastMapToString => "cast_map_to_string", CastRecord1ToRecord2 => "cast_record1_to_record2", CastRecordToString => "cast_record_to_string", CastStringToArray => "cast_string_to_array", @@ -168,7 +167,6 @@ func_name! { IsLikeMatch => "is_like_match", IsRegexpMatch => "is_regexp_match", ListLengthMax => "list_length_max", - MapBuildFromRecordList => "map_build_from_record_list", RecordGet => "record_get", RegexpMatch => "regexp_match", RegexpReplace => "regexp_replace", diff --git a/src/expr/src/scalar/func/impls/map.rs b/src/expr/src/scalar/func/impls/map.rs index 20fee7feed564..d8c7bd3061588 100644 --- a/src/expr/src/scalar/func/impls/map.rs +++ b/src/expr/src/scalar/func/impls/map.rs @@ -7,15 +7,13 @@ // the Business Source License, use of this software will be governed // by the Apache License, Version 2.0. -use std::fmt; - use itertools::Itertools; use mz_expr_derive::sqlfunc; -use mz_repr::{Datum, DatumMap, RowArena, SqlColumnType, SqlScalarType}; +use mz_repr::{Datum, DatumList, DatumMap, ExcludeNull, RowArena, SqlScalarType}; use serde::{Deserialize, Serialize}; -use crate::scalar::func::{LazyUnaryFunc, stringify_datum}; -use crate::{Eval, EvalError}; +use crate::EvalError; +use crate::scalar::func::stringify_datum; #[derive( Ord, @@ -32,56 +30,12 @@ pub struct CastMapToString { pub ty: SqlScalarType, } -impl LazyUnaryFunc for CastMapToString { - fn eval<'a>( - &'a self, - datums: &[Datum<'a>], - temp_storage: &'a RowArena, - a: &'a impl Eval, - ) -> Result, EvalError> { - let a = a.eval(datums, temp_storage)?; - if a.is_null() { - return Ok(Datum::Null); - } - let mut buf = String::new(); - stringify_datum(&mut buf, a, &self.ty)?; - Ok(Datum::String(temp_storage.push_string(buf))) - } - - fn output_sql_type(&self, input_type: SqlColumnType) -> SqlColumnType { - SqlScalarType::String.nullable(input_type.nullable) - } - - fn propagates_nulls(&self) -> bool { - true - } - - fn introduces_nulls(&self) -> bool { - false - } - - fn preserves_uniqueness(&self) -> bool { - true - } - - fn inverse(&self) -> Option { - // TODO? If we moved typeconv into expr, we could evaluate this - None - } - - fn is_monotone(&self) -> bool { - false - } - - fn is_eliminable_cast(&self) -> bool { - false - } -} - -impl fmt::Display for CastMapToString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("maptostr") - } +// TODO? If we moved typeconv into expr, we could evaluate the inverse of this cast +#[sqlfunc(CastMapToString, sqlname = "maptostr", preserves_uniqueness = true)] +fn cast_map_to_string<'a>(&self, a: ExcludeNull>) -> Result { + let mut buf = String::new(); + stringify_datum(&mut buf, *a, &self.ty)?; + Ok(buf) } #[sqlfunc(sqlname = "map_length")] @@ -107,72 +61,36 @@ pub struct MapBuildFromRecordList { pub value_type: SqlScalarType, } -impl LazyUnaryFunc for MapBuildFromRecordList { - fn eval<'a>( - &'a self, - datums: &[Datum<'a>], - temp_storage: &'a RowArena, - a: &'a impl Eval, - ) -> Result, EvalError> { - let a = a.eval(datums, temp_storage)?; - if a.is_null() { - return Ok(Datum::Null); +#[sqlfunc( + MapBuildFromRecordList, + sqlname = "map_build", + output_type_expr = SqlScalarType::Map { + value_type: Box::new(self.value_type.clone()), + custom_id: None, + } + .nullable(false) +)] +fn map_build_from_record_list<'a>( + &self, + a: DatumList<'a>, + temp_storage: &'a RowArena, +) -> DatumMap<'a> { + let mut map = std::collections::BTreeMap::new(); + + for i in a.iter() { + if i.is_null() { + continue; } - let list = a.unwrap_list(); - let mut map = std::collections::BTreeMap::new(); - for i in list.iter() { - if i.is_null() { + for (k, v) in i.unwrap_list().iter().tuples() { + if k.is_null() { continue; } - - for (k, v) in i.unwrap_list().iter().tuples() { - if k.is_null() { - continue; - } - map.insert(k.unwrap_str(), v); - } + map.insert(k.unwrap_str(), v); } - - let map = temp_storage.make_datum(|packer| packer.push_dict(map)); - Ok(map) - } - - fn output_sql_type(&self, _input_type: SqlColumnType) -> SqlColumnType { - SqlScalarType::Map { - value_type: Box::new(self.value_type.clone()), - custom_id: None, - } - .nullable(true) - } - - fn propagates_nulls(&self) -> bool { - true - } - - fn introduces_nulls(&self) -> bool { - true } - fn preserves_uniqueness(&self) -> bool { - false - } - - fn inverse(&self) -> Option { - None - } - - fn is_monotone(&self) -> bool { - false - } - - fn is_eliminable_cast(&self) -> bool { - false - } -} - -impl fmt::Display for MapBuildFromRecordList { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("map_build") - } + temp_storage + .make_datum(|packer| packer.push_dict(map)) + .unwrap_map() }