You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by ta...@apache.org on 2018/02/23 17:22:27 UTC
[2/3] impala git commit: IMPALA-6537: Add missing ODBC scalar
functions
IMPALA-6537: Add missing ODBC scalar functions
This patch contains the following builtin function changes:
New aliases for existing functions:
- LEFT() same as STRLEFT()
- RIGHT() same as STRRIGHT()
- WEEK() same as WEEKOFYEAR()
New functions:
- QUARTER()
- MONTHNAME()
Refactors:
- Remove TimestampFunctions::DayName and add LongDayName to match pattern of
TimestampFunctions::ShortDayName
Additionally, it adds the unit of QUARTER to EXTRACT() and DATE_PART()
Testing:
- manual testing comparing the translated ODBC functions to the
non-translated ones
- added at least one new expr-test for aliases
- new expr-tests added for new functions
Change-Id: Ia60af2b4de8c098be7ecb3e60840e459ae10d499
Reviewed-on: http://gerrit.cloudera.org:8080/9376
Reviewed-by: Alex Behm <al...@cloudera.com>
Tested-by: Impala Public Jenkins
Project: http://git-wip-us.apache.org/repos/asf/impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/impala/commit/d91df9b6
Tree: http://git-wip-us.apache.org/repos/asf/impala/tree/d91df9b6
Diff: http://git-wip-us.apache.org/repos/asf/impala/diff/d91df9b6
Branch: refs/heads/master
Commit: d91df9b63fa1fc8a907fc28e5db53b8eb275e8f3
Parents: 152cf8b
Author: Greg Rahn <gr...@users.noreply.github.com>
Authored: Tue Feb 20 18:31:57 2018 -0800
Committer: Impala Public Jenkins <im...@gerrit.cloudera.org>
Committed: Fri Feb 23 07:19:07 2018 +0000
----------------------------------------------------------------------
be/src/exprs/expr-test.cc | 42 +++++++++++++++++++
be/src/exprs/timestamp-functions-ir.cc | 43 ++++++++++++--------
be/src/exprs/timestamp-functions.cc | 14 +++----
be/src/exprs/timestamp-functions.h | 21 ++++------
be/src/exprs/udf-builtins-ir.cc | 6 +++
common/function-registry/impala_functions.py | 11 ++---
common/thrift/Exprs.thrift | 1 +
fe/src/main/cup/sql-parser.cup | 6 ++-
.../impala/analysis/AnalyzeExprsTest.java | 2 +-
.../org/apache/impala/analysis/ParserTest.java | 17 ++++----
10 files changed, 109 insertions(+), 54 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/be/src/exprs/expr-test.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/expr-test.cc b/be/src/exprs/expr-test.cc
index a78fcae..71f91c8 100644
--- a/be/src/exprs/expr-test.cc
+++ b/be/src/exprs/expr-test.cc
@@ -3759,6 +3759,7 @@ TEST_F(ExprTest, StringFunctions) {
TestIsNull("strleft(NULL, 3)", TYPE_STRING);
TestIsNull("strleft('abcdefg', NULL)", TYPE_STRING);
TestIsNull("strleft(NULL, NULL)", TYPE_STRING);
+ TestStringValue("left('foobar', 3)", "foo");
TestStringValue("strright('abcdefg', 0)", "");
TestStringValue("strright('abcdefg', 3)", "efg");
TestStringValue("strright('abcdefg', cast(10 as bigint))", "abcdefg");
@@ -3767,6 +3768,7 @@ TEST_F(ExprTest, StringFunctions) {
TestIsNull("strright(NULL, 3)", TYPE_STRING);
TestIsNull("strright('abcdefg', NULL)", TYPE_STRING);
TestIsNull("strright(NULL, NULL)", TYPE_STRING);
+ TestStringValue("right('foobar', 3)", "bar");
TestStringValue("translate('', '', '')", "");
TestStringValue("translate('abcd', '', '')", "abcd");
@@ -5933,11 +5935,13 @@ TEST_F(ExprTest, TimestampFunctions) {
TestValue("cast('2011-12-22 09:10:11.000000' as timestamp) = \
cast('2011-12-22 09:10:11' as timestamp)", TYPE_BOOLEAN, true);
TestValue("year(cast('2011-12-22 09:10:11.000000' as timestamp))", TYPE_INT, 2011);
+ TestValue("quarter(cast('2011-12-22 09:10:11.000000' as timestamp))", TYPE_INT, 4);
TestValue("month(cast('2011-12-22 09:10:11.000000' as timestamp))", TYPE_INT, 12);
TestValue("dayofmonth(cast('2011-12-22 09:10:11.000000' as timestamp))", TYPE_INT, 22);
TestValue("day(cast('2011-12-22 09:10:11.000000' as timestamp))", TYPE_INT, 22);
TestValue("dayofyear(cast('2011-12-22 09:10:11.000000' as timestamp))", TYPE_INT, 356);
TestValue("weekofyear(cast('2011-12-22 09:10:11.000000' as timestamp))", TYPE_INT, 51);
+ TestValue("week(cast('2011-12-22 09:10:11.000000' as timestamp))", TYPE_INT, 51);
TestValue("dayofweek(cast('2011-12-18 09:10:11.000000' as timestamp))", TYPE_INT, 1);
TestValue("dayofweek(cast('2011-12-22 09:10:11.000000' as timestamp))", TYPE_INT, 5);
TestValue("dayofweek(cast('2011-12-24 09:10:11.000000' as timestamp))", TYPE_INT, 7);
@@ -5949,11 +5953,13 @@ TEST_F(ExprTest, TimestampFunctions) {
TestValue("millisecond(cast('2011-12-22 09:10:11' as timestamp))", TYPE_INT, 0);
TestValue("millisecond(cast('2011-12-22' as timestamp))", TYPE_INT, 0);
TestValue("year(cast('2011-12-22' as timestamp))", TYPE_INT, 2011);
+ TestValue("quarter(cast('2011-12-22' as timestamp))", TYPE_INT, 4);
TestValue("month(cast('2011-12-22' as timestamp))", TYPE_INT, 12);
TestValue("dayofmonth(cast('2011-12-22' as timestamp))", TYPE_INT, 22);
TestValue("day(cast('2011-12-22' as timestamp))", TYPE_INT, 22);
TestValue("dayofyear(cast('2011-12-22' as timestamp))", TYPE_INT, 356);
TestValue("weekofyear(cast('2011-12-22' as timestamp))", TYPE_INT, 51);
+ TestValue("week(cast('2011-12-22' as timestamp))", TYPE_INT, 51);
TestValue("dayofweek(cast('2011-12-18' as timestamp))", TYPE_INT, 1);
TestValue("dayofweek(cast('2011-12-22' as timestamp))", TYPE_INT, 5);
TestValue("dayofweek(cast('2011-12-24' as timestamp))", TYPE_INT, 7);
@@ -6011,22 +6017,26 @@ TEST_F(ExprTest, TimestampFunctions) {
TestIsNull("cast('2000-12-31 24:59:59' as timestamp)", TYPE_TIMESTAMP);
TestIsNull("year(cast('09:10:11.000000' as timestamp))", TYPE_INT);
+ TestIsNull("quarter(cast('09:10:11.000000' as timestamp))", TYPE_INT);
TestIsNull("month(cast('09:10:11.000000' as timestamp))", TYPE_INT);
TestIsNull("dayofmonth(cast('09:10:11.000000' as timestamp))", TYPE_INT);
TestIsNull("day(cast('09:10:11.000000' as timestamp))", TYPE_INT);
TestIsNull("dayofyear(cast('09:10:11.000000' as timestamp))", TYPE_INT);
TestIsNull("dayofweek(cast('09:10:11.000000' as timestamp))", TYPE_INT);
TestIsNull("weekofyear(cast('09:10:11.000000' as timestamp))", TYPE_INT);
+ TestIsNull("week(cast('09:10:11.000000' as timestamp))", TYPE_INT);
TestIsNull("datediff(cast('09:10:11.12345678' as timestamp), "
"cast('2012-12-22' as timestamp))", TYPE_INT);
TestIsNull("year(NULL)", TYPE_INT);
+ TestIsNull("quarter(NULL)", TYPE_INT);
TestIsNull("month(NULL)", TYPE_INT);
TestIsNull("dayofmonth(NULL)", TYPE_INT);
TestIsNull("day(NULL)", TYPE_INT);
TestIsNull("dayofweek(NULL)", TYPE_INT);
TestIsNull("dayofyear(NULL)", TYPE_INT);
TestIsNull("weekofyear(NULL)", TYPE_INT);
+ TestIsNull("week(NULL)", TYPE_INT);
TestIsNull("datediff(NULL, cast('2011-12-22 09:10:11.12345678' as timestamp))",
TYPE_INT);
TestIsNull("datediff(cast('2012-12-22' as timestamp), NULL)", TYPE_INT);
@@ -6046,6 +6056,34 @@ TEST_F(ExprTest, TimestampFunctions) {
TestStringValue("dayname(cast('2011-12-25 09:10:11.000000' as timestamp))", "Sunday");
TestIsNull("dayname(NULL)", TYPE_STRING);
+ TestStringValue("monthname(cast('2011-01-18 09:10:11.000000' as timestamp))", "January");
+ TestStringValue("monthname(cast('2011-02-18 09:10:11.000000' as timestamp))", "February");
+ TestStringValue("monthname(cast('2011-03-18 09:10:11.000000' as timestamp))", "March");
+ TestStringValue("monthname(cast('2011-04-18 09:10:11.000000' as timestamp))", "April");
+ TestStringValue("monthname(cast('2011-05-18 09:10:11.000000' as timestamp))", "May");
+ TestStringValue("monthname(cast('2011-06-18 09:10:11.000000' as timestamp))", "June");
+ TestStringValue("monthname(cast('2011-07-18 09:10:11.000000' as timestamp))", "July");
+ TestStringValue("monthname(cast('2011-08-18 09:10:11.000000' as timestamp))", "August");
+ TestStringValue("monthname(cast('2011-09-18 09:10:11.000000' as timestamp))", "September");
+ TestStringValue("monthname(cast('2011-10-18 09:10:11.000000' as timestamp))", "October");
+ TestStringValue("monthname(cast('2011-11-18 09:10:11.000000' as timestamp))", "November");
+ TestStringValue("monthname(cast('2011-12-18 09:10:11.000000' as timestamp))", "December");
+ TestIsNull("monthname(NULL)", TYPE_STRING);
+
+ TestValue("quarter(cast('2011-01-18 09:10:11.000000' as timestamp))", TYPE_INT, 1);
+ TestValue("quarter(cast('2011-02-18 09:10:11.000000' as timestamp))", TYPE_INT, 1);
+ TestValue("quarter(cast('2011-03-18 09:10:11.000000' as timestamp))", TYPE_INT, 1);
+ TestValue("quarter(cast('2011-04-18 09:10:11.000000' as timestamp))", TYPE_INT, 2);
+ TestValue("quarter(cast('2011-05-18 09:10:11.000000' as timestamp))", TYPE_INT, 2);
+ TestValue("quarter(cast('2011-06-18 09:10:11.000000' as timestamp))", TYPE_INT, 2);
+ TestValue("quarter(cast('2011-07-18 09:10:11.000000' as timestamp))", TYPE_INT, 3);
+ TestValue("quarter(cast('2011-08-18 09:10:11.000000' as timestamp))", TYPE_INT, 3);
+ TestValue("quarter(cast('2011-09-18 09:10:11.000000' as timestamp))", TYPE_INT, 3);
+ TestValue("quarter(cast('2011-10-18 09:10:11.000000' as timestamp))", TYPE_INT, 4);
+ TestValue("quarter(cast('2011-11-18 09:10:11.000000' as timestamp))", TYPE_INT, 4);
+ TestValue("quarter(cast('2011-12-18 09:10:11.000000' as timestamp))", TYPE_INT, 4);
+ TestIsNull("quarter(NULL)", TYPE_INT);
+
// Tests from Hive
// The hive documentation states that timestamps are timezoneless, but the tests
// show that they treat them as being in the current timezone so these tests
@@ -6526,6 +6564,8 @@ TEST_F(ExprTest, TimestampFunctions) {
// Extract using FROM keyword
TestValue("extract(YEAR from cast('2006-05-12 18:27:28.12345' as timestamp))",
TYPE_INT, 2006);
+ TestValue("extract(QUARTER from cast('2006-05-12 18:27:28.12345' as timestamp))",
+ TYPE_INT, 2);
TestValue("extract(MoNTH from cast('2006-05-12 18:27:28.12345' as timestamp))",
TYPE_INT, 5);
TestValue("extract(DaY from cast('2006-05-12 18:27:28.12345' as timestamp))",
@@ -6547,6 +6587,8 @@ TEST_F(ExprTest, TimestampFunctions) {
// Date_part, same as extract function but with arguments swapped
TestValue("date_part('YEAR', cast('2006-05-12 18:27:28.12345' as timestamp))",
TYPE_INT, 2006);
+ TestValue("date_part('QUARTER', cast('2006-05-12 18:27:28.12345' as timestamp))",
+ TYPE_INT, 2);
TestValue("date_part('MoNTH', cast('2006-05-12 18:27:28.12345' as timestamp))",
TYPE_INT, 5);
TestValue("date_part('DaY', cast('2006-05-12 18:27:28.12345' as timestamp))",
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/be/src/exprs/timestamp-functions-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/timestamp-functions-ir.cc b/be/src/exprs/timestamp-functions-ir.cc
index 9104bcf..f2d741e 100644
--- a/be/src/exprs/timestamp-functions-ir.cc
+++ b/be/src/exprs/timestamp-functions-ir.cc
@@ -204,21 +204,6 @@ void TimestampFunctions::ReportBadFormat(FunctionContext* context,
}
}
-StringVal TimestampFunctions::DayName(FunctionContext* context, const TimestampVal& ts) {
- if (ts.is_null) return StringVal::null();
- IntVal dow = DayOfWeek(context, ts);
- switch(dow.val) {
- case 1: return StringVal(SUNDAY);
- case 2: return StringVal(MONDAY);
- case 3: return StringVal(TUESDAY);
- case 4: return StringVal(WEDNESDAY);
- case 5: return StringVal(THURSDAY);
- case 6: return StringVal(FRIDAY);
- case 7: return StringVal(SATURDAY);
- default: return StringVal::null();
- }
-}
-
IntVal TimestampFunctions::Year(FunctionContext* context, const TimestampVal& ts_val) {
if (ts_val.is_null) return IntVal::null();
const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
@@ -226,7 +211,6 @@ IntVal TimestampFunctions::Year(FunctionContext* context, const TimestampVal& ts
return IntVal(ts_value.date().year());
}
-
IntVal TimestampFunctions::Month(FunctionContext* context, const TimestampVal& ts_val) {
if (ts_val.is_null) return IntVal::null();
const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
@@ -234,6 +218,13 @@ IntVal TimestampFunctions::Month(FunctionContext* context, const TimestampVal& t
return IntVal(ts_value.date().month());
}
+IntVal TimestampFunctions::Quarter(FunctionContext* context, const TimestampVal& ts_val) {
+ if (ts_val.is_null) return IntVal::null();
+ const TimestampValue& ts_value = TimestampValue::FromTimestampVal(ts_val);
+ if (!ts_value.HasDate()) return IntVal::null();
+ int m = ts_value.date().month();
+ return IntVal((m - 1) / 3 + 1);
+}
IntVal TimestampFunctions::DayOfWeek(FunctionContext* context,
const TimestampVal& ts_val) {
@@ -473,6 +464,16 @@ string TimestampFunctions::ShortDayName(FunctionContext* context,
return DAY_ARRAY[dow.val - 1];
}
+StringVal TimestampFunctions::LongDayName(FunctionContext* context,
+ const TimestampVal& ts) {
+ if (ts.is_null) return StringVal::null();
+ IntVal dow = DayOfWeek(context, ts);
+ DCHECK_GT(dow.val, 0);
+ DCHECK_LT(dow.val, 8);
+ const string& day_name = DAYNAME_ARRAY[dow.val - 1];
+ return StringVal(reinterpret_cast<uint8_t*>(const_cast<char*>(day_name.data())), day_name.size());
+}
+
string TimestampFunctions::ShortMonthName(FunctionContext* context,
const TimestampVal& ts) {
if (ts.is_null) return NULL;
@@ -482,6 +483,16 @@ string TimestampFunctions::ShortMonthName(FunctionContext* context,
return MONTH_ARRAY[mth.val - 1];
}
+StringVal TimestampFunctions::LongMonthName(FunctionContext* context,
+ const TimestampVal& ts) {
+ if (ts.is_null) return StringVal::null();
+ IntVal mth = Month(context, ts);
+ DCHECK_GT(mth.val, 0);
+ DCHECK_LT(mth.val, 13);
+ const string& mn = MONTHNAME_ARRAY[mth.val - 1];
+ return StringVal(reinterpret_cast<uint8_t*>(const_cast<char*>(mn.data())), mn.size());
+}
+
StringVal TimestampFunctions::TimeOfDay(FunctionContext* context) {
const TimestampVal curr = Now(context);
if (curr.is_null) return StringVal::null();
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/be/src/exprs/timestamp-functions.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/timestamp-functions.cc b/be/src/exprs/timestamp-functions.cc
index d9372fb..76edd9a 100644
--- a/be/src/exprs/timestamp-functions.cc
+++ b/be/src/exprs/timestamp-functions.cc
@@ -42,19 +42,15 @@ typedef boost::gregorian::date Date;
namespace impala {
-// Constant strings used for DayName function.
-const char* TimestampFunctions::SUNDAY = "Sunday";
-const char* TimestampFunctions::MONDAY = "Monday";
-const char* TimestampFunctions::TUESDAY = "Tuesday";
-const char* TimestampFunctions::WEDNESDAY = "Wednesday";
-const char* TimestampFunctions::THURSDAY = "Thursday";
-const char* TimestampFunctions::FRIDAY = "Friday";
-const char* TimestampFunctions::SATURDAY = "Saturday";
-
const string TimestampFunctions::DAY_ARRAY[7] = {"Sun", "Mon", "Tue", "Wed", "Thu",
"Fri", "Sat"};
+const string TimestampFunctions::DAYNAME_ARRAY[7] = {"Sunday", "Monday", "Tuesday",
+ "Wednesday", "Thursday", "Friday", "Saturday"};
const string TimestampFunctions::MONTH_ARRAY[12] = {"Jan", "Feb", "Mar", "Apr", "May",
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+const string TimestampFunctions::MONTHNAME_ARRAY[12] = {"January", "February", "March",
+ "April", "May", "June", "July", "August", "September", "October", "November",
+ "December"};
namespace {
/// Uses Boost's internal checking to throw an exception if 'date' is out of the
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/be/src/exprs/timestamp-functions.h
----------------------------------------------------------------------
diff --git a/be/src/exprs/timestamp-functions.h b/be/src/exprs/timestamp-functions.h
index fdf33bd..ee0d54f 100644
--- a/be/src/exprs/timestamp-functions.h
+++ b/be/src/exprs/timestamp-functions.h
@@ -123,11 +123,9 @@ class TimestampFunctions {
static TimestampVal ToUtc(FunctionContext* context,
const TimestampVal& ts_val, const StringVal& tz_string_val);
- /// Returns the day's name as a string (e.g. 'Saturday').
- static StringVal DayName(FunctionContext* context, const TimestampVal& dow);
-
/// Functions to extract parts of the timestamp, return integers.
static IntVal Year(FunctionContext* context, const TimestampVal& ts_val);
+ static IntVal Quarter(FunctionContext* context, const TimestampVal& ts_val);
static IntVal Month(FunctionContext* context, const TimestampVal& ts_val);
static IntVal DayOfWeek(FunctionContext* context, const TimestampVal& ts_val);
static IntVal DayOfMonth(FunctionContext* context, const TimestampVal& ts_val);
@@ -145,7 +143,9 @@ class TimestampFunctions {
static IntVal DateDiff(FunctionContext* context, const TimestampVal& ts_val1,
const TimestampVal& ts_val2);
static std::string ShortDayName(FunctionContext* context, const TimestampVal& ts);
+ static StringVal LongDayName(FunctionContext* context, const TimestampVal& ts);
static std::string ShortMonthName(FunctionContext* context, const TimestampVal& ts);
+ static StringVal LongMonthName(FunctionContext* context, const TimestampVal& ts);
/// Return verbose string version of current time of day
/// e.g. Mon Dec 01 16:25:05 2003 EST.
@@ -229,18 +229,13 @@ class TimestampFunctions {
const StringVal& format, bool is_error);
private:
- /// Static result values for DayName() function.
- static const char* MONDAY;
- static const char* TUESDAY;
- static const char* WEDNESDAY;
- static const char* THURSDAY;
- static const char* FRIDAY;
- static const char* SATURDAY;
- static const char* SUNDAY;
-
- /// Static result values for ShortDayName() and ShortMonthName() functions.
+
+ /// Static result values for DayName(), ShortDayName(), ShortMonthName() and
+ /// LongMonthName functions.
static const std::string DAY_ARRAY[7];
+ static const std::string DAYNAME_ARRAY[7];
static const std::string MONTH_ARRAY[12];
+ static const std::string MONTHNAME_ARRAY[12];
};
} // namespace impala
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/be/src/exprs/udf-builtins-ir.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/udf-builtins-ir.cc b/be/src/exprs/udf-builtins-ir.cc
index 03b88ba..3c47e6b 100644
--- a/be/src/exprs/udf-builtins-ir.cc
+++ b/be/src/exprs/udf-builtins-ir.cc
@@ -119,6 +119,7 @@ TExtractField::type StrToExtractField(FunctionContext* ctx, const StringVal& uni
StringVal unit = UdfBuiltins::Lower(ctx, unit_str);
if (UNLIKELY(unit.is_null)) return TExtractField::INVALID_FIELD;
if (unit == "year") return TExtractField::YEAR;
+ if (unit == "quarter") return TExtractField::QUARTER;
if (unit == "month") return TExtractField::MONTH;
if (unit == "day") return TExtractField::DAY;
if (unit == "hour") return TExtractField::HOUR;
@@ -153,6 +154,7 @@ IntVal UdfBuiltins::Extract(FunctionContext* context, const StringVal& unit_str,
switch (field) {
case TExtractField::YEAR:
+ case TExtractField::QUARTER:
case TExtractField::MONTH:
case TExtractField::DAY:
if (orig_date.is_special()) return IntVal::null();
@@ -174,6 +176,10 @@ IntVal UdfBuiltins::Extract(FunctionContext* context, const StringVal& unit_str,
case TExtractField::YEAR: {
return IntVal(orig_date.year());
}
+ case TExtractField::QUARTER: {
+ int m = orig_date.month();
+ return IntVal((m - 1) / 3 + 1);
+ }
case TExtractField::MONTH: {
return IntVal(orig_date.month());
}
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/common/function-registry/impala_functions.py
----------------------------------------------------------------------
diff --git a/common/function-registry/impala_functions.py b/common/function-registry/impala_functions.py
index 8174abb..b3387c6 100644
--- a/common/function-registry/impala_functions.py
+++ b/common/function-registry/impala_functions.py
@@ -109,21 +109,23 @@ visible_functions = [
'_ZN6impala11UdfBuiltins9VectorGetEPN10impala_udf15FunctionContextERKNS1_9BigIntValERKNS1_9StringValE'],
# Timestamp functions
+ [['monthname'], 'STRING', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions13LongMonthNameEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['next_day'], 'TIMESTAMP', ['TIMESTAMP', 'STRING'], '_ZN6impala18TimestampFunctions7NextDayEPN10impala_udf15FunctionContextERKNS1_12TimestampValERKNS1_9StringValE'],
[['last_day'], 'TIMESTAMP', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions7LastDayEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['unix_timestamp'], 'BIGINT', ['STRING'], '_ZN6impala18TimestampFunctions14UnixFromStringEPN10impala_udf15FunctionContextERKNS1_9StringValE'],
[['year'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions4YearEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
+ [['quarter'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions7QuarterEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['month'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions5MonthEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['dayofweek'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions9DayOfWeekEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['day', 'dayofmonth'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions10DayOfMonthEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['dayofyear'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions9DayOfYearEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
- [['weekofyear'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions10WeekOfYearEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
+ [['week', 'weekofyear'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions10WeekOfYearEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['hour'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions4HourEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['minute'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions6MinuteEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['second'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions6SecondEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['millisecond'], 'INT', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions11MillisecondEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['to_date'], 'STRING', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions6ToDateEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
- [['dayname'], 'STRING', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions7DayNameEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
+ [['dayname'], 'STRING', ['TIMESTAMP'], '_ZN6impala18TimestampFunctions11LongDayNameEPN10impala_udf15FunctionContextERKNS1_12TimestampValE'],
[['date_trunc'], 'TIMESTAMP', ['STRING', 'TIMESTAMP'],
'_ZN6impala11UdfBuiltins9DateTruncEPN10impala_udf15FunctionContextERKNS1_9StringValERKNS1_12TimestampValE',
'_ZN6impala11UdfBuiltins16DateTruncPrepareEPN10impala_udf15FunctionContextENS2_18FunctionStateScopeE',
@@ -419,9 +421,8 @@ visible_functions = [
'impala::StringFunctions::SplitPart'],
[['base64encode'], 'STRING', ['STRING'], 'impala::StringFunctions::Base64Encode'],
[['base64decode'], 'STRING', ['STRING'], 'impala::StringFunctions::Base64Decode'],
- # left and right are key words, leave them out for now.
- [['strleft'], 'STRING', ['STRING', 'BIGINT'], 'impala::StringFunctions::Left'],
- [['strright'], 'STRING', ['STRING', 'BIGINT'], 'impala::StringFunctions::Right'],
+ [['left', 'strleft'], 'STRING', ['STRING', 'BIGINT'], 'impala::StringFunctions::Left'],
+ [['right', 'strright'], 'STRING', ['STRING', 'BIGINT'], 'impala::StringFunctions::Right'],
[['space'], 'STRING', ['BIGINT'], 'impala::StringFunctions::Space'],
[['repeat'], 'STRING', ['STRING', 'BIGINT'], 'impala::StringFunctions::Repeat'],
[['lpad'], 'STRING', ['STRING', 'BIGINT', 'STRING'], 'impala::StringFunctions::Lpad'],
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/common/thrift/Exprs.thrift
----------------------------------------------------------------------
diff --git a/common/thrift/Exprs.thrift b/common/thrift/Exprs.thrift
index 7c88f2b..ee9fe94 100644
--- a/common/thrift/Exprs.thrift
+++ b/common/thrift/Exprs.thrift
@@ -79,6 +79,7 @@ struct TTimestampLiteral {
enum TExtractField {
INVALID_FIELD,
YEAR,
+ QUARTER,
MONTH,
DAY,
HOUR,
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/fe/src/main/cup/sql-parser.cup
----------------------------------------------------------------------
diff --git a/fe/src/main/cup/sql-parser.cup b/fe/src/main/cup/sql-parser.cup
index 9f55dda..9802778 100644
--- a/fe/src/main/cup/sql-parser.cup
+++ b/fe/src/main/cup/sql-parser.cup
@@ -2799,13 +2799,17 @@ non_pred_expr ::=
{: RESULT = e; :}
| analytic_expr:e
{: RESULT = e; :}
- /* Since "IF", "REPLACE", "TRUNCATE" are keywords, need to special case these functions */
+ /* Additional rules for function names that are also keywords */
| KW_IF LPAREN expr_list:exprs RPAREN
{: RESULT = new FunctionCallExpr("if", exprs); :}
| KW_REPLACE LPAREN expr_list:exprs RPAREN
{: RESULT = new FunctionCallExpr("replace", exprs); :}
| KW_TRUNCATE LPAREN expr_list:exprs RPAREN
{: RESULT = new FunctionCallExpr("truncate", exprs); :}
+ | KW_LEFT LPAREN expr_list:exprs RPAREN
+ {: RESULT = new FunctionCallExpr("left", exprs); :}
+ | KW_RIGHT LPAREN expr_list:exprs RPAREN
+ {: RESULT = new FunctionCallExpr("right", exprs); :}
| cast_expr:c
{: RESULT = c; :}
| case_expr:c
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/fe/src/test/java/org/apache/impala/analysis/AnalyzeExprsTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeExprsTest.java b/fe/src/test/java/org/apache/impala/analysis/AnalyzeExprsTest.java
index d3eeb19..8f2cc60 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeExprsTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeExprsTest.java
@@ -1786,7 +1786,7 @@ public class AnalyzeExprsTest extends AnalyzerTest {
AnalyzesOk("select extract(year from now())");
AnalysisError("select extract(foo from now())",
"Time unit 'foo' in expression 'EXTRACT(foo FROM now())' is invalid. Expected " +
- "one of YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, EPOCH.");
+ "one of YEAR, QUARTER, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND, EPOCH.");
AnalysisError("select extract(year from 0)",
"Expression '0' in 'EXTRACT(year FROM 0)' has a return type of TINYINT but a " +
"TIMESTAMP is required.");
http://git-wip-us.apache.org/repos/asf/impala/blob/d91df9b6/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
----------------------------------------------------------------------
diff --git a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
index 178539f..b51d148 100644
--- a/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/ParserTest.java
@@ -3243,9 +3243,8 @@ public class ParserTest extends FrontendTestBase {
"select from t\n" +
" ^\n" +
"Encountered: FROM\n" +
- "Expected: ALL, CASE, CAST, DEFAULT, DISTINCT, EXISTS, " +
- "FALSE, IF, INTERVAL, NOT, NULL, REPLACE, " +
- "STRAIGHT_JOIN, TRUNCATE, TRUE, IDENTIFIER\n");
+ "Expected: ALL, CASE, CAST, DEFAULT, DISTINCT, EXISTS, FALSE, IF, INTERVAL, " +
+ "LEFT, NOT, NULL, REPLACE, RIGHT, STRAIGHT_JOIN, TRUNCATE, TRUE, IDENTIFIER");
// missing from
ParserError("select c, b, c where a = 5",
@@ -3270,8 +3269,8 @@ public class ParserTest extends FrontendTestBase {
"select c, b, c from t where\n" +
" ^\n" +
"Encountered: EOF\n" +
- "Expected: CASE, CAST, DEFAULT, EXISTS, FALSE, " +
- "IF, INTERVAL, NOT, NULL, REPLACE, TRUNCATE, TRUE, IDENTIFIER\n");
+ "Expected: CASE, CAST, DEFAULT, EXISTS, FALSE, IF, INTERVAL, LEFT, NOT, NULL, " +
+ "REPLACE, RIGHT, TRUNCATE, TRUE, IDENTIFIER");
// missing predicate in where clause (group by)
ParserError("select c, b, c from t where group by a, b",
@@ -3279,8 +3278,8 @@ public class ParserTest extends FrontendTestBase {
"select c, b, c from t where group by a, b\n" +
" ^\n" +
"Encountered: GROUP\n" +
- "Expected: CASE, CAST, DEFAULT, EXISTS, FALSE, " +
- "IF, INTERVAL, NOT, NULL, REPLACE, TRUNCATE, TRUE, IDENTIFIER\n");
+ "Expected: CASE, CAST, DEFAULT, EXISTS, FALSE, IF, INTERVAL, LEFT, NOT, NULL, " +
+ "REPLACE, RIGHT, TRUNCATE, TRUE, IDENTIFIER");
// unmatched string literal starting with "
ParserError("select c, \"b, c from t",
@@ -3340,8 +3339,8 @@ public class ParserTest extends FrontendTestBase {
"...c,c,c,c,c,c,c,c,cd,c,d,d, ,c, from t\n" +
" ^\n" +
"Encountered: COMMA\n" +
- "Expected: CASE, CAST, DEFAULT, EXISTS, FALSE, " +
- "IF, INTERVAL, NOT, NULL, REPLACE, TRUNCATE, TRUE, IDENTIFIER\n");
+ "Expected: CASE, CAST, DEFAULT, EXISTS, FALSE, IF, INTERVAL, LEFT, NOT, NULL, " +
+ "REPLACE, RIGHT, TRUNCATE, TRUE, IDENTIFIER");
// Parsing identifiers that have different names printed as EXPECTED
ParserError("DROP DATA SRC foo",