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..ddde465 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, @@ -440,11 +442,19 @@ public Object process(Node nd, Stack stack, NodeProcessorCtx procCtx, // 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 + String timeString = BaseSemanticAnalyzer.stripQuotes(expr.getText()); + if (expr.getType() == HiveParser.TOK_DATELITERAL) { + return new ExprNodeConstantDesc(TypeInfoFactory.dateTypeInfo, + 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 string to value.", err); } } } @@ -454,8 +464,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/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/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