Skip to content

Commit

Permalink
Merge pull request #5419 from fkuner/feature-date-add1
Browse files Browse the repository at this point in the history
feat(function): support date_add for new parser
  • Loading branch information
BohuTANG authored May 17, 2022
2 parents 93bf755 + 5e7071e commit 87e5228
Show file tree
Hide file tree
Showing 14 changed files with 438 additions and 53 deletions.
35 changes: 25 additions & 10 deletions common/ast/src/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@ pub enum Expr<'a> {
span: &'a [Token<'a>],
exprs: Vec<Expr<'a>>,
},
/// The `Interval 1 DAY` expr
Interval {
span: &'a [Token<'a>],
expr: Box<Expr<'a>>,
unit: IntervalKind,
},
DateAdd {
span: &'a [Token<'a>],
date: Box<Expr<'a>>,
interval: Box<Expr<'a>>,
unit: IntervalKind,
},
}

#[derive(Debug, Clone, PartialEq)]
Expand All @@ -170,7 +182,6 @@ pub enum Literal {
// Quoted string literal value
String(String),
Boolean(bool),
Interval(Interval),
CurrentTimestamp,
Null,
}
Expand Down Expand Up @@ -208,12 +219,6 @@ pub enum TypeName {
Variant,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Interval {
pub value: String,
pub kind: IntervalKind,
}

#[derive(Debug, Clone, PartialEq)]
pub enum TrimWhere {
Both,
Expand Down Expand Up @@ -286,6 +291,8 @@ impl<'a> Expr<'a> {
Expr::Subquery { span, .. } => span,
Expr::MapAccess { span, .. } => span,
Expr::Array { span, .. } => span,
Expr::Interval { span, .. } => span,
Expr::DateAdd { span, .. } => span,
}
}
}
Expand Down Expand Up @@ -485,9 +492,6 @@ impl Display for Literal {
Literal::CurrentTimestamp => {
write!(f, "CURRENT_TIMESTAMP")
}
Literal::Interval(interval) => {
write!(f, "INTERVAL {} {}", interval.value, interval.kind)
}
Literal::Null => {
write!(f, "NULL")
}
Expand Down Expand Up @@ -689,6 +693,17 @@ impl<'a> Display for Expr<'a> {
write_comma_separated_list(f, exprs)?;
write!(f, "]")?;
}
Expr::Interval { expr, unit, .. } => {
write!(f, "INTERVAL {expr} {unit}")?;
}
Expr::DateAdd {
date,
interval,
unit,
..
} => {
write!(f, "DATEADD({date}, INTERVAL {interval} {unit})")?;
}
}

Ok(())
Expand Down
103 changes: 83 additions & 20 deletions common/ast/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,22 +169,34 @@ pub enum ExprElement<'a> {
column: Identifier<'a>,
},
/// `IS NULL` expression
IsNull { not: bool },
IsNull {
not: bool,
},
/// `IS NOT NULL` expression
/// `[ NOT ] IN (list, ...)`
InList { list: Vec<Expr<'a>>, not: bool },
InList {
list: Vec<Expr<'a>>,
not: bool,
},
/// `[ NOT ] IN (SELECT ...)`
InSubquery { subquery: Box<Query<'a>>, not: bool },
InSubquery {
subquery: Box<Query<'a>>,
not: bool,
},
/// `BETWEEN ... AND ...`
Between {
low: Box<Expr<'a>>,
high: Box<Expr<'a>>,
not: bool,
},
/// Binary operation
BinaryOp { op: BinaryOperator },
BinaryOp {
op: BinaryOperator,
},
/// Unary operation
UnaryOp { op: UnaryOperator },
UnaryOp {
op: UnaryOperator,
},
/// `CAST` expression, like `CAST(expr AS target_type)`
Cast {
expr: Box<Expr<'a>>,
Expand All @@ -196,7 +208,9 @@ pub enum ExprElement<'a> {
target_type: TypeName,
},
/// `::<type_name>` expression
PgCast { target_type: TypeName },
PgCast {
target_type: TypeName,
},
/// EXTRACT(IntervalKind FROM <expr>)
Extract {
field: IntervalKind,
Expand All @@ -222,11 +236,15 @@ pub enum ExprElement<'a> {
trim_where: Option<(TrimWhere, Box<Expr<'a>>)>,
},
/// A literal value, such as string, number, date or NULL
Literal { lit: Literal },
Literal {
lit: Literal,
},
/// `Count(*)` expression
CountAll,
/// `(foo, bar)`
Tuple { exprs: Vec<Expr<'a>> },
Tuple {
exprs: Vec<Expr<'a>>,
},
/// Scalar function call
FunctionCall {
/// Set to true if the function is aggregate function with `DISTINCT`, like `COUNT(DISTINCT a)`
Expand All @@ -243,15 +261,32 @@ pub enum ExprElement<'a> {
else_result: Option<Box<Expr<'a>>>,
},
/// `EXISTS` expression
Exists { subquery: Query<'a> },
Exists {
subquery: Query<'a>,
},
/// Scalar subquery, which will only return a single row with a single column.
Subquery { subquery: Query<'a> },
Subquery {
subquery: Query<'a>,
},
/// Access elements of `Array`, `Object` and `Variant` by index or key, like `arr[0]`, or `obj:k1`
MapAccess { accessor: MapAccessor<'a> },
MapAccess {
accessor: MapAccessor<'a>,
},
/// An expression between parentheses
Group(Expr<'a>),
/// `[1, 2, 3]`
Array { exprs: Vec<Expr<'a>> },
Array {
exprs: Vec<Expr<'a>>,
},
Interval {
expr: Expr<'a>,
unit: IntervalKind,
},
DateAdd {
date: Expr<'a>,
interval: Expr<'a>,
unit: IntervalKind,
},
}

struct ExprParser;
Expand Down Expand Up @@ -410,6 +445,21 @@ impl<'a, I: Iterator<Item = WithSpan<'a>>> PrattParser<I> for ExprParser {
span: elem.span.0,
exprs,
},
ExprElement::Interval { expr, unit } => Expr::Interval {
span: elem.span.0,
expr: Box::new(expr),
unit,
},
ExprElement::DateAdd {
date,
interval,
unit,
} => Expr::DateAdd {
span: elem.span.0,
date: Box::new(date),
interval: Box::new(interval),
unit,
},
_ => unreachable!(),
};
Ok(expr)
Expand Down Expand Up @@ -740,7 +790,25 @@ pub fn expr_element(i: Input) -> IResult<WithSpan> {
ExprElement::Array { exprs }
},
);

let date_add = map(
rule! {
DATEADD ~ "(" ~ #subexpr(0) ~ "," ~ #subexpr(0) ~ "," ~ #interval_kind ~ ")"
},
|(_, _, date, _, interval, _, unit, _)| ExprElement::DateAdd {
date,
interval,
unit,
},
);
let interval = map(
rule! {
INTERVAL ~ #subexpr(0) ~ #interval_kind
},
|(_, operand, unit)| ExprElement::Interval {
expr: operand,
unit,
},
);
let (rest, (span, elem)) = consumed(alt((
rule! (
#is_null : "`... IS [NOT] NULL`"
Expand All @@ -750,6 +818,8 @@ pub fn expr_element(i: Input) -> IResult<WithSpan> {
| #binary_op : "<operator>"
| #unary_op : "<operator>"
| #cast : "`CAST(... AS ...)`"
| #date_add: "`DATEADD(..., ..., (YEAR| MONTH | DAY | HOUR | MINUTE | SECOND | DOY | DOW))`"
| #interval: "`INTERVAL ... (YEAR| MONTH | DAY | HOUR | MINUTE | SECOND | DOY | DOW)`"
| #pg_cast : "`::<type_name>`"
| #extract : "`EXTRACT((YEAR | MONTH | DAY | HOUR | MINUTE | SECOND) FROM ...)`"
| #position : "`POSITION(... IN ...)`"
Expand Down Expand Up @@ -828,20 +898,13 @@ pub fn literal(i: Input) -> IResult<Literal> {
value(Literal::Boolean(true), rule! { TRUE }),
value(Literal::Boolean(false), rule! { FALSE }),
));
let interval = map(
rule! {
INTERVAL ~ #literal_string ~ #interval_kind
},
|(_, value, field)| Literal::Interval(Interval { value, kind: field }),
);
let current_timestamp = value(Literal::CurrentTimestamp, rule! { CURRENT_TIMESTAMP });
let null = value(Literal::Null, rule! { NULL });

rule!(
#string
| #number
| #boolean
| #interval : "`INTERVAL '...' (YEAR | MONTH | DAY | ...)`"
| #current_timestamp
| #null
)(i)
Expand Down
14 changes: 13 additions & 1 deletion common/ast/src/parser/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ pub enum TokenKind {
DATABASES,
#[token("DATE", ignore(ascii_case))]
DATE,
#[token("DATE_ADD", ignore(ascii_case))]
DATEADD,
#[token("DATETIME", ignore(ascii_case))]
DATETIME,
#[token("DAY", ignore(ascii_case))]
Expand Down Expand Up @@ -788,7 +790,17 @@ impl TokenKind {
// | TokenKind::UNION
| TokenKind::WHERE
// | TokenKind::WINDOW
| TokenKind::WITH if !after_as => true,
| TokenKind::WITH
| TokenKind::DATEADD
| TokenKind::YEAR
| TokenKind::MONTH
| TokenKind::DAY
| TokenKind::HOUR
| TokenKind::MINUTE
| TokenKind::SECOND
| TokenKind::DOY
| TokenKind::DOW
if !after_as => true,
_ => false
}
}
Expand Down
2 changes: 1 addition & 1 deletion common/ast/tests/it/testdata/expr-error.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ error:
--> SQL:1:10
|
1 | CAST(col1)
| ---- ^ expected `AS`, `,`, `(`, `.`, `IS`, `NOT`, or 46 more ...
| ---- ^ expected `AS`, `,`, `(`, `.`, `IS`, `NOT`, or 47 more ...
| |
| while parsing `CAST(... AS ...)`
| while parsing expression
Expand Down
39 changes: 39 additions & 0 deletions common/functions/src/scalars/dates/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use common_datavalues::IntervalKind;

use super::now::NowFunction;
use super::number_function::ToMondayFunction;
use super::number_function::ToYearFunction;
use super::round_function::Round;
use super::to_interval_function_creator;
use super::AddDaysFunction;
use super::AddMonthsFunction;
use super::AddTimesFunction;
use super::AddYearsFunction;
use super::DateAddFunction;
use super::RoundFunction;
use super::ToDayOfMonthFunction;
use super::ToDayOfWeekFunction;
Expand Down Expand Up @@ -124,5 +128,40 @@ impl DateFunction {
factory.register("subtractHours", AddTimesFunction::desc(-3600));
factory.register("subtractMinutes", AddTimesFunction::desc(-60));
factory.register("subtractSeconds", AddTimesFunction::desc(-1));

factory.register(
"to_interval_year",
to_interval_function_creator(IntervalKind::Year),
);
factory.register(
"to_interval_month",
to_interval_function_creator(IntervalKind::Month),
);
factory.register(
"to_interval_day",
to_interval_function_creator(IntervalKind::Day),
);
factory.register(
"to_interval_hour",
to_interval_function_creator(IntervalKind::Hour),
);
factory.register(
"to_interval_minute",
to_interval_function_creator(IntervalKind::Minute),
);
factory.register(
"to_interval_second",
to_interval_function_creator(IntervalKind::Second),
);
factory.register(
"to_interval_doy",
to_interval_function_creator(IntervalKind::Doy),
);
factory.register(
"to_interval_dow",
to_interval_function_creator(IntervalKind::Dow),
);

factory.register("date_add", DateAddFunction::desc());
}
}
Loading

0 comments on commit 87e5228

Please sign in to comment.