diff --git ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g index c903e8f..7072109 100644 --- ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g +++ ql/src/java/org/apache/hadoop/hive/ql/parse/HiveParser.g @@ -109,6 +109,7 @@ TOK_DATE; TOK_DATELITERAL; TOK_DATETIME; TOK_TIMESTAMP; +TOK_TIMESTAMPLITERAL; TOK_STRING; TOK_CHAR; TOK_VARCHAR; diff --git ql/src/java/org/apache/hadoop/hive/ql/parse/IdentifiersParser.g ql/src/java/org/apache/hadoop/hive/ql/parse/IdentifiersParser.g index 13d5255..ce9a9f8 100644 --- ql/src/java/org/apache/hadoop/hive/ql/parse/IdentifiersParser.g +++ ql/src/java/org/apache/hadoop/hive/ql/parse/IdentifiersParser.g @@ -218,6 +218,7 @@ constant : Number | dateLiteral + | timestampLiteral | StringLiteral | stringLiteralSequence | BigintLiteral @@ -250,6 +251,14 @@ dateLiteral } ; +timestampLiteral + : + KW_TIMESTAMP StringLiteral -> + { + adaptor.create(TOK_TIMESTAMPLITERAL, $StringLiteral.text) + } + ; + expression @init { gParent.pushMsg("expression specification", state); } @after { gParent.popMsg(state); } @@ -260,7 +269,6 @@ expression atomExpression : KW_NULL -> TOK_NULL - | dateLiteral | constant | castExpression | caseExpression diff --git ql/src/java/org/apache/hadoop/hive/ql/parse/TypeCheckProcFactory.java ql/src/java/org/apache/hadoop/hive/ql/parse/TypeCheckProcFactory.java index e065983..4d90327 100644 --- ql/src/java/org/apache/hadoop/hive/ql/parse/TypeCheckProcFactory.java +++ ql/src/java/org/apache/hadoop/hive/ql/parse/TypeCheckProcFactory.java @@ -19,6 +19,7 @@ package org.apache.hadoop.hive.ql.parse; import java.sql.Date; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -170,7 +171,8 @@ public static ExprNodeDesc processGByExpr(Node nd, Object procCtx) tf.getStrExprProcessor()); opRules.put(new RuleRegExp("R4", HiveParser.KW_TRUE + "%|" + HiveParser.KW_FALSE + "%"), tf.getBoolExprProcessor()); - opRules.put(new RuleRegExp("R5", HiveParser.TOK_DATELITERAL + "%"), tf.getDateExprProcessor()); + opRules.put(new RuleRegExp("R5", HiveParser.TOK_DATELITERAL + "%|" + + HiveParser.TOK_TIMESTAMPLITERAL + "%"), tf.getDateTimeExprProcessor()); opRules.put(new RuleRegExp("R6", HiveParser.TOK_TABLE_OR_COL + "%"), tf.getColumnExprProcessor()); opRules.put(new RuleRegExp("R7", HiveParser.TOK_SUBQUERY_OP + "%"), @@ -420,7 +422,7 @@ public BoolExprProcessor getBoolExprProcessor() { /** * Processor for date constants. */ - public static class DateExprProcessor implements NodeProcessor { + public static class DateTimeExprProcessor implements NodeProcessor { @Override public Object process(Node nd, Stack stack, NodeProcessorCtx procCtx, @@ -437,14 +439,24 @@ public Object process(Node nd, Stack stack, NodeProcessorCtx procCtx, } ASTNode expr = (ASTNode) nd; + String timeString = BaseSemanticAnalyzer.stripQuotes(expr.getText()); // Get the string value and convert to a Date value. try { - String dateString = BaseSemanticAnalyzer.stripQuotes(expr.getText()); - Date date = Date.valueOf(dateString); - return new ExprNodeConstantDesc(TypeInfoFactory.dateTypeInfo, date); - } catch (IllegalArgumentException err) { - throw new SemanticException("Unable to convert date literal string to date value.", err); + // todo replace below with joda-time, which supports timezone + if (expr.getType() == HiveParser.TOK_DATELITERAL) { + PrimitiveTypeInfo typeInfo = TypeInfoFactory.dateTypeInfo; + return new ExprNodeConstantDesc(typeInfo, + Date.valueOf(timeString)); + } + if (expr.getType() == HiveParser.TOK_TIMESTAMPLITERAL) { + return new ExprNodeConstantDesc(TypeInfoFactory.timestampTypeInfo, + Timestamp.valueOf(timeString)); + } + throw new IllegalArgumentException("Invalid time literal type " + expr.getType()); + } catch (Exception err) { + throw new SemanticException( + "Unable to convert time literal '" + timeString + "' to time value.", err); } } } @@ -454,8 +466,8 @@ public Object process(Node nd, Stack stack, NodeProcessorCtx procCtx, * * @return DateExprProcessor. */ - public DateExprProcessor getDateExprProcessor() { - return new DateExprProcessor(); + public DateTimeExprProcessor getDateTimeExprProcessor() { + return new DateTimeExprProcessor(); } /** diff --git ql/src/test/queries/clientnegative/timestamp_literal.q ql/src/test/queries/clientnegative/timestamp_literal.q new file mode 100644 index 0000000..1360dc9 --- /dev/null +++ ql/src/test/queries/clientnegative/timestamp_literal.q @@ -0,0 +1,2 @@ +-- TimeZone is not yet supported +SELECT TIMESTAMP '2012-12-29 20:01:00 +03:00'; diff --git ql/src/test/queries/clientpositive/timestamp_literal.q ql/src/test/queries/clientpositive/timestamp_literal.q new file mode 100644 index 0000000..2a7b91b --- /dev/null +++ ql/src/test/queries/clientpositive/timestamp_literal.q @@ -0,0 +1,12 @@ +explain +select timestamp '2011-01-01 01:01:01'; +select timestamp '2011-01-01 01:01:01'; + +explain +select '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100'; +select '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100'; + +explain +select 1 where timestamp '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100'; +select 1 where timestamp '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100'; + diff --git ql/src/test/results/clientnegative/date_literal2.q.out ql/src/test/results/clientnegative/date_literal2.q.out index 82f6425..a34cac0 100644 --- ql/src/test/results/clientnegative/date_literal2.q.out +++ ql/src/test/results/clientnegative/date_literal2.q.out @@ -1 +1 @@ -FAILED: SemanticException Unable to convert date literal string to date value. +FAILED: SemanticException Unable to convert time literal '2001/01/01' to time value. diff --git ql/src/test/results/clientnegative/date_literal3.q.out ql/src/test/results/clientnegative/date_literal3.q.out index 82f6425..f51de7c 100644 --- ql/src/test/results/clientnegative/date_literal3.q.out +++ ql/src/test/results/clientnegative/date_literal3.q.out @@ -1 +1 @@ -FAILED: SemanticException Unable to convert date literal string to date value. +FAILED: SemanticException Unable to convert time literal '2001-01-32' to time value. diff --git ql/src/test/results/clientnegative/illegal_partition_type4.q.out ql/src/test/results/clientnegative/illegal_partition_type4.q.out index e388086..861ee51 100644 --- ql/src/test/results/clientnegative/illegal_partition_type4.q.out +++ ql/src/test/results/clientnegative/illegal_partition_type4.q.out @@ -6,4 +6,4 @@ POSTHOOK: query: create table tab1(s string) PARTITIONED BY(dt date, st string) POSTHOOK: type: CREATETABLE POSTHOOK: Output: database:default POSTHOOK: Output: default@tab1 -FAILED: SemanticException Unable to convert date literal string to date value. +FAILED: SemanticException Unable to convert time literal 'foo' to time value. diff --git ql/src/test/results/clientnegative/timestamp_literal.q.out ql/src/test/results/clientnegative/timestamp_literal.q.out new file mode 100644 index 0000000..b9c92e6 --- /dev/null +++ ql/src/test/results/clientnegative/timestamp_literal.q.out @@ -0,0 +1 @@ +FAILED: SemanticException Unable to convert time literal '2012-12-29 20:01:00 +03:00' to time value. diff --git ql/src/test/results/clientpositive/timestamp_literal.q.out ql/src/test/results/clientpositive/timestamp_literal.q.out new file mode 100644 index 0000000..13ffaf1 --- /dev/null +++ ql/src/test/results/clientpositive/timestamp_literal.q.out @@ -0,0 +1,99 @@ +PREHOOK: query: explain +select timestamp '2011-01-01 01:01:01' +PREHOOK: type: QUERY +POSTHOOK: query: explain +select timestamp '2011-01-01 01:01:01' +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-0 is a root stage + +STAGE PLANS: + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + TableScan + alias: _dummy_table + Row Limit Per Split: 1 + Statistics: Num rows: 0 Data size: 1 Basic stats: PARTIAL Column stats: COMPLETE + Select Operator + expressions: 2011-01-01 01:01:01.0 (type: timestamp) + outputColumnNames: _col0 + Statistics: Num rows: 0 Data size: 1 Basic stats: PARTIAL Column stats: COMPLETE + ListSink + +PREHOOK: query: select timestamp '2011-01-01 01:01:01' +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select timestamp '2011-01-01 01:01:01' +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +2011-01-01 01:01:01 +PREHOOK: query: explain +select '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100' +PREHOOK: type: QUERY +POSTHOOK: query: explain +select '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100' +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-0 is a root stage + +STAGE PLANS: + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + TableScan + alias: _dummy_table + Row Limit Per Split: 1 + Statistics: Num rows: 0 Data size: 1 Basic stats: PARTIAL Column stats: COMPLETE + Select Operator + expressions: true (type: boolean) + outputColumnNames: _col0 + Statistics: Num rows: 0 Data size: 1 Basic stats: PARTIAL Column stats: COMPLETE + ListSink + +PREHOOK: query: select '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100' +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100' +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +true +PREHOOK: query: explain +select 1 where timestamp '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100' +PREHOOK: type: QUERY +POSTHOOK: query: explain +select 1 where timestamp '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100' +POSTHOOK: type: QUERY +STAGE DEPENDENCIES: + Stage-0 is a root stage + +STAGE PLANS: + Stage: Stage-0 + Fetch Operator + limit: -1 + Processor Tree: + TableScan + alias: _dummy_table + Row Limit Per Split: 1 + Statistics: Num rows: 0 Data size: 1 Basic stats: PARTIAL Column stats: COMPLETE + Select Operator + expressions: 1 (type: int) + outputColumnNames: _col0 + Statistics: Num rows: 0 Data size: 1 Basic stats: PARTIAL Column stats: COMPLETE + ListSink + +PREHOOK: query: select 1 where timestamp '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100' +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select 1 where timestamp '2011-01-01 01:01:01.101' <> timestamp '2011-01-01 01:01:01.100' +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +1