-
Notifications
You must be signed in to change notification settings - Fork 29k
[SPARK-19951][SQL] Add string concatenate operator || to Spark SQL #17711
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
5544ff2
05d490e
afcd950
f89d131
5957545
cb4b26e
8890b94
df3869a
c88652c
96db575
de89791
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,6 @@ | ||
| -- Argument number exception | ||
| select concat_ws(); | ||
| select format_string(); | ||
|
|
||
| -- A pipe operator for string concatenation | ||
| select 'a' || 'b' || 'c'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,286 @@ | ||
| -- Automatically generated by SQLQueryTestSuite | ||
| -- Number of queries: 34 | ||
|
|
||
|
|
||
| -- !query 0 | ||
| select -100 | ||
| -- !query 0 schema | ||
| struct<-100:int> | ||
| -- !query 0 output | ||
| -100 | ||
|
|
||
|
|
||
| -- !query 1 | ||
| select +230 | ||
| -- !query 1 schema | ||
| struct<230:int> | ||
| -- !query 1 output | ||
| 230 | ||
|
|
||
|
|
||
| -- !query 2 | ||
| select -5.2 | ||
| -- !query 2 schema | ||
| struct<-5.2:decimal(2,1)> | ||
| -- !query 2 output | ||
| -5.2 | ||
|
|
||
|
|
||
| -- !query 3 | ||
| select +6.8e0 | ||
| -- !query 3 schema | ||
| struct<6.8:decimal(2,1)> | ||
| -- !query 3 output | ||
| 6.8 | ||
|
|
||
|
|
||
| -- !query 4 | ||
| select -key, +key from testdata where key = 2 | ||
| -- !query 4 schema | ||
| struct<(- key):int,key:int> | ||
| -- !query 4 output | ||
| -2 2 | ||
|
|
||
|
|
||
| -- !query 5 | ||
| select -(key + 1), - key + 1, +(key + 5) from testdata where key = 1 | ||
| -- !query 5 schema | ||
| struct<(- (key + 1)):int,((- key) + 1):int,(key + 5):int> | ||
| -- !query 5 output | ||
| -2 0 6 | ||
|
|
||
|
|
||
| -- !query 6 | ||
| select -max(key), +max(key) from testdata | ||
| -- !query 6 schema | ||
| struct<(- max(key)):int,max(key):int> | ||
| -- !query 6 output | ||
| -100 100 | ||
|
|
||
|
|
||
| -- !query 7 | ||
| select - (-10) | ||
| -- !query 7 schema | ||
| struct<(- -10):int> | ||
| -- !query 7 output | ||
| 10 | ||
|
|
||
|
|
||
| -- !query 8 | ||
| select + (-key) from testdata where key = 32 | ||
| -- !query 8 schema | ||
| struct<(- key):int> | ||
| -- !query 8 output | ||
| -32 | ||
|
|
||
|
|
||
| -- !query 9 | ||
| select - (+max(key)) from testdata | ||
| -- !query 9 schema | ||
| struct<(- max(key)):int> | ||
| -- !query 9 output | ||
| -100 | ||
|
|
||
|
|
||
| -- !query 10 | ||
| select - - 3 | ||
| -- !query 10 schema | ||
| struct<(- -3):int> | ||
| -- !query 10 output | ||
| 3 | ||
|
|
||
|
|
||
| -- !query 11 | ||
| select - + 20 | ||
| -- !query 11 schema | ||
| struct<(- 20):int> | ||
| -- !query 11 output | ||
| -20 | ||
|
|
||
|
|
||
| -- !query 12 | ||
| select + + 100 | ||
| -- !query 12 schema | ||
| struct<100:int> | ||
| -- !query 12 output | ||
| 100 | ||
|
|
||
|
|
||
| -- !query 13 | ||
| select - - max(key) from testdata | ||
| -- !query 13 schema | ||
| struct<(- (- max(key))):int> | ||
| -- !query 13 output | ||
| 100 | ||
|
|
||
|
|
||
| -- !query 14 | ||
| select + - key from testdata where key = 33 | ||
| -- !query 14 schema | ||
| struct<(- key):int> | ||
| -- !query 14 output | ||
| -33 | ||
|
|
||
|
|
||
| -- !query 15 | ||
| select 5 / 2 | ||
| -- !query 15 schema | ||
| struct<(CAST(5 AS DOUBLE) / CAST(2 AS DOUBLE)):double> | ||
| -- !query 15 output | ||
| 2.5 | ||
|
|
||
|
|
||
| -- !query 16 | ||
| select 5 / 0 | ||
| -- !query 16 schema | ||
| struct<(CAST(5 AS DOUBLE) / CAST(0 AS DOUBLE)):double> | ||
| -- !query 16 output | ||
| NULL | ||
|
|
||
|
|
||
| -- !query 17 | ||
| select 5 / null | ||
| -- !query 17 schema | ||
| struct<(CAST(5 AS DOUBLE) / CAST(NULL AS DOUBLE)):double> | ||
| -- !query 17 output | ||
| NULL | ||
|
|
||
|
|
||
| -- !query 18 | ||
| select null / 5 | ||
| -- !query 18 schema | ||
| struct<(CAST(NULL AS DOUBLE) / CAST(5 AS DOUBLE)):double> | ||
| -- !query 18 output | ||
| NULL | ||
|
|
||
|
|
||
| -- !query 19 | ||
| select 5 div 2 | ||
| -- !query 19 schema | ||
| struct<CAST((CAST(5 AS DOUBLE) / CAST(2 AS DOUBLE)) AS BIGINT):bigint> | ||
| -- !query 19 output | ||
| 2 | ||
|
|
||
|
|
||
| -- !query 20 | ||
| select 5 div 0 | ||
| -- !query 20 schema | ||
| struct<CAST((CAST(5 AS DOUBLE) / CAST(0 AS DOUBLE)) AS BIGINT):bigint> | ||
| -- !query 20 output | ||
| NULL | ||
|
|
||
|
|
||
| -- !query 21 | ||
| select 5 div null | ||
| -- !query 21 schema | ||
| struct<CAST((CAST(5 AS DOUBLE) / CAST(NULL AS DOUBLE)) AS BIGINT):bigint> | ||
| -- !query 21 output | ||
| NULL | ||
|
|
||
|
|
||
| -- !query 22 | ||
| select null div 5 | ||
| -- !query 22 schema | ||
| struct<CAST((CAST(NULL AS DOUBLE) / CAST(5 AS DOUBLE)) AS BIGINT):bigint> | ||
| -- !query 22 output | ||
| NULL | ||
|
|
||
|
|
||
| -- !query 23 | ||
| select 1 + 2 | ||
| -- !query 23 schema | ||
| struct<(1 + 2):int> | ||
| -- !query 23 output | ||
| 3 | ||
|
|
||
|
|
||
| -- !query 24 | ||
| select 1 - 2 | ||
| -- !query 24 schema | ||
| struct<(1 - 2):int> | ||
| -- !query 24 output | ||
| -1 | ||
|
|
||
|
|
||
| -- !query 25 | ||
| select 2 * 5 | ||
| -- !query 25 schema | ||
| struct<(2 * 5):int> | ||
| -- !query 25 output | ||
| 10 | ||
|
|
||
|
|
||
| -- !query 26 | ||
| select 5 % 3 | ||
| -- !query 26 schema | ||
| struct<(5 % 3):int> | ||
| -- !query 26 output | ||
| 2 | ||
|
|
||
|
|
||
| -- !query 27 | ||
| select pmod(-7, 3) | ||
| -- !query 27 schema | ||
| struct<pmod(-7, 3):int> | ||
| -- !query 27 output | ||
| 2 | ||
|
|
||
|
|
||
| -- !query 28 | ||
| explain select 'a' || 1 + 2 | ||
| -- !query 28 schema | ||
| struct<plan:string> | ||
| -- !query 28 output | ||
| == Physical Plan == | ||
| *Project [null AS (CAST(concat(a, CAST(1 AS STRING)) AS DOUBLE) + CAST(2 AS DOUBLE))#x] | ||
| +- Scan OneRowRelation[] | ||
|
|
||
|
|
||
| -- !query 29 | ||
| explain select 1 - 2 || 'b' | ||
| -- !query 29 schema | ||
| struct<plan:string> | ||
| -- !query 29 output | ||
| == Physical Plan == | ||
| *Project [-1b AS concat(CAST((1 - 2) AS STRING), b)#x] | ||
| +- Scan OneRowRelation[] | ||
|
|
||
|
|
||
| -- !query 30 | ||
| explain select 2 * 4 + 3 || 'b' | ||
| -- !query 30 schema | ||
| struct<plan:string> | ||
| -- !query 30 output | ||
| == Physical Plan == | ||
| *Project [11b AS concat(CAST(((2 * 4) + 3) AS STRING), b)#x] | ||
| +- Scan OneRowRelation[] | ||
|
|
||
|
|
||
| -- !query 31 | ||
| explain select 3 + 1 || 'a' || 4 / 2 | ||
| -- !query 31 schema | ||
| struct<plan:string> | ||
| -- !query 31 output | ||
| == Physical Plan == | ||
| *Project [4a2.0 AS concat(concat(CAST((3 + 1) AS STRING), a), CAST((CAST(4 AS DOUBLE) / CAST(2 AS DOUBLE)) AS STRING))#x] | ||
| +- Scan OneRowRelation[] | ||
|
|
||
|
|
||
| -- !query 32 | ||
| explain select 1 == 1 OR 'a' || 'b' == 'ab' | ||
| -- !query 32 schema | ||
| struct<plan:string> | ||
| -- !query 32 output | ||
| == Physical Plan == | ||
| *Project [true AS ((1 = 1) OR (concat(a, b) = ab))#x] | ||
| +- Scan OneRowRelation[] | ||
|
|
||
|
|
||
| -- !query 33 | ||
| explain select 'a' || 'c' == 'ac' AND 2 == 3 | ||
| -- !query 33 schema | ||
| struct<plan:string> | ||
| -- !query 33 output | ||
| == Physical Plan == | ||
| *Project [false AS ((concat(a, c) = ac) AND (2 = 3))#x] | ||
| +- Scan OneRowRelation[] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,9 +19,9 @@ package org.apache.spark.sql.execution | |
|
|
||
| import org.apache.spark.sql.SaveMode | ||
| import org.apache.spark.sql.catalyst.{FunctionIdentifier, TableIdentifier} | ||
| import org.apache.spark.sql.catalyst.analysis.{UnresolvedAttribute, UnresolvedRelation, UnresolvedStar} | ||
| import org.apache.spark.sql.catalyst.analysis.{UnresolvedAlias, UnresolvedAttribute, UnresolvedRelation, UnresolvedStar} | ||
| import org.apache.spark.sql.catalyst.catalog.{BucketSpec, CatalogStorageFormat, CatalogTable, CatalogTableType} | ||
| import org.apache.spark.sql.catalyst.expressions.{Ascending, SortOrder} | ||
| import org.apache.spark.sql.catalyst.expressions.{Ascending, Concat, SortOrder} | ||
| import org.apache.spark.sql.catalyst.parser.ParseException | ||
| import org.apache.spark.sql.catalyst.plans.PlanTest | ||
| import org.apache.spark.sql.catalyst.plans.logical.{LogicalPlan, Project, RepartitionByExpression, Sort} | ||
|
|
@@ -290,4 +290,15 @@ class SparkSqlParserSuite extends PlanTest { | |
| basePlan, | ||
| numPartitions = newConf.numShufflePartitions))) | ||
| } | ||
|
|
||
| test("pipeline concatenation") { | ||
| val concat = Concat( | ||
| Concat(UnresolvedAttribute("a") :: UnresolvedAttribute("b") :: Nil) :: | ||
| UnresolvedAttribute("c") :: | ||
| Nil | ||
| ) | ||
| assertEqual( | ||
| "SELECT a || b || c FROM t", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If it is tricky to combine sequential
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. aha, I see. WDYT, @gatorsmile ?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. I prefer to simpler codes.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, I'll try to add a new rule for that. Thanks!
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually I am thinking is a follow PR to add the rule.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea, I also feel so. Is it okay to remove the rule from this pr? @gatorsmile. If ok, I'll fix the points you reviewed in follow-up.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am fine
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reverted, thanks |
||
| Project(UnresolvedAlias(concat) :: Nil, UnresolvedRelation(TableIdentifier("t")))) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As arithmetic.sql is renamed to operator.sql and operator.sql.out is added, shall we remove arithmetic.sql.out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: rename it to
operators.sql?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok