Skip to content

Commit 24df520

Browse files
committed
support string literal as the second argument of date_add/date_sub functions
1 parent f1cc867 commit 24df520

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

docs/sql-migration-guide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ license: |
113113

114114
### UDFs and Built-in Functions
115115

116-
- Since Spark 3.0, the `date_add` and `date_sub` functions only accepts int, smallint, tinyint as the 2nd argument, fractional and string types are not valid anymore, e.g. `date_add(cast('1964-05-23' as date), '12.34')` will cause `AnalysisException`. In Spark version 2.4 and earlier, if the 2nd argument is fractional or string value, it will be coerced to int value, and the result will be a date value of `1964-06-04`.
116+
- Since Spark 3.0, the `date_add` and `date_sub` functions only accepts int, smallint, tinyint as the 2nd argument, fractional and string types (excluding string literals) are not valid anymore, e.g. `date_add(cast('1964-05-23' as date), '12.34')` will cause `AnalysisException`. In Spark version 2.4 and earlier, if the 2nd argument is fractional or string value, it will be coerced to int value, and the result will be a date value of `1964-06-04`.
117117

118118
- Since Spark 3.0, the function `percentile_approx` and its alias `approx_percentile` only accept integral value with range in `[1, 2147483647]` as its 3rd argument `accuracy`, fractional and string types are disallowed, e.g. `percentile_approx(10.0, 0.2, 1.8D)` will cause `AnalysisException`. In Spark version 2.4 and earlier, if `accuracy` is fractional or string value, it will be coerced to an int value, `percentile_approx(10.0, 0.2, 1.8D)` is operated as `percentile_approx(10.0, 0.2, 1)` which results in `10.0`.
119119

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ object TypeCoercion {
6363
ImplicitTypeCasts ::
6464
DateTimeOperations ::
6565
WindowFrameCoercion ::
66+
StringLiteralCoercion ::
6667
Nil
6768

6869
// See https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types.
@@ -1043,6 +1044,22 @@ object TypeCoercion {
10431044
}
10441045
}
10451046
}
1047+
1048+
/**
1049+
* A special rule to support string literal as the second argument of date_add/date_sub functions,
1050+
* to keep backward compatibility.
1051+
* TODO: revisit the type coercion rules for string.
1052+
*/
1053+
object StringLiteralCoercion extends TypeCoercionRule {
1054+
override protected def coerceTypes(plan: LogicalPlan): LogicalPlan = plan resolveExpressions {
1055+
// Skip nodes who's children have not been resolved yet.
1056+
case e if !e.childrenResolved => e
1057+
case DateAdd(l, r) if r.dataType == StringType && r.foldable =>
1058+
DateAdd(l, AnsiCast(r, IntegerType))
1059+
case DateSub(l, r) if r.dataType == StringType && r.foldable =>
1060+
DateSub(l, AnsiCast(r, IntegerType))
1061+
}
1062+
}
10461063
}
10471064

10481065
trait TypeCoercionRule extends Rule[LogicalPlan] with Logging {

sql/core/src/test/resources/sql-tests/inputs/datetime.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,12 @@ select date_add('2011-11-11', 1L);
5858
select date_add('2011-11-11', 1.0);
5959
select date_add('2011-11-11', 1E1);
6060
select date_add('2011-11-11', '1');
61+
select date_add('2011-11-11', '1.2');
6162
select date_add(date'2011-11-11', 1);
6263
select date_add(timestamp'2011-11-11', 1);
6364
select date_sub(date'2011-11-11', 1);
65+
select date_sub(date'2011-11-11', '1');
66+
select date_sub(date'2011-11-11', '1.2');
6467
select date_sub(timestamp'2011-11-11', 1);
6568
select date_sub(null, 1);
6669
select date_sub(date'2011-11-11', null);
@@ -72,6 +75,11 @@ select date '2001-10-01' - 7;
7275
select date '2001-09-28' + null;
7376
select date '2001-09-28' - null;
7477

78+
-- date add/sub with non-literal string column
79+
create temp view v as select '1' str;
80+
select date_add('2011-11-11', str) from v;
81+
select date_sub('2011-11-11', str) from v;
82+
7583
-- subtract dates
7684
select null - date '2019-10-06';
7785
select date '2001-10-01' - date '2001-09-28';

sql/core/src/test/resources/sql-tests/results/datetime.sql.out

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
-- Automatically generated by SQLQueryTestSuite
2-
-- Number of queries: 77
2+
-- Number of queries: 83
33

44

55
-- !query
@@ -266,10 +266,18 @@ cannot resolve 'date_add(CAST('2011-11-11' AS DATE), 10.0D)' due to data type mi
266266
-- !query
267267
select date_add('2011-11-11', '1')
268268
-- !query schema
269+
struct<date_add(CAST(2011-11-11 AS DATE), CAST(1 AS INT)):date>
270+
-- !query output
271+
2011-11-12
272+
273+
274+
-- !query
275+
select date_add('2011-11-11', '1.2')
276+
-- !query schema
269277
struct<>
270278
-- !query output
271-
org.apache.spark.sql.AnalysisException
272-
cannot resolve 'date_add(CAST('2011-11-11' AS DATE), '1')' due to data type mismatch: argument 2 requires (int or smallint or tinyint) type, however, ''1'' is of string type.; line 1 pos 7
279+
java.lang.NumberFormatException
280+
invalid input syntax for type numeric: 1.2
273281

274282

275283
-- !query
@@ -296,6 +304,23 @@ struct<date_sub(DATE '2011-11-11', 1):date>
296304
2011-11-10
297305

298306

307+
-- !query
308+
select date_sub(date'2011-11-11', '1')
309+
-- !query schema
310+
struct<date_sub(DATE '2011-11-11', CAST(1 AS INT)):date>
311+
-- !query output
312+
2011-11-10
313+
314+
315+
-- !query
316+
select date_sub(date'2011-11-11', '1.2')
317+
-- !query schema
318+
struct<>
319+
-- !query output
320+
java.lang.NumberFormatException
321+
invalid input syntax for type numeric: 1.2
322+
323+
299324
-- !query
300325
select date_sub(timestamp'2011-11-11', 1)
301326
-- !query schema
@@ -377,6 +402,32 @@ struct<date_sub(DATE '2001-09-28', CAST(NULL AS INT)):date>
377402
NULL
378403

379404

405+
-- !query
406+
create temp view v as select '1' str
407+
-- !query schema
408+
struct<>
409+
-- !query output
410+
411+
412+
413+
-- !query
414+
select date_add('2011-11-11', str) from v
415+
-- !query schema
416+
struct<>
417+
-- !query output
418+
org.apache.spark.sql.AnalysisException
419+
cannot resolve 'date_add(CAST('2011-11-11' AS DATE), v.`str`)' due to data type mismatch: argument 2 requires (int or smallint or tinyint) type, however, 'v.`str`' is of string type.; line 1 pos 7
420+
421+
422+
-- !query
423+
select date_sub('2011-11-11', str) from v
424+
-- !query schema
425+
struct<>
426+
-- !query output
427+
org.apache.spark.sql.AnalysisException
428+
cannot resolve 'date_sub(CAST('2011-11-11' AS DATE), v.`str`)' due to data type mismatch: argument 2 requires (int or smallint or tinyint) type, however, 'v.`str`' is of string type.; line 1 pos 7
429+
430+
380431
-- !query
381432
select null - date '2019-10-06'
382433
-- !query schema

0 commit comments

Comments
 (0)