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

Add DATE and TIMESTAMP operators #9691

Merged
merged 5 commits into from
Mar 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 63 additions & 0 deletions dbms/src/Parsers/ExpressionListParsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,69 @@ bool ParserNullityChecking::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
return true;
}

bool ParserDateOperatorExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
auto begin = pos;

/// If no DATE keyword, go to the nested parser.
if (!ParserKeyword("DATE").ignore(pos, expected))
return next_parser.parse(pos, node, expected);

ASTPtr expr;
if (!ParserStringLiteral().parse(pos, expr, expected))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But why it's just for literals?
Does SQL standard support DATE x?

Copy link
Contributor Author

@4ertus2 4ertus2 Mar 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sayes this:

F051-01 DATE data type (including support of DATE literal)
— Subclause 5.3, “<literal>”: The <date literal> form of <datetime literal>
— Subclause 6.1, “<data type>”: The DATE <datetime type>
— Subclause 6.31, “<datetime value expression>”: For values of type DATE

<datetime literal> ::= <date literal> | <time literal> | <timestamp literal>
<date literal> ::= DATE <date string>
<time literal> ::= TIME <time string>
<timestamp literal> ::= TIMESTAMP <timestamp string>

<date string> ::= <quote> <unquoted date string> <quote>
<unquoted date string> ::= <date value>
<date value> ::= <years value> <minus sign> <months value> <minus sign> <days value>

I haven't found any place where it would be applyed to non literal. In MySQL it's also possible to apply DATE operator for timestamp string to exptract date. In PG it's possible to cropp seconds in timestamp string. But for SQL compatibility we need TIME, 6-digits afrer dot TIMESTAMP and lots of copmarison, timezones and operation results rules.

{
pos = begin;
return next_parser.parse(pos, node, expected);
}

/// the function corresponding to the operator
auto function = std::make_shared<ASTFunction>();

/// function arguments
auto exp_list = std::make_shared<ASTExpressionList>();

/// the first argument of the function is the previous element, the second is the next one
function->name = "toDate";
function->arguments = exp_list;
function->children.push_back(exp_list);

exp_list->children.push_back(expr);

node = function;
return true;
}

bool ParserTimestampOperatorExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
auto begin = pos;

/// If no TIMESTAMP keyword, go to the nested parser.
if (!ParserKeyword("TIMESTAMP").ignore(pos, expected))
return next_parser.parse(pos, node, expected);

ASTPtr expr;
if (!ParserStringLiteral().parse(pos, expr, expected))
{
pos = begin;
return next_parser.parse(pos, node, expected);
}

/// the function corresponding to the operator
auto function = std::make_shared<ASTFunction>();

/// function arguments
auto exp_list = std::make_shared<ASTExpressionList>();

/// the first argument of the function is the previous element, the second is the next one
function->name = "toDateTime";
function->arguments = exp_list;
function->children.push_back(exp_list);

exp_list->children.push_back(expr);

node = function;
return true;
}

bool ParserIntervalOperatorExpression::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
Expand Down
28 changes: 23 additions & 5 deletions dbms/src/Parsers/ExpressionListParsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,34 +159,52 @@ class ParserMultiplicativeExpression : public IParserBase
ParserLeftAssociativeBinaryOperatorList operator_parser {operators, std::make_unique<ParserUnaryMinusExpression>()};

protected:
const char * getName() const override{ return "multiplicative expression"; }
const char * getName() const override { return "multiplicative expression"; }

bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
{
return operator_parser.parse(pos, node, expected);
}
};

/// DATE operator. "DATE '2001-01-01'" would be parsed as "toDate('2001-01-01')".
class ParserDateOperatorExpression : public IParserBase
{
protected:
ParserMultiplicativeExpression next_parser;

const char * getName() const override { return "DATE operator expression"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};

/// TIMESTAMP operator. "TIMESTAMP '2001-01-01 12:34:56'" would be parsed as "toDateTime('2001-01-01 12:34:56')".
class ParserTimestampOperatorExpression : public IParserBase
{
protected:
ParserDateOperatorExpression next_parser;

const char * getName() const override { return "TIMESTAMP operator expression"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};

/// Optional conversion to INTERVAL data type. Example: "INTERVAL x SECOND" parsed as "toIntervalSecond(x)".
class ParserIntervalOperatorExpression : public IParserBase
{
protected:
ParserMultiplicativeExpression next_parser;
ParserTimestampOperatorExpression next_parser;

const char * getName() const override{ return "INTERVAL operator expression"; }
const char * getName() const override { return "INTERVAL operator expression"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};


class ParserAdditiveExpression : public IParserBase
{
private:
static const char * operators[];
ParserLeftAssociativeBinaryOperatorList operator_parser {operators, std::make_unique<ParserIntervalOperatorExpression>()};

protected:
const char * getName() const override{ return "additive expression"; }
const char * getName() const override { return "additive expression"; }

bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
{
Expand Down
4 changes: 2 additions & 2 deletions dbms/tests/queries/0_stateless/01053_if_chain_check.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
SET max_parser_depth = 4000;
SELECT x FROM (SELECT number % 16 = 0 ? nan : (number % 24 = 0 ? NULL : (number % 37 = 0 ? nan : (number % 34 = 0 ? nan : (number % 3 = 0 ? NULL : (number % 68 = 0 ? 42 : (number % 28 = 0 ? nan : (number % 46 = 0 ? nan : (number % 13 = 0 ? nan : (number % 27 = 0 ? NULL : (number % 39 = 0 ? NULL : (number % 27 = 0 ? NULL : (number % 30 = 0 ? NULL : (number % 72 = 0 ? NULL : (number % 36 = 0 ? NULL : (number % 51 = 0 ? NULL : (number % 58 = 0 ? nan : (number % 26 = 0 ? 42 : (number % 13 = 0 ? nan : (number % 12 = 0 ? NULL : (number % 22 = 0 ? nan : (number % 36 = 0 ? NULL : (number % 63 = 0 ? NULL : (number % 27 = 0 ? NULL : (number % 18 = 0 ? NULL : (number % 69 = 0 ? NULL : (number % 76 = 0 ? nan : (number % 42 = 0 ? NULL : (number % 9 = 0 ? NULL : (toFloat64(number)))))))))))))))))))))))))))))) AS x FROM system.numbers LIMIT 1001) ORDER BY x ASC NULLS FIRST;

SELECT x FROM (SELECT number % 22 = 0 ? nan : (number % 56 = 0 ? 42 : (number % 45 = 0 ? NULL : (number % 47 = 0 ? 42 : (number % 39 = 0 ? NULL : (number % 1 = 0 ? nan : (number % 43 = 0 ? nan : (number % 40 = 0 ? nan : (number % 42 = 0 ? NULL : (number % 26 = 0 ? 42 : (number % 41 = 0 ? 42 : (number % 6 = 0 ? NULL : (number % 39 = 0 ? NULL : (number % 34 = 0 ? nan : (number % 74 = 0 ? 42 : (number % 40 = 0 ? nan : (number % 37 = 0 ? nan : (number % 51 = 0 ? NULL : (number % 46 = 0 ? nan : (toFloat64(number)))))))))))))))))))) AS x FROM system.numbers LIMIT 1001) ORDER BY x ASC NULLS FIRST;
SELECT x FROM (SELECT number % 22 = 0 ? nan : (number % 56 = 0 ? 42 : (number % 45 = 0 ? NULL : (number % 47 = 0 ? 42 : (number % 39 = 0 ? NULL : (number % 1 = 0 ? nan : (number % 43 = 0 ? nan : (number % 40 = 0 ? nan : (number % 42 = 0 ? NULL : (number % 26 = 0 ? 42 : (number % 41 = 0 ? 42 : (number % 6 = 0 ? NULL : (number % 39 = 0 ? NULL : (number % 34 = 0 ? nan : (number % 74 = 0 ? 42 : (number % 40 = 0 ? nan : (number % 37 = 0 ? nan : (number % 51 = 0 ? NULL : (number % 46 = 0 ? nan : (toFloat64(number)))))))))))))))))))) AS x FROM system.numbers LIMIT 1001) ORDER BY x ASC NULLS FIRST;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-
Maximum parse depth (40) exceeded.
Maximum parse depth (42) exceeded.
-
Maximum parse depth (20) exceeded.
4 changes: 2 additions & 2 deletions dbms/tests/queries/0_stateless/01062_max_parser_depth.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
. $CURDIR/../shell_config.sh

echo 'select 1' | ${CLICKHOUSE_CURL} -sSg "${CLICKHOUSE_URL}&max_parser_depth=40" -d @- 2>&1 | grep -oP "Maximum parse depth .* exceeded."
echo 'select 1' | ${CLICKHOUSE_CURL} -sSg "${CLICKHOUSE_URL}&max_parser_depth=42" -d @- 2>&1 | grep -oP "Maximum parse depth .* exceeded."
echo -
echo 'select (1+1)*(2+1)' | ${CLICKHOUSE_CURL} -sSg "${CLICKHOUSE_URL}&max_parser_depth=40" -d @- 2>&1 | grep -oP "Maximum parse depth .* exceeded."
echo 'select (1+1)*(2+1)' | ${CLICKHOUSE_CURL} -sSg "${CLICKHOUSE_URL}&max_parser_depth=42" -d @- 2>&1 | grep -oP "Maximum parse depth .* exceeded."
echo -
echo 'select 1' | ${CLICKHOUSE_CURL} -sSg "${CLICKHOUSE_URL}&max_parser_depth=20" -d @- 2>&1 | grep -oP "Maximum parse depth .* exceeded."
42 changes: 21 additions & 21 deletions dbms/tests/queries/0_stateless/01095_tpch_like_smoke.sql
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ select
from
lineitem
where
l_shipdate <= toDate('1998-12-01') - interval 90 day
l_shipdate <= date '1998-12-01' - interval 90 day
group by
l_returnflag,
l_linestatus
Expand Down Expand Up @@ -197,8 +197,8 @@ where
c_mktsegment = 'BUILDING'
and c_custkey = o_custkey
and l_orderkey = o_orderkey
and o_orderdate < toDate('1995-03-15')
and l_shipdate > toDate('1995-03-15')
and o_orderdate < date '1995-03-15'
and l_shipdate > date '1995-03-15'
group by
l_orderkey,
o_orderdate,
Expand All @@ -215,8 +215,8 @@ limit 10;
-- from
-- orders
-- where
-- o_orderdate >= toDate('1993-07-01')
-- and o_orderdate < toDate('1993-07-01') + interval '3' month
-- o_orderdate >= date '1993-07-01'
-- and o_orderdate < date '1993-07-01' + interval '3' month
-- and exists (
-- select
-- *
Expand Down Expand Up @@ -250,8 +250,8 @@ where
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'ASIA'
and o_orderdate >= toDate('1994-01-01')
and o_orderdate < toDate('1994-01-01') + interval '1' year
and o_orderdate >= date '1994-01-01'
and o_orderdate < date '1994-01-01' + interval '1' year
group by
n_name
order by
Expand All @@ -263,8 +263,8 @@ select
from
lineitem
where
l_shipdate >= toDate('1994-01-01')
and l_shipdate < toDate('1994-01-01') + interval '1' year
l_shipdate >= date '1994-01-01'
and l_shipdate < date '1994-01-01' + interval '1' year
and l_discount between toDecimal32(0.06, 2) - toDecimal32(0.01, 2)
and toDecimal32(0.06, 2) + toDecimal32(0.01, 2)
and l_quantity < 24;
Expand Down Expand Up @@ -299,7 +299,7 @@ where
-- (n1.n_name = 'FRANCE' and n2.n_name = 'GERMANY')
-- or (n1.n_name = 'GERMANY' and n2.n_name = 'FRANCE')
-- )
-- and l_shipdate between toDate('1995-01-01') and toDate('1996-12-31')
-- and l_shipdate between date '1995-01-01' and date '1996-12-31'
-- ) as shipping
-- group by
-- supp_nation,
Expand Down Expand Up @@ -341,7 +341,7 @@ where
-- and n1.n_regionkey = r_regionkey
-- and r_name = 'AMERICA'
-- and s_nationkey = n2.n_nationkey
-- and o_orderdate between toDate('1995-01-01') and toDate('1996-12-31')
-- and o_orderdate between date '1995-01-01' and date '1996-12-31'
-- and p_type = 'ECONOMY ANODIZED STEEL'
-- ) as all_nations
-- group by
Expand Down Expand Up @@ -401,8 +401,8 @@ from
where
c_custkey = o_custkey
and l_orderkey = o_orderkey
and o_orderdate >= toDate('1993-10-01')
and o_orderdate < toDate('1993-10-01') + interval '3' month
and o_orderdate >= date '1993-10-01'
and o_orderdate < date '1993-10-01' + interval '3' month
and l_returnflag = 'R'
and c_nationkey = n_nationkey
group by
Expand Down Expand Up @@ -472,8 +472,8 @@ where
and l_shipmode in ('MAIL', 'SHIP')
and l_commitdate < l_receiptdate
and l_shipdate < l_commitdate
and l_receiptdate >= toDate('1994-01-01')
and l_receiptdate < toDate('1994-01-01') + interval '1' year
and l_receiptdate >= date '1994-01-01'
and l_receiptdate < date '1994-01-01' + interval '1' year
group by
l_shipmode
order by
Expand Down Expand Up @@ -513,8 +513,8 @@ from
part
where
l_partkey = p_partkey
and l_shipdate >= toDate('1995-09-01')
and l_shipdate < toDate('1995-09-01') + interval '1' month;
and l_shipdate >= date '1995-09-01'
and l_shipdate < date '1995-09-01' + interval '1' month;

-- select 15;
-- create view revenue0 as
Expand All @@ -524,8 +524,8 @@ where
-- from
-- lineitem
-- where
-- l_shipdate >= toDate('1996-01-01')
-- and l_shipdate < toDate('1996-01-01') + interval '3' month
-- l_shipdate >= date '1996-01-01'
-- and l_shipdate < date '1996-01-01' + interval '3' month
-- group by
-- l_suppkey;
-- select
Expand Down Expand Up @@ -702,8 +702,8 @@ where
-- where
-- l_partkey = ps_partkey
-- and l_suppkey = ps_suppkey
-- and l_shipdate >= toDate('1994-01-01')
-- and l_shipdate < toDate('1994-01-01') + interval '1' year
-- and l_shipdate >= date '1994-01-01'
-- and l_shipdate < date '1994-01-01' + interval '1' year
-- )
-- )
-- and s_nationkey = n_nationkey
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
1 1 1
1 1 1
1 1
2001-09-28
2001-10-05 Date
2001-09-24 Date
2001-10-05 Date
2001-09-24 Date
2001-09-28 01:00:00 DateTime
2001-09-27 23:00:00 DateTime
3 Int32
2001-09-29 00:00:00
2001-09-28 00:00:00
140400 Int32
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
select interval 1 second, interval 1 minute, interval 1 hour;
select interval 1 day, interval 1 week, interval 1 month;
select interval 1 quarter, interval 1 year;

select date '2001-09-28';
select (date '2001-09-28' + interval 7 day) x, toTypeName(x);
select (date '2001-10-01' - interval 7 day) x, toTypeName(x);
select (date '2001-09-28' + 7) x, toTypeName(x);
select (date '2001-10-01' - 7) x, toTypeName(x);
select (date '2001-09-28' + interval 1 hour) x, toTypeName(x);
select (date '2001-09-28' - interval 1 hour) x, toTypeName(x);
select (date '2001-10-01' - date '2001-09-28') x, toTypeName(x);
select timestamp '2001-09-28 01:00:00' + interval 23 hour;
select timestamp '2001-09-28 23:00:00' - interval 23 hour;

-- TODO: return interval
select (timestamp '2001-09-29 03:00:00' - timestamp '2001-09-27 12:00:00') x, toTypeName(x); -- interval '1 day 15:00:00'

-- select -interval 23 hour; -- interval '-23:00:00'
-- select interval 1 day + interval 1 hour; -- interval '1 day 01:00:00'
-- select interval '1 day' - interval '1 hour'; -- interval '1 day -01:00:00'

-- select date '2001-09-28' + time '03:00'; -- timestamp '2001-09-28 03:00:00'
-- select time '01:00' + interval '3 hours'; -- time '04:00:00'
-- select time '05:00' - time '03:00'; -- interval '02:00:00'
-- select time '05:00' - interval '2 hours'; -- time '03:00:00'

-- select 900 * interval '1 second'; -- interval '00:15:00'
-- select (21 * interval '1 day') x, toTypeName(x); -- interval '21 days'
-- select (double precision '3.5' * interval '1 hour') x, toTypeName(x); -- interval '03:30:00'
-- select (interval '1 hour' / double precision '1.5') x, toTypeName(x); -- interval '00:40:00'