Skip to content

Commit

Permalink
refactor(expr): move cast signatures to frontend (#14203)
Browse files Browse the repository at this point in the history
Signed-off-by: Runji Wang <[email protected]>
  • Loading branch information
wangrunji0408 authored Dec 26, 2023
1 parent 590fd7e commit f1f3f7b
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 149 deletions.
143 changes: 0 additions & 143 deletions src/expr/core/src/sig/cast.rs

This file was deleted.

2 changes: 0 additions & 2 deletions src/expr/core/src/sig/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ use crate::expr::BoxedExpression;
use crate::table_function::BoxedTableFunction;
use crate::ExprError;

pub mod cast;

/// The global registry of all function signatures.
pub static FUNCTION_REGISTRY: LazyLock<FunctionRegistry> = LazyLock::new(|| unsafe {
// SAFETY: this function is called after all `#[ctor]` functions are called.
Expand Down
86 changes: 85 additions & 1 deletion src/frontend/src/expr/type_inference/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.

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

use itertools::Itertools as _;
use parse_display::Display;
use risingwave_common::error::ErrorCode;
use risingwave_common::types::{DataType, DataTypeName};
use risingwave_common::util::iter_util::ZipEqFast;
pub use risingwave_expr::sig::cast::*;

use crate::expr::{Expr as _, ExprImpl, InputRef, Literal};

Expand Down Expand Up @@ -165,6 +168,87 @@ pub fn cast_map_array() -> Vec<(DataTypeName, DataTypeName, CastContext)> {
.collect_vec()
}

#[derive(Clone, Debug)]
pub struct CastSig {
pub from_type: DataTypeName,
pub to_type: DataTypeName,
pub context: CastContext,
}

/// The context a cast operation is invoked in. An implicit cast operation is allowed in a context
/// that allows explicit casts, but not vice versa. See details in
/// [PG](https://www.postgresql.org/docs/current/catalog-pg-cast.html).
#[derive(Clone, Copy, Debug, Display, Eq, Ord, PartialEq, PartialOrd)]
pub enum CastContext {
#[display("i")]
Implicit,
#[display("a")]
Assign,
#[display("e")]
Explicit,
}

pub type CastMap = BTreeMap<(DataTypeName, DataTypeName), CastContext>;

pub fn cast_sigs() -> impl Iterator<Item = CastSig> {
CAST_MAP
.iter()
.map(|((from_type, to_type), context)| CastSig {
from_type: *from_type,
to_type: *to_type,
context: *context,
})
}

pub static CAST_MAP: LazyLock<CastMap> = LazyLock::new(|| {
// cast rules:
// 1. implicit cast operations in PG are organized in 3 sequences,
// with the reverse direction being assign cast operations.
// https://github.com/postgres/postgres/blob/e0064f0ff6dfada2695330c6bc1945fa7ae813be/src/include/catalog/pg_cast.dat#L18-L20
// 1. int2 -> int4 -> int8 -> numeric -> float4 -> float8
// 2. date -> timestamp -> timestamptz
// 3. time -> interval
// 2. any -> varchar is assign and varchar -> any is explicit
// 3. jsonb -> bool/number is explicit
// 4. int32 <-> bool is explicit
// 5. timestamp/timestamptz -> time is assign
// 6. int2/int4/int8 -> int256 is implicit and int256 -> float8 is explicit
use DataTypeName::*;
const CAST_TABLE: &[(&str, DataTypeName)] = &[
// 123456789ABCDEF
(". e a", Boolean), // 0
(" .iiiiii a", Int16), // 1
("ea.iiiii a", Int32), // 2
(" aa.iiii a", Int64), // 3
(" aaa.ii a", Decimal), // 4
(" aaaa.i a", Float32), // 5
(" aaaaa. a", Float64), // 6
(" e. a", Int256), // 7
(" .ii a", Date), // 8
(" a.ia a", Timestamp), // 9
(" aa.a a", Timestamptz), // A
(" .i a", Time), // B
(" a. a", Interval), // C
("eeeeeee . a", Jsonb), // D
(" .a", Bytea), // E
("eeeeeeeeeeeeeee.", Varchar), // F
];
let mut map = BTreeMap::new();
for (row, source) in CAST_TABLE {
for ((_, target), c) in CAST_TABLE.iter().zip_eq_fast(row.bytes()) {
let context = match c {
b' ' | b'.' => continue,
b'i' => CastContext::Implicit,
b'a' => CastContext::Assign,
b'e' => CastContext::Explicit,
_ => unreachable!("invalid cast table char"),
};
map.insert((*source, *target), context);
}
}
map
});

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion src/tests/sqlsmith/src/sql_gen/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use itertools::Itertools;
use rand::seq::SliceRandom;
use rand::Rng;
use risingwave_common::types::{DataType, DataTypeName, StructType};
use risingwave_expr::sig::cast::cast_sigs;
use risingwave_expr::sig::FUNCTION_REGISTRY;
use risingwave_frontend::expr::cast_sigs;
use risingwave_sqlparser::ast::{Expr, Ident, OrderByExpr, Value};

use crate::sql_gen::types::data_type_to_ast_data_type;
Expand Down
3 changes: 1 addition & 2 deletions src/tests/sqlsmith/src/sql_gen/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ use std::sync::LazyLock;
use itertools::Itertools;
use risingwave_common::types::{DataType, DataTypeName};
use risingwave_expr::aggregate::AggKind;
use risingwave_expr::sig::cast::{cast_sigs, CastContext, CastSig as RwCastSig};
use risingwave_expr::sig::{FuncSign, FUNCTION_REGISTRY};
use risingwave_frontend::expr::ExprType;
use risingwave_frontend::expr::{cast_sigs, CastContext, CastSig as RwCastSig, ExprType};
use risingwave_sqlparser::ast::{BinaryOperator, DataType as AstDataType, StructField};

pub(super) fn data_type_to_ast_data_type(data_type: &DataType) -> AstDataType {
Expand Down

0 comments on commit f1f3f7b

Please sign in to comment.