Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
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 @@ -564,8 +564,7 @@ valueExpression
;

primaryExpression
: name=(CURRENT_DATE | CURRENT_TIMESTAMP) #timeFunctionCall
| CASE whenClause+ (ELSE elseExpression=expression)? END #searchedCase
: CASE whenClause+ (ELSE elseExpression=expression)? END #searchedCase
| CASE value=expression whenClause+ (ELSE elseExpression=expression)? END #simpleCase
| CAST '(' expression AS dataType ')' #cast
| STRUCT '(' (argument+=namedExpression (',' argument+=namedExpression)*)? ')' #struct
Expand Down Expand Up @@ -747,7 +746,7 @@ nonReserved
| NULL | ORDER | OUTER | TABLE | TRUE | WITH | RLIKE
| AND | CASE | CAST | DISTINCT | DIV | ELSE | END | FUNCTION | INTERVAL | MACRO | OR | STRATIFY | THEN
| UNBOUNDED | WHEN
| DATABASE | SELECT | FROM | WHERE | HAVING | TO | TABLE | WITH | NOT | CURRENT_DATE | CURRENT_TIMESTAMP
| DATABASE | SELECT | FROM | WHERE | HAVING | TO | TABLE | WITH | NOT
| DIRECTORY
| BOTH | LEADING | TRAILING
;
Expand Down Expand Up @@ -983,8 +982,6 @@ OPTION: 'OPTION';
ANTI: 'ANTI';
LOCAL: 'LOCAL';
INPATH: 'INPATH';
CURRENT_DATE: 'CURRENT_DATE';
CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP';

STRING
: '\'' ( ~('\''|'\\') | ('\\' .) )* '\''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class Analyzer(
ExtractGenerator ::
ResolveGenerate ::
ResolveFunctions ::
ResolveLiteralFunctions ::

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The order matters. It assumes ResolveReferences should be run before this rule. However, ResolveReferences might need multiple passes to resolve all the references. Thus, how about moving the logics into ResolveReferences ? If the attributes are not resolvable, we try to see whether it is a function literal?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agree! I will refactor it.

ResolveAliases ::
ResolveSubquery ::
ResolveSubqueryColumnAliases ::
Expand Down Expand Up @@ -1205,6 +1206,39 @@ class Analyzer(
}
}

/**
* Literal functions do not require the user to specify braces when calling them
* When an UnresolvedAttribute cannot be resolved as a column reference, we try to
* resolve it as a Literal function.
*/
object ResolveLiteralFunctions extends Rule[LogicalPlan] {
// support CURRENT_DATE and CURRENT_TIMESTAMP
val literalFunctions = Seq(CurrentDate(), CurrentTimestamp())

def resolveAsFunctions(name: String): Option[NamedExpression] = {
val func = literalFunctions.find(e => resolver(e.prettyName, name))
if (func.isDefined) {
Some(Alias(func.get, toPrettySQL(func.get))())
} else {
None
}
}

def apply(plan: LogicalPlan): LogicalPlan = plan resolveOperators {
case p: LogicalPlan if p.childrenResolved =>
p transformExpressionsUp {
case u if !u.childrenResolved => u
case u @ UnresolvedAttribute(nameParts) if (nameParts.length == 1) =>
val result =
withPosition(u) {
resolveAsFunctions(nameParts.head).getOrElse(u)
}
logDebug(s"Resolving $u as Literal function $result")
result
}
}
}

/**
* This rule resolves and rewrites subqueries inside expressions.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1234,19 +1234,6 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
}
}

/**
* Create a current timestamp/date expression. These are different from regular function because
* they do not require the user to specify braces when calling them.
*/
override def visitTimeFunctionCall(ctx: TimeFunctionCallContext): Expression = withOrigin(ctx) {
ctx.name.getType match {
case SqlBaseParser.CURRENT_DATE =>
CurrentDate()
case SqlBaseParser.CURRENT_TIMESTAMP =>
CurrentTimestamp()
}
}

/**
* Create a function database (optional) and name pair.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ class DateFunctionsSuite extends QueryTest with SharedSQLContext {
checkAnswer(sql("""SELECT CURRENT_TIMESTAMP() = NOW()"""), Row(true))
}

test("SPARK-22333: timeFunctionCall has conflicts with columnReference ") {
val df = Seq((1, 2), (2, 3)).toDF("current_date", "current_timestamp")
df.createOrReplaceTempView("ttf")
withTempView("ttf") {
checkAnswer(sql("SELECT current_date, current_timestamp FROM ttf"),
Seq(Row(1, 2), Row(2, 3)))
}

val df1 = Seq((1, 2), (2, 3)).toDF("a", "b")
df1.createOrReplaceTempView("ttf1")
withTempView("ttf1") {
checkAnswer(
sql("SELECT current_date = current_date(), current_timestamp = current_timestamp(), " +
"a, b FROM ttf"),
Seq(Row(true, true, 1, 2), Row(true, true, 2, 3)))
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Move these to datetime.sql?


val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US)
val sdfDate = new SimpleDateFormat("yyyy-MM-dd", Locale.US)
val d = new Date(sdf.parse("2015-04-08 13:10:15").getTime)
Expand Down