diff --git a/src/expr/src/interpret.rs b/src/expr/src/interpret.rs index 9e96472a9899f..5933cbf501010 100644 --- a/src/expr/src/interpret.rs +++ b/src/expr/src/interpret.rs @@ -688,11 +688,11 @@ impl SpecialBinary { } match func { - BinaryFunc::JsonbGetString => Some(SpecialBinary { + BinaryFunc::JsonbGetString(_) => Some(SpecialBinary { map_fn: |l, r| jsonb_get_string(l, r, false), pushdownable: (true, false), }), - BinaryFunc::JsonbGetStringStringify => Some(SpecialBinary { + BinaryFunc::JsonbGetStringStringify(_) => Some(SpecialBinary { map_fn: |l, r| jsonb_get_string(l, r, true), pushdownable: (true, false), }), @@ -1180,8 +1180,8 @@ mod tests { Lte.into(), Gte.into(), DateTruncUnitsTimestamp.into(), - BinaryFunc::JsonbGetString, - BinaryFunc::JsonbGetStringStringify, + JsonbGetString.into(), + JsonbGetStringStringify.into(), ] } @@ -1203,7 +1203,7 @@ mod tests { .scalar_type .base_eq(&SqlScalarType::Timestamp { precision: None }) } - JsonbGetString | JsonbGetStringStringify => { + JsonbGetString(_) | JsonbGetStringStringify(_) => { arg0.scalar_type.base_eq(&SqlScalarType::Jsonb) && arg1.scalar_type.base_eq(&SqlScalarType::String) } @@ -1570,17 +1570,15 @@ mod tests { fn test_jsonb() { let arena = RowArena::new(); - let expr = MirScalarExpr::CallUnary { - func: UnaryFunc::CastJsonbToNumeric(CastJsonbToNumeric(None)), - expr: Box::new(MirScalarExpr::CallBinary { - func: BinaryFunc::JsonbGetString, - expr1: Box::new(MirScalarExpr::column(0)), - expr2: Box::new(MirScalarExpr::Literal( + let expr = MirScalarExpr::column(0) + .call_binary( + MirScalarExpr::Literal( Ok(Row::pack_slice(&["ts".into()])), SqlScalarType::String.nullable(false), - )), - }), - }; + ), + JsonbGetString, + ) + .call_unary(CastJsonbToNumeric(None)); let relation = SqlRelationType::new(vec![SqlScalarType::Jsonb.nullable(true)]); let mut interpreter = ColumnSpecs::new(&relation, &arena); diff --git a/src/expr/src/relation/func.rs b/src/expr/src/relation/func.rs index 36d3ade377405..859e5365c99ea 100644 --- a/src/expr/src/relation/func.rs +++ b/src/expr/src/relation/func.rs @@ -2665,10 +2665,20 @@ impl AggregateFunc { } } -fn jsonb_each<'a>( +fn jsonb_each<'a>(a: Datum<'a>) -> impl Iterator + 'a { + // First produce a map, so that a common iterator can be returned. + let map = match a { + Datum::Map(dict) => dict, + _ => mz_repr::DatumMap::empty(), + }; + + map.iter() + .map(move |(k, v)| (Row::pack_slice(&[Datum::String(k), v]), Diff::ONE)) +} + +fn jsonb_each_stringify<'a>( a: Datum<'a>, temp_storage: &'a RowArena, - stringify: bool, ) -> impl Iterator + 'a { // First produce a map, so that a common iterator can be returned. let map = match a { @@ -2677,9 +2687,9 @@ fn jsonb_each<'a>( }; map.iter().map(move |(k, mut v)| { - if stringify { - v = jsonb_stringify(v, temp_storage); - } + v = jsonb_stringify(v, temp_storage) + .map(Datum::String) + .unwrap_or(Datum::Null); (Row::pack_slice(&[Datum::String(k), v]), Diff::ONE) }) } @@ -2694,19 +2704,26 @@ fn jsonb_object_keys<'a>(a: Datum<'a>) -> impl Iterator + 'a .map(move |(k, _)| (Row::pack_slice(&[Datum::String(k)]), Diff::ONE)) } -fn jsonb_array_elements<'a>( +fn jsonb_array_elements<'a>(a: Datum<'a>) -> impl Iterator + 'a { + let list = match a { + Datum::List(list) => list, + _ => mz_repr::DatumList::empty(), + }; + list.iter().map(move |e| (Row::pack_slice(&[e]), Diff::ONE)) +} + +fn jsonb_array_elements_stringify<'a>( a: Datum<'a>, temp_storage: &'a RowArena, - stringify: bool, ) -> impl Iterator + 'a { let list = match a { Datum::List(list) => list, _ => mz_repr::DatumList::empty(), }; list.iter().map(move |mut e| { - if stringify { - e = jsonb_stringify(e, temp_storage); - } + e = jsonb_stringify(e, temp_storage) + .map(Datum::String) + .unwrap_or(Datum::Null); (Row::pack_slice(&[e]), Diff::ONE) }) } @@ -3244,13 +3261,11 @@ fn mz_acl_explode<'a>( pub enum TableFunc { AclExplode, MzAclExplode, - JsonbEach { - stringify: bool, - }, + JsonbEach, + JsonbEachStringify, JsonbObjectKeys, - JsonbArrayElements { - stringify: bool, - }, + JsonbArrayElements, + JsonbArrayElementsStringify, RegexpExtract(AnalyzedRegex), CsvExtract(usize), GenerateSeriesInt32, @@ -3372,14 +3387,15 @@ impl TableFunc { match self { TableFunc::AclExplode => Ok(Box::new(acl_explode(datums[0], temp_storage)?)), TableFunc::MzAclExplode => Ok(Box::new(mz_acl_explode(datums[0], temp_storage)?)), - TableFunc::JsonbEach { stringify } => { - Ok(Box::new(jsonb_each(datums[0], temp_storage, *stringify))) + TableFunc::JsonbEach => Ok(Box::new(jsonb_each(datums[0]))), + TableFunc::JsonbEachStringify => { + Ok(Box::new(jsonb_each_stringify(datums[0], temp_storage))) } TableFunc::JsonbObjectKeys => Ok(Box::new(jsonb_object_keys(datums[0]))), - TableFunc::JsonbArrayElements { stringify } => Ok(Box::new(jsonb_array_elements( + TableFunc::JsonbArrayElements => Ok(Box::new(jsonb_array_elements(datums[0]))), + TableFunc::JsonbArrayElementsStringify => Ok(Box::new(jsonb_array_elements_stringify( datums[0], temp_storage, - *stringify, ))), TableFunc::RegexpExtract(a) => Ok(Box::new(regexp_extract(datums[0], a).into_iter())), TableFunc::CsvExtract(n_cols) => Ok(Box::new(csv_extract(datums[0], *n_cols))), @@ -3474,18 +3490,18 @@ impl TableFunc { let keys = vec![]; (column_types, keys) } - TableFunc::JsonbEach { stringify: true } => { + TableFunc::JsonbEach => { let column_types = vec![ SqlScalarType::String.nullable(false), - SqlScalarType::String.nullable(true), + SqlScalarType::Jsonb.nullable(false), ]; let keys = vec![]; (column_types, keys) } - TableFunc::JsonbEach { stringify: false } => { + TableFunc::JsonbEachStringify => { let column_types = vec![ SqlScalarType::String.nullable(false), - SqlScalarType::Jsonb.nullable(false), + SqlScalarType::String.nullable(true), ]; let keys = vec![]; (column_types, keys) @@ -3495,13 +3511,13 @@ impl TableFunc { let keys = vec![]; (column_types, keys) } - TableFunc::JsonbArrayElements { stringify: true } => { - let column_types = vec![SqlScalarType::String.nullable(true)]; + TableFunc::JsonbArrayElements => { + let column_types = vec![SqlScalarType::Jsonb.nullable(false)]; let keys = vec![]; (column_types, keys) } - TableFunc::JsonbArrayElements { stringify: false } => { - let column_types = vec![SqlScalarType::Jsonb.nullable(false)]; + TableFunc::JsonbArrayElementsStringify => { + let column_types = vec![SqlScalarType::String.nullable(true)]; let keys = vec![]; (column_types, keys) } @@ -3613,9 +3629,11 @@ impl TableFunc { match self { TableFunc::AclExplode => 4, TableFunc::MzAclExplode => 4, - TableFunc::JsonbEach { .. } => 2, + TableFunc::JsonbEach => 2, + TableFunc::JsonbEachStringify => 2, TableFunc::JsonbObjectKeys => 1, - TableFunc::JsonbArrayElements { .. } => 1, + TableFunc::JsonbArrayElements => 1, + TableFunc::JsonbArrayElementsStringify => 1, TableFunc::RegexpExtract(a) => a.capture_groups_len(), TableFunc::CsvExtract(n_cols) => *n_cols, TableFunc::GenerateSeriesInt32 => 1, @@ -3639,9 +3657,11 @@ impl TableFunc { match self { TableFunc::AclExplode | TableFunc::MzAclExplode - | TableFunc::JsonbEach { .. } + | TableFunc::JsonbEach + | TableFunc::JsonbEachStringify | TableFunc::JsonbObjectKeys - | TableFunc::JsonbArrayElements { .. } + | TableFunc::JsonbArrayElements + | TableFunc::JsonbArrayElementsStringify | TableFunc::GenerateSeriesInt32 | TableFunc::GenerateSeriesInt64 | TableFunc::GenerateSeriesTimestamp @@ -3668,9 +3688,11 @@ impl TableFunc { match self { TableFunc::AclExplode => false, TableFunc::MzAclExplode => false, - TableFunc::JsonbEach { .. } => true, + TableFunc::JsonbEach => true, + TableFunc::JsonbEachStringify => true, TableFunc::JsonbObjectKeys => true, - TableFunc::JsonbArrayElements { .. } => true, + TableFunc::JsonbArrayElements => true, + TableFunc::JsonbArrayElementsStringify => true, TableFunc::RegexpExtract(_) => true, TableFunc::CsvExtract(_) => true, TableFunc::GenerateSeriesInt32 => true, @@ -3696,9 +3718,11 @@ impl fmt::Display for TableFunc { match self { TableFunc::AclExplode => f.write_str("aclexplode"), TableFunc::MzAclExplode => f.write_str("mz_aclexplode"), - TableFunc::JsonbEach { .. } => f.write_str("jsonb_each"), + TableFunc::JsonbEach => f.write_str("jsonb_each"), + TableFunc::JsonbEachStringify => f.write_str("jsonb_each"), TableFunc::JsonbObjectKeys => f.write_str("jsonb_object_keys"), - TableFunc::JsonbArrayElements { .. } => f.write_str("jsonb_array_elements"), + TableFunc::JsonbArrayElements => f.write_str("jsonb_array_elements"), + TableFunc::JsonbArrayElementsStringify => f.write_str("jsonb_array_elements"), TableFunc::RegexpExtract(a) => write!(f, "regexp_extract({:?}, _)", a.0), TableFunc::CsvExtract(n_cols) => write!(f, "csv_extract({}, _)", n_cols), TableFunc::GenerateSeriesInt32 => f.write_str("generate_series"), diff --git a/src/expr/src/scalar/func.rs b/src/expr/src/scalar/func.rs index 712e5f6b0e803..2e56cb1c4fe23 100644 --- a/src/expr/src/scalar/func.rs +++ b/src/expr/src/scalar/func.rs @@ -81,13 +81,13 @@ pub use variadic::VariadicFunc; /// function where it applies. const MAX_STRING_FUNC_RESULT_BYTES: usize = 1024 * 1024 * 100; -pub fn jsonb_stringify<'a>(a: Datum<'a>, temp_storage: &'a RowArena) -> Datum<'a> { +pub fn jsonb_stringify<'a>(a: Datum<'a>, temp_storage: &'a RowArena) -> Option<&'a str> { match a { - Datum::JsonNull => Datum::Null, - Datum::String(_) => a, + Datum::JsonNull => None, + Datum::String(s) => Some(s), _ => { let s = cast_jsonb_to_string(JsonbRef::from_datum(a)); - Datum::String(temp_storage.push_string(s)) + Some(temp_storage.push_string(s)) } } } @@ -1743,13 +1743,12 @@ fn to_char_timestamp_tz_format( fmt.render(&*ts) } -fn jsonb_get_int64<'a>( - a: Datum<'a>, - b: Datum<'a>, - temp_storage: &'a RowArena, - stringify: bool, -) -> Datum<'a> { - let i = b.unwrap_int64(); +#[sqlfunc( + sqlname = "->", + output_type = "Option", + is_infix_op = true +)] +fn jsonb_get_int64<'a>(a: Datum<'a>, i: i64) -> Datum<'a> { match a { Datum::List(list) => { let i = if i >= 0 { @@ -1760,7 +1759,6 @@ fn jsonb_get_int64<'a>( (list.iter().count()).wrapping_sub(i) }; match list.iter().nth(i) { - Some(d) if stringify => jsonb_stringify(d, temp_storage), Some(d) => d, None => Datum::Null, } @@ -1769,11 +1767,7 @@ fn jsonb_get_int64<'a>( _ => { if i == 0 || i == -1 { // I have no idea why postgres does this, but we're stuck with it - if stringify { - jsonb_stringify(a, temp_storage) - } else { - a - } + a } else { Datum::Null } @@ -1781,16 +1775,42 @@ fn jsonb_get_int64<'a>( } } -fn jsonb_get_string<'a>( +#[sqlfunc(sqlname = "->>", is_infix_op = true)] +fn jsonb_get_int64_stringify<'a>( a: Datum<'a>, - b: Datum<'a>, + i: i64, temp_storage: &'a RowArena, - stringify: bool, -) -> Datum<'a> { - let k = b.unwrap_str(); +) -> Option<&'a str> { + match a { + Datum::List(list) => { + let i = if i >= 0 { + usize::cast_from(i.unsigned_abs()) + } else { + // index backwards from the end + let i = usize::cast_from(i.unsigned_abs()); + (list.iter().count()).wrapping_sub(i) + }; + match list.iter().nth(i) { + Some(d) => jsonb_stringify(d, temp_storage), + None => None, + } + } + Datum::Map(_) => None, + _ => { + if i == 0 || i == -1 { + // I have no idea why postgres does this, but we're stuck with it + jsonb_stringify(a, temp_storage) + } else { + None + } + } + } +} + +#[sqlfunc(sqlname = "->", output_type = "Option")] +fn jsonb_get_string<'a>(a: Datum<'a>, k: &str) -> Datum<'a> { match a { Datum::Map(dict) => match dict.iter().find(|(k2, _v)| k == *k2) { - Some((_k, v)) if stringify => jsonb_stringify(v, temp_storage), Some((_k, v)) => v, None => Datum::Null, }, @@ -1798,14 +1818,29 @@ fn jsonb_get_string<'a>( } } -fn jsonb_get_path<'a>( +#[sqlfunc(sqlname = "->>", is_infix_op = true)] +fn jsonb_get_string_stringify<'a>( a: Datum<'a>, - b: Datum<'a>, + k: &str, temp_storage: &'a RowArena, - stringify: bool, -) -> Datum<'a> { +) -> Option<&'a str> { + match a { + Datum::Map(dict) => match dict.iter().find(|(k2, _v)| k == *k2) { + Some((_k, v)) => jsonb_stringify(v, temp_storage), + None => None, + }, + _ => None, + } +} + +#[sqlfunc( + sqlname = "#>", + output_type = "Option", + is_infix_op = true +)] +fn jsonb_get_path<'a>(a: Datum<'a>, b: Array<'a>) -> Datum<'a> { let mut json = a; - let path = b.unwrap_array().elements(); + let path = b.elements(); for key in path.iter() { let key = match key { Datum::String(s) => s, @@ -1836,11 +1871,17 @@ fn jsonb_get_path<'a>( _ => return Datum::Null, } } - if stringify { - jsonb_stringify(json, temp_storage) - } else { - json - } + json +} + +#[sqlfunc(sqlname = "#>>", is_infix_op = true)] +fn jsonb_get_path_stringify<'a>( + a: Datum<'a>, + b: Array<'a>, + temp_storage: &'a RowArena, +) -> Option<&'a str> { + let json = jsonb_get_path(a, b); + jsonb_stringify(json, temp_storage) } #[sqlfunc(is_infix_op = true, sqlname = "?", propagates_nulls = true)] @@ -2638,12 +2679,12 @@ pub enum BinaryFunc { TimezoneIntervalTime, TimezoneOffset(TimezoneOffset), TextConcat(TextConcatBinary), - JsonbGetInt64, - JsonbGetInt64Stringify, - JsonbGetString, - JsonbGetStringStringify, - JsonbGetPath, - JsonbGetPathStringify, + JsonbGetInt64(JsonbGetInt64), + JsonbGetInt64Stringify(JsonbGetInt64Stringify), + JsonbGetString(JsonbGetString), + JsonbGetStringStringify(JsonbGetStringStringify), + JsonbGetPath(JsonbGetPath), + JsonbGetPathStringify(JsonbGetPathStringify), JsonbContainsString(JsonbContainsString), JsonbConcat(JsonbConcat), JsonbContainsJsonb(JsonbContainsJsonb), @@ -2898,12 +2939,18 @@ impl BinaryFunc { // BinaryFunc::TimezoneIntervalTime(s) => return s.eval(datums, temp_storage, a_expr, b_expr), BinaryFunc::TimezoneOffset(s) => return s.eval(datums, temp_storage, a_expr, b_expr), BinaryFunc::TextConcat(s) => return s.eval(datums, temp_storage, a_expr, b_expr), - // BinaryFunc::JsonbGetInt64(s) => return s.eval(datums, temp_storage, a_expr, b_expr), - // BinaryFunc::JsonbGetInt64Stringify(s) => return s.eval(datums, temp_storage, a_expr, b_expr), - // BinaryFunc::JsonbGetString(s) => return s.eval(datums, temp_storage, a_expr, b_expr), - // BinaryFunc::JsonbGetStringStringify(s) => return s.eval(datums, temp_storage, a_expr, b_expr), - // BinaryFunc::JsonbGetPath(s) => return s.eval(datums, temp_storage, a_expr, b_expr), - // BinaryFunc::JsonbGetPathStringify(s) => return s.eval(datums, temp_storage, a_expr, b_expr), + BinaryFunc::JsonbGetInt64(s) => return s.eval(datums, temp_storage, a_expr, b_expr), + BinaryFunc::JsonbGetInt64Stringify(s) => { + return s.eval(datums, temp_storage, a_expr, b_expr); + } + BinaryFunc::JsonbGetString(s) => return s.eval(datums, temp_storage, a_expr, b_expr), + BinaryFunc::JsonbGetStringStringify(s) => { + return s.eval(datums, temp_storage, a_expr, b_expr); + } + BinaryFunc::JsonbGetPath(s) => return s.eval(datums, temp_storage, a_expr, b_expr), + BinaryFunc::JsonbGetPathStringify(s) => { + return s.eval(datums, temp_storage, a_expr, b_expr); + } BinaryFunc::JsonbContainsString(s) => { return s.eval(datums, temp_storage, a_expr, b_expr); } @@ -3031,12 +3078,6 @@ impl BinaryFunc { BinaryFunc::TimezoneIntervalTimestamp => timezone_interval_timestamp(a, b), BinaryFunc::TimezoneIntervalTimestampTz => timezone_interval_timestamptz(a, b), BinaryFunc::TimezoneIntervalTime => timezone_interval_time(a, b), - BinaryFunc::JsonbGetInt64 => Ok(jsonb_get_int64(a, b, temp_storage, false)), - BinaryFunc::JsonbGetInt64Stringify => Ok(jsonb_get_int64(a, b, temp_storage, true)), - BinaryFunc::JsonbGetString => Ok(jsonb_get_string(a, b, temp_storage, false)), - BinaryFunc::JsonbGetStringStringify => Ok(jsonb_get_string(a, b, temp_storage, true)), - BinaryFunc::JsonbGetPath => Ok(jsonb_get_path(a, b, temp_storage, false)), - BinaryFunc::JsonbGetPathStringify => Ok(jsonb_get_path(a, b, temp_storage, true)), BinaryFunc::ListLengthMax { max_layer } => list_length_max(a, b, *max_layer), BinaryFunc::ArrayContainsArray { rev: false } => Ok(array_contains_array(a, b)), BinaryFunc::ArrayContainsArray { rev: true } => Ok(array_contains_array(b, a)), @@ -3236,11 +3277,13 @@ impl BinaryFunc { MzRenderTypmod(s) => s.output_type(input1_type, input2_type), TextConcat(s) => s.output_type(input1_type, input2_type), - JsonbGetInt64Stringify | JsonbGetStringStringify | JsonbGetPathStringify => { - SqlScalarType::String.nullable(true) - } + JsonbGetInt64Stringify(s) => s.output_type(input1_type, input2_type), + JsonbGetStringStringify(s) => s.output_type(input1_type, input2_type), + JsonbGetPathStringify(s) => s.output_type(input1_type, input2_type), - JsonbGetInt64 | JsonbGetString | JsonbGetPath => SqlScalarType::Jsonb.nullable(true), + JsonbGetInt64(s) => s.output_type(input1_type, input2_type), + JsonbGetString(s) => s.output_type(input1_type, input2_type), + JsonbGetPath(s) => s.output_type(input1_type, input2_type), JsonbConcat(s) => s.output_type(input1_type, input2_type), JsonbDeleteInt64(s) => s.output_type(input1_type, input2_type), JsonbDeleteString(s) => s.output_type(input1_type, input2_type), @@ -3422,12 +3465,12 @@ impl BinaryFunc { BinaryFunc::JsonbContainsString(s) => s.propagates_nulls(), BinaryFunc::JsonbDeleteInt64(s) => s.propagates_nulls(), BinaryFunc::JsonbDeleteString(s) => s.propagates_nulls(), - BinaryFunc::JsonbGetInt64 => true, - BinaryFunc::JsonbGetInt64Stringify => true, - BinaryFunc::JsonbGetPath => true, - BinaryFunc::JsonbGetPathStringify => true, - BinaryFunc::JsonbGetString => true, - BinaryFunc::JsonbGetStringStringify => true, + BinaryFunc::JsonbGetInt64(s) => s.propagates_nulls(), + BinaryFunc::JsonbGetInt64Stringify(s) => s.propagates_nulls(), + BinaryFunc::JsonbGetPath(s) => s.propagates_nulls(), + BinaryFunc::JsonbGetPathStringify(s) => s.propagates_nulls(), + BinaryFunc::JsonbGetString(s) => s.propagates_nulls(), + BinaryFunc::JsonbGetStringStringify(s) => s.propagates_nulls(), BinaryFunc::Left(s) => s.propagates_nulls(), BinaryFunc::LikeEscape(s) => s.propagates_nulls(), BinaryFunc::ListContainsList { .. } => true, @@ -3718,12 +3761,12 @@ impl BinaryFunc { JsonbConcat(s) => s.introduces_nulls(), JsonbDeleteInt64(s) => s.introduces_nulls(), JsonbDeleteString(s) => s.introduces_nulls(), - JsonbGetInt64 => true, - JsonbGetInt64Stringify => true, - JsonbGetPath => true, - JsonbGetPathStringify => true, - JsonbGetString => true, - JsonbGetStringStringify => true, + JsonbGetInt64(s) => s.introduces_nulls(), + JsonbGetInt64Stringify(s) => s.introduces_nulls(), + JsonbGetPath(s) => s.introduces_nulls(), + JsonbGetPathStringify(s) => s.introduces_nulls(), + JsonbGetString(s) => s.introduces_nulls(), + JsonbGetStringStringify(s) => s.introduces_nulls(), ListLengthMax { .. } => true, MapGetValue(s) => s.introduces_nulls(), } @@ -3805,12 +3848,12 @@ impl BinaryFunc { JsonbContainsString(s) => s.is_infix_op(), JsonbDeleteInt64(s) => s.is_infix_op(), JsonbDeleteString(s) => s.is_infix_op(), - JsonbGetInt64 => true, - JsonbGetInt64Stringify => true, - JsonbGetPath => true, - JsonbGetPathStringify => true, - JsonbGetString => true, - JsonbGetStringStringify => true, + JsonbGetInt64(s) => s.is_infix_op(), + JsonbGetInt64Stringify(s) => s.is_infix_op(), + JsonbGetPath(s) => s.is_infix_op(), + JsonbGetPathStringify(s) => s.is_infix_op(), + JsonbGetString(s) => s.is_infix_op(), + JsonbGetStringStringify(s) => s.is_infix_op(), ListContainsList { .. } => true, ListElementConcat(s) => s.is_infix_op(), ListListConcat(s) => s.is_infix_op(), @@ -4035,12 +4078,12 @@ impl BinaryFunc { BinaryFunc::JsonbContainsString(s) => s.negate(), BinaryFunc::JsonbDeleteInt64(s) => s.negate(), BinaryFunc::JsonbDeleteString(s) => s.negate(), - BinaryFunc::JsonbGetInt64 => None, - BinaryFunc::JsonbGetInt64Stringify => None, - BinaryFunc::JsonbGetPath => None, - BinaryFunc::JsonbGetPathStringify => None, - BinaryFunc::JsonbGetString => None, - BinaryFunc::JsonbGetStringStringify => None, + BinaryFunc::JsonbGetInt64(s) => s.negate(), + BinaryFunc::JsonbGetInt64Stringify(s) => s.negate(), + BinaryFunc::JsonbGetPath(s) => s.negate(), + BinaryFunc::JsonbGetPathStringify(s) => s.negate(), + BinaryFunc::JsonbGetString(s) => s.negate(), + BinaryFunc::JsonbGetStringStringify(s) => s.negate(), BinaryFunc::Left(s) => s.negate(), BinaryFunc::LikeEscape(s) => s.negate(), BinaryFunc::ListContainsList { .. } => None, @@ -4182,12 +4225,12 @@ impl BinaryFunc { BinaryFunc::Eq(s) => s.could_error(), BinaryFunc::Gt(s) => s.could_error(), BinaryFunc::Gte(s) => s.could_error(), - BinaryFunc::JsonbGetInt64 => false, - BinaryFunc::JsonbGetInt64Stringify => false, - BinaryFunc::JsonbGetPath => false, - BinaryFunc::JsonbGetPathStringify => false, - BinaryFunc::JsonbGetString => false, - BinaryFunc::JsonbGetStringStringify => false, + BinaryFunc::JsonbGetInt64(s) => s.could_error(), + BinaryFunc::JsonbGetInt64Stringify(s) => s.could_error(), + BinaryFunc::JsonbGetPath(s) => s.could_error(), + BinaryFunc::JsonbGetPathStringify(s) => s.could_error(), + BinaryFunc::JsonbGetString(s) => s.could_error(), + BinaryFunc::JsonbGetStringStringify(s) => s.could_error(), BinaryFunc::ListContainsList { rev: _ } => false, BinaryFunc::ListElementConcat(s) => s.could_error(), BinaryFunc::ListListConcat(s) => s.could_error(), @@ -4486,12 +4529,12 @@ impl BinaryFunc { | BinaryFunc::TimezoneIntervalTimestampTz | BinaryFunc::TimezoneIntervalTime => (false, false), BinaryFunc::TimezoneOffset(s) => s.is_monotone(), - BinaryFunc::JsonbGetInt64 - | BinaryFunc::JsonbGetInt64Stringify - | BinaryFunc::JsonbGetString - | BinaryFunc::JsonbGetStringStringify - | BinaryFunc::JsonbGetPath - | BinaryFunc::JsonbGetPathStringify => (false, false), + BinaryFunc::JsonbGetInt64(s) => s.is_monotone(), + BinaryFunc::JsonbGetInt64Stringify(s) => s.is_monotone(), + BinaryFunc::JsonbGetString(s) => s.is_monotone(), + BinaryFunc::JsonbGetStringStringify(s) => s.is_monotone(), + BinaryFunc::JsonbGetPath(s) => s.is_monotone(), + BinaryFunc::JsonbGetPathStringify(s) => s.is_monotone(), BinaryFunc::JsonbContainsString(s) => s.is_monotone(), BinaryFunc::JsonbConcat(s) => s.is_monotone(), BinaryFunc::JsonbContainsJsonb(s) => s.is_monotone(), @@ -4693,12 +4736,12 @@ impl fmt::Display for BinaryFunc { BinaryFunc::TimezoneIntervalTime => f.write_str("timezoneit"), BinaryFunc::TimezoneOffset(s) => s.fmt(f), BinaryFunc::TextConcat(s) => s.fmt(f), - BinaryFunc::JsonbGetInt64 => f.write_str("->"), - BinaryFunc::JsonbGetInt64Stringify => f.write_str("->>"), - BinaryFunc::JsonbGetString => f.write_str("->"), - BinaryFunc::JsonbGetStringStringify => f.write_str("->>"), - BinaryFunc::JsonbGetPath => f.write_str("#>"), - BinaryFunc::JsonbGetPathStringify => f.write_str("#>>"), + BinaryFunc::JsonbGetInt64(s) => s.fmt(f), + BinaryFunc::JsonbGetInt64Stringify(s) => s.fmt(f), + BinaryFunc::JsonbGetString(s) => s.fmt(f), + BinaryFunc::JsonbGetStringStringify(s) => s.fmt(f), + BinaryFunc::JsonbGetPath(s) => s.fmt(f), + BinaryFunc::JsonbGetPathStringify(s) => s.fmt(f), BinaryFunc::JsonbContainsString(s) => s.fmt(f), BinaryFunc::MapContainsKey(s) => s.fmt(f), BinaryFunc::JsonbConcat(s) => s.fmt(f), diff --git a/src/expr/src/scalar/func/binary.rs b/src/expr/src/scalar/func/binary.rs index 900ab7811fb10..ca07dfaebee2e 100644 --- a/src/expr/src/scalar/func/binary.rs +++ b/src/expr/src/scalar/func/binary.rs @@ -281,12 +281,12 @@ mod derive { JsonbContainsString, JsonbDeleteInt64, JsonbDeleteString, - // JsonbGetInt64, - // JsonbGetInt64Stringify, - // JsonbGetPath, - // JsonbGetPathStringify, - // JsonbGetString, - // JsonbGetStringStringify, + JsonbGetInt64, + JsonbGetInt64Stringify, + JsonbGetPath, + JsonbGetPathStringify, + JsonbGetString, + JsonbGetStringStringify, Left, LikeEscape, // ListContainsList diff --git a/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_int64.snap b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_int64.snap new file mode 100644 index 0000000000000..020b4ded1a87e --- /dev/null +++ b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_int64.snap @@ -0,0 +1,78 @@ +--- +source: src/expr/src/scalar/func.rs +expression: "#[sqlfunc(\n sqlname = \"->\",\n output_type = \"Option\",\n is_infix_op = true\n)]\nfn jsonb_get_int64<'a>(a: Datum<'a>, i: i64) -> Datum<'a> {\n match a {\n Datum::List(list) => {\n let i = if i >= 0 {\n usize::cast_from(i.unsigned_abs())\n } else {\n let i = usize::cast_from(i.unsigned_abs());\n (list.iter().count()).wrapping_sub(i)\n };\n match list.iter().nth(i) {\n Some(d) => d,\n None => Datum::Null,\n }\n }\n Datum::Map(_) => Datum::Null,\n _ => if i == 0 || i == -1 { a } else { Datum::Null }\n }\n}\n" +--- +#[derive( + proptest_derive::Arbitrary, + Ord, + PartialOrd, + Clone, + Debug, + Eq, + PartialEq, + serde::Serialize, + serde::Deserialize, + Hash, + mz_lowertest::MzReflect +)] +pub struct JsonbGetInt64; +impl<'a> crate::func::binary::EagerBinaryFunc<'a> for JsonbGetInt64 { + type Input1 = Datum<'a>; + type Input2 = i64; + type Output = Datum<'a>; + fn call( + &self, + a: Self::Input1, + b: Self::Input2, + temp_storage: &'a mz_repr::RowArena, + ) -> Self::Output { + jsonb_get_int64(a, b) + } + fn output_type( + &self, + input_type_a: mz_repr::SqlColumnType, + input_type_b: mz_repr::SqlColumnType, + ) -> mz_repr::SqlColumnType { + use mz_repr::AsColumnType; + let output = >::as_column_type(); + let propagates_nulls = crate::func::binary::EagerBinaryFunc::propagates_nulls( + self, + ); + let nullable = output.nullable; + output + .nullable( + nullable + || (propagates_nulls + && (input_type_a.nullable || input_type_b.nullable)), + ) + } + fn introduces_nulls(&self) -> bool { + as ::mz_repr::DatumType<'_, ()>>::nullable() + } + fn is_infix_op(&self) -> bool { + true + } +} +impl std::fmt::Display for JsonbGetInt64 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("->") + } +} +fn jsonb_get_int64<'a>(a: Datum<'a>, i: i64) -> Datum<'a> { + match a { + Datum::List(list) => { + let i = if i >= 0 { + usize::cast_from(i.unsigned_abs()) + } else { + let i = usize::cast_from(i.unsigned_abs()); + (list.iter().count()).wrapping_sub(i) + }; + match list.iter().nth(i) { + Some(d) => d, + None => Datum::Null, + } + } + Datum::Map(_) => Datum::Null, + _ => if i == 0 || i == -1 { a } else { Datum::Null } + } +} diff --git a/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_int64_stringify.snap b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_int64_stringify.snap new file mode 100644 index 0000000000000..da9de3c295f62 --- /dev/null +++ b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_int64_stringify.snap @@ -0,0 +1,79 @@ +--- +source: src/expr/src/scalar/func.rs +expression: "#[sqlfunc(sqlname = \"->>\", is_infix_op = true)]\nfn jsonb_get_int64_stringify<'a>(\n a: Datum<'a>,\n i: i64,\n temp_storage: &'a RowArena,\n) -> Option<&'a str> {\n match a {\n Datum::List(list) => {\n let i = if i >= 0 {\n usize::cast_from(i.unsigned_abs())\n } else {\n let i = usize::cast_from(i.unsigned_abs());\n (list.iter().count()).wrapping_sub(i)\n };\n match list.iter().nth(i) {\n Some(d) => jsonb_stringify(d, temp_storage),\n None => None,\n }\n }\n Datum::Map(_) => None,\n _ => if i == 0 || i == -1 { jsonb_stringify(a, temp_storage) } else { None }\n }\n}\n" +--- +#[derive( + proptest_derive::Arbitrary, + Ord, + PartialOrd, + Clone, + Debug, + Eq, + PartialEq, + serde::Serialize, + serde::Deserialize, + Hash, + mz_lowertest::MzReflect +)] +pub struct JsonbGetInt64Stringify; +impl<'a> crate::func::binary::EagerBinaryFunc<'a> for JsonbGetInt64Stringify { + type Input1 = Datum<'a>; + type Input2 = i64; + type Output = Option<&'a str>; + fn call( + &self, + a: Self::Input1, + b: Self::Input2, + temp_storage: &'a mz_repr::RowArena, + ) -> Self::Output { + jsonb_get_int64_stringify(a, b, temp_storage) + } + fn output_type( + &self, + input_type_a: mz_repr::SqlColumnType, + input_type_b: mz_repr::SqlColumnType, + ) -> mz_repr::SqlColumnType { + use mz_repr::AsColumnType; + let output = Self::Output::as_column_type(); + let propagates_nulls = crate::func::binary::EagerBinaryFunc::propagates_nulls( + self, + ); + let nullable = output.nullable; + output + .nullable( + nullable + || (propagates_nulls + && (input_type_a.nullable || input_type_b.nullable)), + ) + } + fn is_infix_op(&self) -> bool { + true + } +} +impl std::fmt::Display for JsonbGetInt64Stringify { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("->>") + } +} +fn jsonb_get_int64_stringify<'a>( + a: Datum<'a>, + i: i64, + temp_storage: &'a RowArena, +) -> Option<&'a str> { + match a { + Datum::List(list) => { + let i = if i >= 0 { + usize::cast_from(i.unsigned_abs()) + } else { + let i = usize::cast_from(i.unsigned_abs()); + (list.iter().count()).wrapping_sub(i) + }; + match list.iter().nth(i) { + Some(d) => jsonb_stringify(d, temp_storage), + None => None, + } + } + Datum::Map(_) => None, + _ => if i == 0 || i == -1 { jsonb_stringify(a, temp_storage) } else { None } + } +} diff --git a/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_path.snap b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_path.snap new file mode 100644 index 0000000000000..bfa1626bb4430 --- /dev/null +++ b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_path.snap @@ -0,0 +1,98 @@ +--- +source: src/expr/src/scalar/func.rs +expression: "#[sqlfunc(\n sqlname = \"#>\",\n output_type = \"Option\",\n is_infix_op = true\n)]\nfn jsonb_get_path<'a>(a: Datum<'a>, b: Array<'a>) -> Datum<'a> {\n let mut json = a;\n let path = b.elements();\n for key in path.iter() {\n let key = match key {\n Datum::String(s) => s,\n Datum::Null => return Datum::Null,\n _ => unreachable!(\"keys in jsonb_get_path known to be strings\"),\n };\n json = match json {\n Datum::Map(map) => {\n match map.iter().find(|(k, _)| key == *k) {\n Some((_k, v)) => v,\n None => return Datum::Null,\n }\n }\n Datum::List(list) => {\n match strconv::parse_int64(key) {\n Ok(i) => {\n let i = if i >= 0 {\n usize::cast_from(i.unsigned_abs())\n } else {\n let i = usize::cast_from(i.unsigned_abs());\n (list.iter().count()).wrapping_sub(i)\n };\n match list.iter().nth(i) {\n Some(e) => e,\n None => return Datum::Null,\n }\n }\n Err(_) => return Datum::Null,\n }\n }\n _ => return Datum::Null,\n };\n }\n json\n}\n" +--- +#[derive( + proptest_derive::Arbitrary, + Ord, + PartialOrd, + Clone, + Debug, + Eq, + PartialEq, + serde::Serialize, + serde::Deserialize, + Hash, + mz_lowertest::MzReflect +)] +pub struct JsonbGetPath; +impl<'a> crate::func::binary::EagerBinaryFunc<'a> for JsonbGetPath { + type Input1 = Datum<'a>; + type Input2 = Array<'a>; + type Output = Datum<'a>; + fn call( + &self, + a: Self::Input1, + b: Self::Input2, + temp_storage: &'a mz_repr::RowArena, + ) -> Self::Output { + jsonb_get_path(a, b) + } + fn output_type( + &self, + input_type_a: mz_repr::SqlColumnType, + input_type_b: mz_repr::SqlColumnType, + ) -> mz_repr::SqlColumnType { + use mz_repr::AsColumnType; + let output = >::as_column_type(); + let propagates_nulls = crate::func::binary::EagerBinaryFunc::propagates_nulls( + self, + ); + let nullable = output.nullable; + output + .nullable( + nullable + || (propagates_nulls + && (input_type_a.nullable || input_type_b.nullable)), + ) + } + fn introduces_nulls(&self) -> bool { + as ::mz_repr::DatumType<'_, ()>>::nullable() + } + fn is_infix_op(&self) -> bool { + true + } +} +impl std::fmt::Display for JsonbGetPath { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("#>") + } +} +fn jsonb_get_path<'a>(a: Datum<'a>, b: Array<'a>) -> Datum<'a> { + let mut json = a; + let path = b.elements(); + for key in path.iter() { + let key = match key { + Datum::String(s) => s, + Datum::Null => return Datum::Null, + _ => unreachable!("keys in jsonb_get_path known to be strings"), + }; + json = match json { + Datum::Map(map) => { + match map.iter().find(|(k, _)| key == *k) { + Some((_k, v)) => v, + None => return Datum::Null, + } + } + Datum::List(list) => { + match strconv::parse_int64(key) { + Ok(i) => { + let i = if i >= 0 { + usize::cast_from(i.unsigned_abs()) + } else { + let i = usize::cast_from(i.unsigned_abs()); + (list.iter().count()).wrapping_sub(i) + }; + match list.iter().nth(i) { + Some(e) => e, + None => return Datum::Null, + } + } + Err(_) => return Datum::Null, + } + } + _ => return Datum::Null, + }; + } + json +} diff --git a/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_path_stringify.snap b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_path_stringify.snap new file mode 100644 index 0000000000000..9619517218b37 --- /dev/null +++ b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_path_stringify.snap @@ -0,0 +1,65 @@ +--- +source: src/expr/src/scalar/func.rs +expression: "#[sqlfunc(sqlname = \"#>>\", is_infix_op = true)]\nfn jsonb_get_path_stringify<'a>(\n a: Datum<'a>,\n b: Array<'a>,\n temp_storage: &'a RowArena,\n) -> Option<&'a str> {\n let json = jsonb_get_path(a, b);\n jsonb_stringify(json, temp_storage)\n}\n" +--- +#[derive( + proptest_derive::Arbitrary, + Ord, + PartialOrd, + Clone, + Debug, + Eq, + PartialEq, + serde::Serialize, + serde::Deserialize, + Hash, + mz_lowertest::MzReflect +)] +pub struct JsonbGetPathStringify; +impl<'a> crate::func::binary::EagerBinaryFunc<'a> for JsonbGetPathStringify { + type Input1 = Datum<'a>; + type Input2 = Array<'a>; + type Output = Option<&'a str>; + fn call( + &self, + a: Self::Input1, + b: Self::Input2, + temp_storage: &'a mz_repr::RowArena, + ) -> Self::Output { + jsonb_get_path_stringify(a, b, temp_storage) + } + fn output_type( + &self, + input_type_a: mz_repr::SqlColumnType, + input_type_b: mz_repr::SqlColumnType, + ) -> mz_repr::SqlColumnType { + use mz_repr::AsColumnType; + let output = Self::Output::as_column_type(); + let propagates_nulls = crate::func::binary::EagerBinaryFunc::propagates_nulls( + self, + ); + let nullable = output.nullable; + output + .nullable( + nullable + || (propagates_nulls + && (input_type_a.nullable || input_type_b.nullable)), + ) + } + fn is_infix_op(&self) -> bool { + true + } +} +impl std::fmt::Display for JsonbGetPathStringify { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("#>>") + } +} +fn jsonb_get_path_stringify<'a>( + a: Datum<'a>, + b: Array<'a>, + temp_storage: &'a RowArena, +) -> Option<&'a str> { + let json = jsonb_get_path(a, b); + jsonb_stringify(json, temp_storage) +} diff --git a/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_string.snap b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_string.snap new file mode 100644 index 0000000000000..a398a8bc11f27 --- /dev/null +++ b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_string.snap @@ -0,0 +1,68 @@ +--- +source: src/expr/src/scalar/func.rs +expression: "#[sqlfunc(sqlname = \"->\", output_type = \"Option\")]\nfn jsonb_get_string<'a>(a: Datum<'a>, k: &str) -> Datum<'a> {\n match a {\n Datum::Map(dict) => {\n match dict.iter().find(|(k2, _v)| k == *k2) {\n Some((_k, v)) => v,\n None => Datum::Null,\n }\n }\n _ => Datum::Null,\n }\n}\n" +--- +#[derive( + proptest_derive::Arbitrary, + Ord, + PartialOrd, + Clone, + Debug, + Eq, + PartialEq, + serde::Serialize, + serde::Deserialize, + Hash, + mz_lowertest::MzReflect +)] +pub struct JsonbGetString; +impl<'a> crate::func::binary::EagerBinaryFunc<'a> for JsonbGetString { + type Input1 = Datum<'a>; + type Input2 = &'a str; + type Output = Datum<'a>; + fn call( + &self, + a: Self::Input1, + b: Self::Input2, + temp_storage: &'a mz_repr::RowArena, + ) -> Self::Output { + jsonb_get_string(a, b) + } + fn output_type( + &self, + input_type_a: mz_repr::SqlColumnType, + input_type_b: mz_repr::SqlColumnType, + ) -> mz_repr::SqlColumnType { + use mz_repr::AsColumnType; + let output = >::as_column_type(); + let propagates_nulls = crate::func::binary::EagerBinaryFunc::propagates_nulls( + self, + ); + let nullable = output.nullable; + output + .nullable( + nullable + || (propagates_nulls + && (input_type_a.nullable || input_type_b.nullable)), + ) + } + fn introduces_nulls(&self) -> bool { + as ::mz_repr::DatumType<'_, ()>>::nullable() + } +} +impl std::fmt::Display for JsonbGetString { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("->") + } +} +fn jsonb_get_string<'a>(a: Datum<'a>, k: &str) -> Datum<'a> { + match a { + Datum::Map(dict) => { + match dict.iter().find(|(k2, _v)| k == *k2) { + Some((_k, v)) => v, + None => Datum::Null, + } + } + _ => Datum::Null, + } +} diff --git a/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_string_stringify.snap b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_string_stringify.snap new file mode 100644 index 0000000000000..05843adccda3a --- /dev/null +++ b/src/expr/src/scalar/snapshots/mz_expr__scalar__func__jsonb_get_string_stringify.snap @@ -0,0 +1,72 @@ +--- +source: src/expr/src/scalar/func.rs +expression: "#[sqlfunc(sqlname = \"->>\", is_infix_op = true)]\nfn jsonb_get_string_stringify<'a>(\n a: Datum<'a>,\n k: &str,\n temp_storage: &'a RowArena,\n) -> Option<&'a str> {\n match a {\n Datum::Map(dict) => {\n match dict.iter().find(|(k2, _v)| k == *k2) {\n Some((_k, v)) => jsonb_stringify(v, temp_storage),\n None => None,\n }\n }\n _ => None,\n }\n}\n" +--- +#[derive( + proptest_derive::Arbitrary, + Ord, + PartialOrd, + Clone, + Debug, + Eq, + PartialEq, + serde::Serialize, + serde::Deserialize, + Hash, + mz_lowertest::MzReflect +)] +pub struct JsonbGetStringStringify; +impl<'a> crate::func::binary::EagerBinaryFunc<'a> for JsonbGetStringStringify { + type Input1 = Datum<'a>; + type Input2 = &'a str; + type Output = Option<&'a str>; + fn call( + &self, + a: Self::Input1, + b: Self::Input2, + temp_storage: &'a mz_repr::RowArena, + ) -> Self::Output { + jsonb_get_string_stringify(a, b, temp_storage) + } + fn output_type( + &self, + input_type_a: mz_repr::SqlColumnType, + input_type_b: mz_repr::SqlColumnType, + ) -> mz_repr::SqlColumnType { + use mz_repr::AsColumnType; + let output = Self::Output::as_column_type(); + let propagates_nulls = crate::func::binary::EagerBinaryFunc::propagates_nulls( + self, + ); + let nullable = output.nullable; + output + .nullable( + nullable + || (propagates_nulls + && (input_type_a.nullable || input_type_b.nullable)), + ) + } + fn is_infix_op(&self) -> bool { + true + } +} +impl std::fmt::Display for JsonbGetStringStringify { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("->>") + } +} +fn jsonb_get_string_stringify<'a>( + a: Datum<'a>, + k: &str, + temp_storage: &'a RowArena, +) -> Option<&'a str> { + match a { + Datum::Map(dict) => { + match dict.iter().find(|(k2, _v)| k == *k2) { + Some((_k, v)) => jsonb_stringify(v, temp_storage), + None => None, + } + } + _ => None, + } +} diff --git a/src/sql/src/func.rs b/src/sql/src/func.rs index 231a50068d475..86506e28008ac 100644 --- a/src/sql/src/func.rs +++ b/src/sql/src/func.rs @@ -3353,7 +3353,7 @@ pub static PG_CATALOG_BUILTINS: LazyLock> = LazyLoc params!(Jsonb) => Operation::unary(move |_ecx, jsonb| { Ok(TableFuncPlan { imp: TableFuncImpl::CallTable { - func: TableFunc::JsonbArrayElements { stringify: false }, + func: TableFunc::JsonbArrayElements, exprs: vec![jsonb], }, column_names: vec!["value".into()], @@ -3364,7 +3364,7 @@ pub static PG_CATALOG_BUILTINS: LazyLock> = LazyLoc params!(Jsonb) => Operation::unary(move |_ecx, jsonb| { Ok(TableFuncPlan { imp: TableFuncImpl::CallTable { - func: TableFunc::JsonbArrayElements { stringify: true }, + func: TableFunc::JsonbArrayElementsStringify, exprs: vec![jsonb], }, column_names: vec!["value".into()], @@ -3375,7 +3375,7 @@ pub static PG_CATALOG_BUILTINS: LazyLock> = LazyLoc params!(Jsonb) => Operation::unary(move |_ecx, jsonb| { Ok(TableFuncPlan { imp: TableFuncImpl::CallTable { - func: TableFunc::JsonbEach { stringify: false }, + func: TableFunc::JsonbEach, exprs: vec![jsonb], }, column_names: vec!["key".into(), "value".into()], @@ -3386,7 +3386,7 @@ pub static PG_CATALOG_BUILTINS: LazyLock> = LazyLoc params!(Jsonb) => Operation::unary(move |_ecx, jsonb| { Ok(TableFuncPlan { imp: TableFuncImpl::CallTable { - func: TableFunc::JsonbEach { stringify: true }, + func: TableFunc::JsonbEachStringify, exprs: vec![jsonb], }, column_names: vec!["key".into(), "value".into()], @@ -4781,19 +4781,19 @@ pub static OP_IMPLS: LazyLock> = LazyLock::new(|| { // JSON, MAP, RANGE, LIST, ARRAY "->" => Scalar { - params!(Jsonb, Int64) => BinaryFunc::JsonbGetInt64 => Jsonb, 3212; - params!(Jsonb, String) => BinaryFunc::JsonbGetString => Jsonb, 3211; + params!(Jsonb, Int64) => BF::from(func::JsonbGetInt64) => Jsonb, 3212; + params!(Jsonb, String) => BF::from(func::JsonbGetString) => Jsonb, 3211; params!(MapAny, String) => BF::from(func::MapGetValue) => Any, oid::OP_GET_VALUE_MAP_OID; }, "->>" => Scalar { - params!(Jsonb, Int64) => BinaryFunc::JsonbGetInt64Stringify => String, 3481; - params!(Jsonb, String) => BinaryFunc::JsonbGetStringStringify => String, 3477; + params!(Jsonb, Int64) => BF::from(func::JsonbGetInt64Stringify) => String, 3481; + params!(Jsonb, String) => BF::from(func::JsonbGetStringStringify) => String, 3477; }, "#>" => Scalar { - params!(Jsonb, SqlScalarType::Array(Box::new(SqlScalarType::String))) => BinaryFunc::JsonbGetPath => Jsonb, 3213; + params!(Jsonb, SqlScalarType::Array(Box::new(SqlScalarType::String))) => BF::from(func::JsonbGetPath) => Jsonb, 3213; }, "#>>" => Scalar { - params!(Jsonb, SqlScalarType::Array(Box::new(SqlScalarType::String))) => BinaryFunc::JsonbGetPathStringify => String, 3206; + params!(Jsonb, SqlScalarType::Array(Box::new(SqlScalarType::String))) => BF::from(func::JsonbGetPathStringify) => String, 3206; }, "@>" => Scalar { params!(Jsonb, Jsonb) => BF::from(func::JsonbContainsJsonb) => Bool, 3246; diff --git a/src/sql/src/plan/query.rs b/src/sql/src/plan/query.rs index 8f4e6bc0161dd..f6b9c8680d29c 100644 --- a/src/sql/src/plan/query.rs +++ b/src/sql/src/plan/query.rs @@ -4540,7 +4540,7 @@ fn plan_subscript_jsonb( }, exprs, ), - BinaryFunc::JsonbGetPath, + expr_func::JsonbGetPath, ); Ok(expr.into()) }