Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(optimizer): record error contexts when casting composite types #19449

Merged
merged 10 commits into from
Nov 25, 2024
Prev Previous commit
Next Next commit
refine message:
- only show "context" in the bottom level
- show struct field name
- do not expose internal impl of map type, instead, show "key" or "value"

Signed-off-by: Bugen Zhao <i@bugenzhao.com>
  • Loading branch information
BugenZhao committed Nov 21, 2024
commit fc4223348295f029a4d88d0d9f64b4de8a760ac8
2 changes: 1 addition & 1 deletion e2e_test/batch/basic/dml_update.slt.part
Original file line number Diff line number Diff line change
@@ -99,7 +99,7 @@ update t set (v1, v2) = (select '888.88', 999);
db error: ERROR: Failed to run the query

Caused by these errors (recent errors listed first):
1: cannot cast type "record" to "record" in Assign context
1: cannot cast type "record" to "record"
2: cannot cast type "character varying" to "integer" in Assign context


17 changes: 9 additions & 8 deletions src/frontend/planner_test/tests/testdata/output/cast.yaml
Original file line number Diff line number Diff line change
@@ -87,7 +87,7 @@
Failed to bind expression: CAST(CAST('[]' AS INT[]) AS BYTEA[])

Caused by these errors (recent errors listed first):
1: cannot cast type "integer[]" to "bytea[]" in Explicit context
1: cannot cast type "integer[]" to "bytea[]"
2: cannot cast type "integer" to "bytea" in Explicit context
- name: composite type cast error message (struct)
sql: |
@@ -97,9 +97,11 @@
Failed to bind expression: CAST(v AS STRUCT<d STRUCT<e BYTEA>, f BOOLEAN>)

Caused by these errors (recent errors listed first):
1: cannot cast type "struct<a struct<b integer>, c boolean>" to "struct<d struct<e bytea>, f boolean>" in Explicit context
2: cannot cast type "struct<b integer>" to "struct<e bytea>" in Explicit context
3: cannot cast type "integer" to "bytea" in Explicit context
1: cannot cast type "struct<a struct<b integer>, c boolean>" to "struct<d struct<e bytea>, f boolean>"
2: cannot cast struct field "a" to struct field "d"
3: cannot cast type "struct<b integer>" to "struct<e bytea>"
4: cannot cast struct field "b" to struct field "e"
5: cannot cast type "integer" to "bytea" in Explicit context
- name: composite type cast error message (map)
sql: |
create table t (v map(int, int));
@@ -108,7 +110,6 @@
Failed to bind expression: CAST(v AS MAP(INT,BYTEA))

Caused by these errors (recent errors listed first):
1: cannot cast type "map(integer,integer)" to "map(integer,bytea)" in Explicit context
2: cannot cast type "struct<key integer, value integer>[]" to "struct<key integer, value bytea>[]" in Explicit context
3: cannot cast type "struct<key integer, value integer>" to "struct<key integer, value bytea>" in Explicit context
4: cannot cast type "integer" to "bytea" in Explicit context
1: cannot cast type "map(integer,integer)" to "map(integer,bytea)"
2: cannot cast map value
3: cannot cast type "integer" to "bytea" in Explicit context
58 changes: 44 additions & 14 deletions src/frontend/src/expr/type_inference/cast.rs
Original file line number Diff line number Diff line change
@@ -13,12 +13,13 @@
// limitations under the License.

use std::collections::BTreeMap;
use std::error::Error;
use std::sync::LazyLock;

use itertools::Itertools as _;
use parse_display::Display;
use risingwave_common::types::{DataType, DataTypeName};
use risingwave_common::util::iter_util::ZipEqFast;
use risingwave_common::util::iter_util::{ZipEqDebug, ZipEqFast};

use crate::error::ErrorCode;
use crate::expr::function_call::{bail_cast_error, cast_error, CastError, CastResult};
@@ -148,12 +149,18 @@ pub fn cast(source: &DataType, target: &DataType, allows: CastContext) -> Result
canmeh(cast_ok_base(source, target, allows))
}
.map_err(|inner| {
// Only show "in .. context" once in the error source chain.
let in_context = if inner.source().is_none() {
&format!(" in {:?} context", allows)
} else {
""
};
cast_error!(
source = inner,
"cannot cast type \"{}\" to \"{}\" in {:?} context",
"cannot cast type \"{}\" to \"{}\"{}",
source,
target,
allows
in_context,
)
})
}
@@ -181,15 +188,32 @@ fn cast_struct(source: &DataType, target: &DataType, allows: CastContext) -> Cas
bail_cast_error!("cannot cast structs of different lengths");
}
// ... and all fields are castable
lty.types()
.zip_eq_fast(rty.types())
.try_for_each(|(src, dst)| {
if src == dst {
lty.iter().zip_eq_debug(rty.iter()).try_for_each(
|((src_name, src_ty), (dst_name, dst_ty))| {
if src_ty == dst_ty {
Ok(())
} else {
cast(src, dst, allows)
cast(src_ty, dst_ty, allows).map_err(|inner| {
if src_name.is_empty() {
inner
} else if dst_name.is_empty() {
cast_error!(
source = inner,
"cannot cast struct field \"{}\"",
src_name
)
} else {
cast_error!(
source = inner,
"cannot cast struct field \"{}\" to struct field \"{}\"",
src_name,
dst_name
)
}
})
}
})
},
)
}
// The automatic casts to string types are treated as assignment casts, while the automatic
// casts from string types are explicit-only.
@@ -216,11 +240,17 @@ fn cast_array(source: &DataType, target: &DataType, allows: CastContext) -> Cast

fn cast_map(source: &DataType, target: &DataType, allows: CastContext) -> CastResult {
match (source, target) {
(DataType::Map(source_elem), DataType::Map(target_elem)) => cast(
&source_elem.clone().into_list(),
&target_elem.clone().into_list(),
allows,
),
(DataType::Map(source_elem), DataType::Map(target_elem)) => {
if source_elem.key() != target_elem.key() {
cast(source_elem.key(), target_elem.key(), allows)
.map_err(|inner| cast_error!(source = inner, "cannot cast map key"))?;
}
if source_elem.value() != target_elem.value() {
cast(source_elem.value(), target_elem.value(), allows)
.map_err(|inner| cast_error!(source = inner, "cannot cast map value"))?;
}
Ok(())
}
_ => cannot(),
}
}
Loading