Skip to content
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0b293db
[SPARK-29774][SQL] Date and Timestamp type +/- null should be null as…
yaooqinn Nov 6, 2019
f726297
Merge branch 'master' into SPARK-29774
yaooqinn Nov 27, 2019
e7225a3
regen golden file
yaooqinn Nov 27, 2019
b925517
null - dates
yaooqinn Nov 27, 2019
cd49411
Merge branch 'master' into SPARK-29774
yaooqinn Dec 2, 2019
57b13e9
support +/-
yaooqinn Dec 2, 2019
eab6a83
support ×/÷
yaooqinn Dec 2, 2019
e8b75ba
import
yaooqinn Dec 2, 2019
02b3738
childResolved required
yaooqinn Dec 2, 2019
e89d806
regen golden file
yaooqinn Dec 2, 2019
0694e07
update comments
yaooqinn Dec 2, 2019
0f5618b
fix tests
yaooqinn Dec 3, 2019
efab3ec
fix tests
yaooqinn Dec 3, 2019
1c27be1
refine case match pattern
yaooqinn Dec 3, 2019
5df6980
fix ut
yaooqinn Dec 3, 2019
9817d2d
hack assert Equal
yaooqinn Dec 3, 2019
9808b9c
regen g f
yaooqinn Dec 3, 2019
b190612
AnalysisTest
yaooqinn Dec 3, 2019
e544137
regen g f
yaooqinn Dec 3, 2019
83705fd
fix test
yaooqinn Dec 4, 2019
846802d
date add/sub only work for int/smallint/tinyint
yaooqinn Dec 4, 2019
4af7edb
regen g f
yaooqinn Dec 4, 2019
a67be30
refine
yaooqinn Dec 4, 2019
9a1affd
type coercion for subtract timestamp
yaooqinn Dec 4, 2019
ae70022
add and reorgnize tests in datetime.sql
yaooqinn Dec 4, 2019
571225b
DateExpressionsSuite
yaooqinn Dec 4, 2019
6052e5a
fix py
yaooqinn Dec 4, 2019
928fd86
fix py
yaooqinn Dec 4, 2019
254d2d2
Revert "fix py"
yaooqinn Dec 5, 2019
5dd632c
fix py
yaooqinn Dec 5, 2019
c84d46e
rm unresolved binary arithmetic
yaooqinn Dec 5, 2019
a44948e
import
yaooqinn Dec 5, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import org.apache.spark.sql.catalyst.expressions.aggregate._
import org.apache.spark.sql.catalyst.expressions.objects._
import org.apache.spark.sql.catalyst.plans._
import org.apache.spark.sql.catalyst.plans.logical._
import org.apache.spark.sql.catalyst.rules._
import org.apache.spark.sql.catalyst.rules.{Rule, _}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this change?

import org.apache.spark.sql.catalyst.trees.TreeNodeRef
import org.apache.spark.sql.catalyst.util.toPrettySQL
import org.apache.spark.sql.connector.catalog.{CatalogManager, CatalogPlugin, CatalogV2Util, Identifier, LookupCatalog, Table, TableCatalog, TableChange, V1Table}
Expand Down Expand Up @@ -228,6 +228,7 @@ class Analyzer(
ResolveLambdaVariables(conf) ::
ResolveTimeZone(conf) ::
ResolveRandomSeed ::
ResolveBinaryArithmetic(conf) ::
TypeCoercion.typeCoercionRules(conf) ++
extendedResolutionRules : _*),
Batch("PostgreSQL Dialect", Once, PostgreSQLDialect.postgreSQLDialectRules: _*),
Expand All @@ -246,6 +247,68 @@ class Analyzer(
CleanupAliases)
)

/**
* For [[UnresolvedAdd]]:
* 1. If one side is timestamp/date/string and the other side is interval, turns it to
Copy link
Contributor

Choose a reason for hiding this comment

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

it's better to reduce the coupling between analyzer rule and type coercion rule. I think here we should turn into TimeAdd if one side is interval, and type coercion rule will cast date/string to timestamp for TimeAdd

Copy link
Member Author

Choose a reason for hiding this comment

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

you missed interval + interval

Copy link
Contributor

Choose a reason for hiding this comment

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

then how about if one side is interval and the other side is not interval?

Copy link
Member Author

Choose a reason for hiding this comment

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

they all go to ADD then fail with type checking

Copy link
Member Author

Choose a reason for hiding this comment

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

org.apache.spark.sql.AnalysisException
+cannot resolve '(INTERVAL '1 days' + 1)' due to data type mismatch: differing types in '(INTERVAL '1 days' + 1)'

Copy link
Contributor

Choose a reason for hiding this comment

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

so what's wrong here? pgsql fails and spark fails as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Er... here we have no problem, just reply to this comment

if one side is interval, and type coercion rule will cast date/string to timestamp for TimeAdd

Copy link
Contributor

Choose a reason for hiding this comment

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

type coercion rule will cast date/string to timestamp but not other types, it matches the expected behavior, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, type coercion will take over after we resolve them

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, type coercion will take over after we resolve them

* [[TimeAdd]];
* 2. else if one side is date, turns it to [[DateAdd]] ;
* 3. else turns it to [[Add]].
*
* For [[UnresolvedSubtract]]:
* 1. If the left side is timestamp/date/string and the right side is an interval, turns it to
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

* [[TimeSub]];
* 2. else if one side is timestamp and the other side is date/timestamp, turns it to
* [[SubtractTimestamps]];
* 3. else if both side are dates, turns it to [[DateDiff]]/[[SubtractDates]];
* 4. else if the left side is date, turns it to [[DateSub]];
* 5. else turns it to [[Subtract]].
*
* For [[UnresolvedMultiply]]:
* 1. If one side is interval and the other side is numeric, turns it to [[MultiplyInterval]];
* 2. otherwise, turns it to [[Multiply]].
*
* For [[UnresolvedDivide]]:
* 1. If the left side is interval and the right side is numeric, turns it to
* [[DivideInterval]];
* 2. otherwise, turns it to [[Divide]].
*/
case class ResolveBinaryArithmetic(conf: SQLConf) extends Rule[LogicalPlan] {
override def apply(plan: LogicalPlan): LogicalPlan = plan.resolveOperatorsUp {
case p: LogicalPlan => p.transformExpressionsUp {
case u @ UnresolvedAdd(l, r) if u.childrenResolved => (l.dataType, r.dataType) match {
case (TimestampType | DateType | StringType, CalendarIntervalType) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

according to the above discussion, I think it's clearer to do

case (CalendarIntervalType, CalendarIntervalType) => Add
case (_, CalendarIntervalType) => TimeAdd
case (CalendarIntervalType, _) => TimeAdd
case (_, DateType) => DateAdd
case (DateType, _) => DateAdd
case _ => Add

Cast(TimeAdd(l, r), l.dataType)
case (CalendarIntervalType, TimestampType | DateType | StringType) =>
Cast(TimeAdd(r, l), r.dataType)
case (DateType, _) => DateAdd(l, r)
case (_, DateType) => DateAdd(r, l)
case (_, _) => Add(l, r)
}
case u @ UnresolvedSubtract(l, r) if u.childrenResolved => (l.dataType, r.dataType) match {
case (TimestampType | DateType | StringType, CalendarIntervalType) =>
Cast(TimeSub(l, r), l.dataType)
Copy link
Member Author

Choose a reason for hiding this comment

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

I notice that TimeSub is replaceable by TimeAdd(l, UnaryMinus(r)), which make it useless

case (TimestampType, TimestampType | DateType | NullType) => SubtractTimestamps(l, r)
case (DateType | NullType, TimestampType) => SubtractTimestamps(Cast(l, TimestampType), r)
case (DateType | NullType, DateType) => if (conf.usePostgreSQLDialect) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to handle NullType here? The Subtract should work for null.

Copy link
Member Author

Choose a reason for hiding this comment

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

yea, the result same but do not semantic equal, is that OK?

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually not, subtract(null, date) will not pass type checking

DateDiff(l, r)
} else {
SubtractDates(l, r)
}
case (DateType, _) => DateSub(l, r)
case (_, _) => Subtract(l, r)
}
case u @ UnresolvedMultiply(l, r) if u.childrenResolved => (l.dataType, r.dataType) match {
case (CalendarIntervalType, _: NumericType | NullType) => MultiplyInterval(l, r)
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

case (_: NumericType | NullType, CalendarIntervalType) => MultiplyInterval(r, l)
Copy link
Member Author

Choose a reason for hiding this comment

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

Here is another thing to discuss, do we have to only support interval * numeric andinterval / numeric, this is not same with other type coercion rules, e.g. 1 / '2' is valid, so interval 1 day / '2' should be valid too.

In PostgreSQL, also valid

postgres=# select interval '1' day * 2;
 ?column?
----------
 2 days
(1 row)

postgres=# select interval '1' day * '2';
 ?column?
----------
 2 days
(1 row)

postgres=# select interval '1' day / '2';
 ?column?
----------
 12:00:00
(1 row)

Copy link
Member Author

Choose a reason for hiding this comment

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

case (_, CalendarIntervalType) => MultiplyInterval(r, l) might be enough for this case.

case (_, _) => Multiply(l, r)
}
case u @ UnresolvedDivide(l, r) if u.childrenResolved => (l.dataType, r.dataType) match {
case (CalendarIntervalType, _: NumericType | NullType) => DivideInterval(l, r)
case (_, _) => Divide(l, r)
}
}
}
}
/**
* Substitute child plan with WindowSpecDefinitions.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ object TypeCoercion {
StackCoercion ::
Division(conf) ::
ImplicitTypeCasts ::
DateTimeOperations ::
WindowFrameCoercion ::
Nil

Expand Down Expand Up @@ -822,55 +821,6 @@ object TypeCoercion {
}
}

/**
* 1. Turns Add/Subtract of DateType/TimestampType/StringType and CalendarIntervalType
* to TimeAdd/TimeSub.
* 2. Turns Add/Subtract of TimestampType/DateType/IntegerType
* and TimestampType/IntegerType/DateType to DateAdd/DateSub/SubtractDates and
* to SubtractTimestamps.
* 3. Turns Multiply/Divide of CalendarIntervalType and NumericType
* to MultiplyInterval/DivideInterval
*/
object DateTimeOperations extends Rule[LogicalPlan] {

private val acceptedTypes = Seq(DateType, TimestampType, StringType)

def apply(plan: LogicalPlan): LogicalPlan = plan resolveExpressions {
// Skip nodes who's children have not been resolved yet.
case e if !e.childrenResolved => e

case Add(l @ CalendarIntervalType(), r) if acceptedTypes.contains(r.dataType) =>
Cast(TimeAdd(r, l), r.dataType)
case Add(l, r @ CalendarIntervalType()) if acceptedTypes.contains(l.dataType) =>
Cast(TimeAdd(l, r), l.dataType)
case Subtract(l, r @ CalendarIntervalType()) if acceptedTypes.contains(l.dataType) =>
Cast(TimeSub(l, r), l.dataType)
case Multiply(l @ CalendarIntervalType(), r @ NumericType()) =>
MultiplyInterval(l, r)
case Multiply(l @ NumericType(), r @ CalendarIntervalType()) =>
MultiplyInterval(r, l)
case Divide(l @ CalendarIntervalType(), r @ NumericType()) =>
DivideInterval(l, r)

case b @ BinaryOperator(l @ CalendarIntervalType(), r @ NullType()) =>
b.withNewChildren(Seq(l, Cast(r, CalendarIntervalType)))
case b @ BinaryOperator(l @ NullType(), r @ CalendarIntervalType()) =>
b.withNewChildren(Seq(Cast(l, CalendarIntervalType), r))

case Add(l @ DateType(), r @ IntegerType()) => DateAdd(l, r)
case Add(l @ IntegerType(), r @ DateType()) => DateAdd(r, l)
case Subtract(l @ DateType(), r @ IntegerType()) => DateSub(l, r)
case Subtract(l @ DateType(), r @ DateType()) =>
if (SQLConf.get.usePostgreSQLDialect) DateDiff(l, r) else SubtractDates(l, r)
case Subtract(l @ TimestampType(), r @ TimestampType()) =>
SubtractTimestamps(l, r)
case Subtract(l @ TimestampType(), r @ DateType()) =>
SubtractTimestamps(l, Cast(r, TimestampType))
case Subtract(l @ DateType(), r @ TimestampType()) =>
SubtractTimestamps(Cast(l, TimestampType), r)
}
}

/**
* Casts types according to the expected input types for [[Expression]]s.
*/
Expand All @@ -881,11 +831,8 @@ object TypeCoercion {
case e if !e.childrenResolved => e

// If DecimalType operands are involved, DecimalPrecision will handle it
// If CalendarIntervalType operands are involved, DateTimeOperations will handle it
case b @ BinaryOperator(left, right) if !left.dataType.isInstanceOf[DecimalType] &&
!right.dataType.isInstanceOf[DecimalType] &&
!left.dataType.isInstanceOf[CalendarIntervalType] &&
!right.dataType.isInstanceOf[CalendarIntervalType] &&
left.dataType != right.dataType =>
findTightestCommonType(left.dataType, right.dataType).map { commonType =>
if (b.inputType.acceptsType(commonType)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,3 +544,19 @@ case class UnresolvedOrdinal(ordinal: Int)
override def nullable: Boolean = throw new UnresolvedException(this, "nullable")
override lazy val resolved = false
}

trait UnresolvedBinaryExpression extends BinaryExpression with Unevaluable {
override lazy val resolved: Boolean = false
override def dataType: DataType = throw new UnresolvedException(this, "dataType")
}

case class UnresolvedAdd(left: Expression, right: Expression) extends UnresolvedBinaryExpression

case class UnresolvedSubtract(left: Expression, right: Expression)
extends UnresolvedBinaryExpression

case class UnresolvedMultiply(left: Expression, right: Expression)
extends UnresolvedBinaryExpression

case class UnresolvedDivide(left: Expression, right: Expression)
extends UnresolvedBinaryExpression
Original file line number Diff line number Diff line change
Expand Up @@ -1429,17 +1429,17 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
val right = expression(ctx.right)
ctx.operator.getType match {
case SqlBaseParser.ASTERISK =>
Multiply(left, right)
UnresolvedMultiply(left, right)
case SqlBaseParser.SLASH =>
Divide(left, right)
UnresolvedDivide(left, right)
case SqlBaseParser.PERCENT =>
Remainder(left, right)
case SqlBaseParser.DIV =>
IntegralDivide(left, right)
case SqlBaseParser.PLUS =>
Add(left, right)
UnresolvedAdd(left, right)
case SqlBaseParser.MINUS =>
Subtract(left, right)
UnresolvedSubtract(left, right)
case SqlBaseParser.CONCAT_PIPE =>
Concat(left :: right :: Nil)
case SqlBaseParser.AMPERSAND =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1401,44 +1401,6 @@ class TypeCoercionSuite extends AnalysisTest {
}
}

test("rule for date/timestamp operations") {
val dateTimeOperations = TypeCoercion.DateTimeOperations
val date = Literal(new java.sql.Date(0L))
val timestamp = Literal(new Timestamp(0L))
val interval = Literal(new CalendarInterval(0, 0, 0))
val str = Literal("2015-01-01")
val intValue = Literal(0, IntegerType)

ruleTest(dateTimeOperations, Add(date, interval), Cast(TimeAdd(date, interval), DateType))
ruleTest(dateTimeOperations, Add(interval, date), Cast(TimeAdd(date, interval), DateType))
ruleTest(dateTimeOperations, Add(timestamp, interval),
Cast(TimeAdd(timestamp, interval), TimestampType))
ruleTest(dateTimeOperations, Add(interval, timestamp),
Cast(TimeAdd(timestamp, interval), TimestampType))
ruleTest(dateTimeOperations, Add(str, interval), Cast(TimeAdd(str, interval), StringType))
ruleTest(dateTimeOperations, Add(interval, str), Cast(TimeAdd(str, interval), StringType))

ruleTest(dateTimeOperations, Subtract(date, interval), Cast(TimeSub(date, interval), DateType))
ruleTest(dateTimeOperations, Subtract(timestamp, interval),
Cast(TimeSub(timestamp, interval), TimestampType))
ruleTest(dateTimeOperations, Subtract(str, interval), Cast(TimeSub(str, interval), StringType))

// interval operations should not be effected
ruleTest(dateTimeOperations, Add(interval, interval), Add(interval, interval))
ruleTest(dateTimeOperations, Subtract(interval, interval), Subtract(interval, interval))

ruleTest(dateTimeOperations, Add(date, intValue), DateAdd(date, intValue))
ruleTest(dateTimeOperations, Add(intValue, date), DateAdd(date, intValue))
ruleTest(dateTimeOperations, Subtract(date, intValue), DateSub(date, intValue))
ruleTest(dateTimeOperations, Subtract(date, date), SubtractDates(date, date))
ruleTest(dateTimeOperations, Subtract(timestamp, timestamp),
SubtractTimestamps(timestamp, timestamp))
ruleTest(dateTimeOperations, Subtract(timestamp, date),
SubtractTimestamps(timestamp, Cast(date, TimestampType)))
ruleTest(dateTimeOperations, Subtract(date, timestamp),
SubtractTimestamps(Cast(date, TimestampType), timestamp))
}

/**
* There are rules that need to not fire before child expressions get resolved.
* We use this test to make sure those rules do not fire early.
Expand Down Expand Up @@ -1586,27 +1548,6 @@ class TypeCoercionSuite extends AnalysisTest {
Multiply(CaseWhen(Seq((EqualTo(1, 2), Cast(1, DecimalType(34, 24)))),
Cast(100, DecimalType(34, 24))), Cast(1, IntegerType)))
}

test("rule for interval operations") {
val dateTimeOperations = TypeCoercion.DateTimeOperations
val interval = Literal(new CalendarInterval(0, 0, 0))

Seq(
Literal(10.toByte, ByteType),
Literal(10.toShort, ShortType),
Literal(10, IntegerType),
Literal(10L, LongType),
Literal(Decimal(10), DecimalType.SYSTEM_DEFAULT),
Literal(10.5.toFloat, FloatType),
Literal(10.5, DoubleType)).foreach { num =>
ruleTest(dateTimeOperations, Multiply(interval, num),
MultiplyInterval(interval, num))
ruleTest(dateTimeOperations, Multiply(num, interval),
MultiplyInterval(interval, num))
ruleTest(dateTimeOperations, Divide(interval, num),
DivideInterval(interval, num))
}
}
}


Expand Down
7 changes: 7 additions & 0 deletions sql/core/src/test/resources/sql-tests/inputs/datetime.sql
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,10 @@ select timestamp'2019-10-06 10:11:12.345678' - date'2020-01-01';

select date '2019-01-01\t';
select timestamp '2019-01-01\t';

select date '2001-09-28' + null;
select date '2001-09-28' - null;
select null + date '2001-09-28';
select null - date '2019-10-06';
select null - timestamp '2019-10-06 10:11:12.345678';
select timestamp '2019-10-06 10:11:12.345678' - null;
50 changes: 49 additions & 1 deletion sql/core/src/test/resources/sql-tests/results/datetime.sql.out
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-- Automatically generated by SQLQueryTestSuite
-- Number of queries: 19
-- Number of queries: 25


-- !query 0
Expand Down Expand Up @@ -161,3 +161,51 @@ select timestamp '2019-01-01\t'
struct<TIMESTAMP '2019-01-01 00:00:00':timestamp>
-- !query 18 output
2019-01-01 00:00:00


-- !query 19
select date '2001-09-28' + null
-- !query 19 schema
struct<date_add(DATE '2001-09-28', CAST(NULL AS INT)):date>
-- !query 19 output
NULL


-- !query 20
select date '2001-09-28' - null
-- !query 20 schema
struct<date_sub(DATE '2001-09-28', CAST(NULL AS INT)):date>
-- !query 20 output
NULL


-- !query 21
select null + date '2001-09-28'
-- !query 21 schema
struct<date_add(DATE '2001-09-28', CAST(NULL AS INT)):date>
-- !query 21 output
NULL


-- !query 22
select null - date '2019-10-06'
-- !query 22 schema
struct<subtractdates(CAST(NULL AS DATE), DATE '2019-10-06'):interval>
-- !query 22 output
NULL


-- !query 23
select null - timestamp '2019-10-06 10:11:12.345678'
-- !query 23 schema
struct<subtracttimestamps(CAST(NULL AS TIMESTAMP), TIMESTAMP '2019-10-06 10:11:12.345678'):interval>
-- !query 23 output
NULL


-- !query 24
select timestamp '2019-10-06 10:11:12.345678' - null
-- !query 24 schema
struct<subtracttimestamps(TIMESTAMP '2019-10-06 10:11:12.345678', CAST(NULL AS TIMESTAMP)):interval>
-- !query 24 output
NULL
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ struct<>
-- !query 6
select id, a+b, a-b, a*b, a/b from decimals_test order by id
-- !query 6 schema
struct<id:int,(a + b):decimal(38,17),(a - b):decimal(38,17),(a * b):decimal(38,6),(a / b):decimal(38,6)>
struct<id:int,(CAST(a AS DECIMAL(38,17)) + CAST(b AS DECIMAL(38,17))):decimal(38,17),(CAST(a AS DECIMAL(38,17)) - CAST(b AS DECIMAL(38,17))):decimal(38,17),(CAST(a AS DECIMAL(38,18)) * CAST(b AS DECIMAL(38,18))):decimal(38,6),(CAST(a AS DECIMAL(38,18)) / CAST(b AS DECIMAL(38,18))):decimal(38,6)>
-- !query 6 output
1 1099.00000000000000000 -899.00000000000000000 99900.000000 0.100100
2 24690.24600000000000000 0.00000000000000000 152402061.885129 1.000000
Expand Down Expand Up @@ -140,7 +140,7 @@ NULL
-- !query 16
select 12345678901234567890.0 * 12345678901234567890.0
-- !query 16 schema
struct<(12345678901234567890.0 * 12345678901234567890.0):decimal(38,2)>
struct<(CAST(12345678901234567890.0 AS DECIMAL(21,1)) * CAST(12345678901234567890.0 AS DECIMAL(21,1))):decimal(38,2)>
-- !query 16 output
NULL

Expand Down Expand Up @@ -196,7 +196,7 @@ spark.sql.decimalOperations.allowPrecisionLoss false
-- !query 23
select id, a+b, a-b, a*b, a/b from decimals_test order by id
-- !query 23 schema
struct<id:int,(a + b):decimal(38,18),(a - b):decimal(38,18),(a * b):decimal(38,36),(a / b):decimal(38,18)>
struct<id:int,(CAST(a AS DECIMAL(38,18)) + CAST(b AS DECIMAL(38,18))):decimal(38,18),(CAST(a AS DECIMAL(38,18)) - CAST(b AS DECIMAL(38,18))):decimal(38,18),(CAST(a AS DECIMAL(38,18)) * CAST(b AS DECIMAL(38,18))):decimal(38,36),(CAST(a AS DECIMAL(38,18)) / CAST(b AS DECIMAL(38,18))):decimal(38,18)>
-- !query 23 output
1 1099.000000000000000000 -899.000000000000000000 NULL 0.100100100100100100
2 24690.246000000000000000 0.000000000000000000 NULL 1.000000000000000000
Expand Down Expand Up @@ -282,7 +282,7 @@ NULL
-- !query 33
select 12345678901234567890.0 * 12345678901234567890.0
-- !query 33 schema
struct<(12345678901234567890.0 * 12345678901234567890.0):decimal(38,2)>
struct<(CAST(12345678901234567890.0 AS DECIMAL(21,1)) * CAST(12345678901234567890.0 AS DECIMAL(21,1))):decimal(38,2)>
-- !query 33 output
NULL

Expand Down
Loading