Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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 @@ -423,6 +423,7 @@ object FunctionRegistry {
expression[MakeTimestamp]("make_timestamp"),
expression[MakeInterval]("make_interval"),
expression[DatePart]("date_part"),
expression[Extract]("extract"),
Copy link
Contributor

Choose a reason for hiding this comment

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

one side effect is now we support extract(field, source) other than extract(field from source). Not a big deal but better if we can avoid exposing more APIs,

Copy link
Member Author

Choose a reason for hiding this comment

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

Not a big deal but better if we can avoid exposing more APIs

Yea, +1 .

btw, its better to add tests for the case extract(field, source)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea if we decide to support it.

Copy link
Member Author

Choose a reason for hiding this comment

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

ok, I'll do follow-up later.

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 opened #28276


// collection functions
expression[CreateArray]("array"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2105,6 +2105,31 @@ object DatePart {
}
}

object DatePartLike {

def toEquivalentExpr(field: Expression, source: Expression): Expression = {
if (!field.foldable) {
throw new AnalysisException("The field parameter needs to be a foldable string value.")
}
val fieldEval = field.eval()
if (fieldEval == null) {
Literal(null, DoubleType)
} else {
val fieldStr = fieldEval.asInstanceOf[UTF8String].toString
val errMsg = s"Literals of type '$fieldStr' are currently not supported " +
s"for the ${source.dataType.catalogString} type."
if (source.dataType == CalendarIntervalType) {
ExtractIntervalPart.parseExtractField(
fieldStr,
source,
throw new AnalysisException(errMsg))
} else {
DatePart.parseExtractField(fieldStr, source, throw new AnalysisException(errMsg))
}
}
}
}

@ExpressionDescription(
usage = "_FUNC_(field, source) - Extracts a part of the date/timestamp or interval source.",
arguments = """
Expand Down Expand Up @@ -2158,35 +2183,51 @@ object DatePart {
case class DatePart(field: Expression, source: Expression, child: Expression)
extends RuntimeReplaceable {

def this(field: Expression, source: Expression) {
this(field, source, {
if (!field.foldable) {
throw new AnalysisException("The field parameter needs to be a foldable string value.")
}
val fieldEval = field.eval()
if (fieldEval == null) {
Literal(null, DoubleType)
} else {
val fieldStr = fieldEval.asInstanceOf[UTF8String].toString
val errMsg = s"Literals of type '$fieldStr' are currently not supported " +
s"for the ${source.dataType.catalogString} type."
if (source.dataType == CalendarIntervalType) {
ExtractIntervalPart.parseExtractField(
fieldStr,
source,
throw new AnalysisException(errMsg))
} else {
DatePart.parseExtractField(fieldStr, source, throw new AnalysisException(errMsg))
}
}
})
def this(field: Expression, source: Expression) = {
this(field, source, DatePartLike.toEquivalentExpr(field, source))
}

override def flatArguments: Iterator[Any] = Iterator(field, source)
override def sql: String = s"$prettyName(${field.sql}, ${source.sql})"
override def prettyName: String = "date_part"
}

@ExpressionDescription(
usage = "_FUNC_(field FROM source) - Extracts a part of the date/timestamp or interval source.",
arguments = """
Arguments:
* field - selects which part of the source should be extracted and supported string values
are the same with the `date_part` fields.
* source - a date/timestamp or interval column from where `field` should be extracted
""",
examples = """
Examples:
> SELECT _FUNC_(YEAR FROM TIMESTAMP '2019-08-12 01:00:00.123456');
2019
> SELECT _FUNC_(week FROM timestamp'2019-08-12 01:00:00.123456');
33
> SELECT _FUNC_(doy FROM DATE'2019-08-12');
224
> SELECT _FUNC_(SECONDS FROM timestamp'2019-10-01 00:00:01.000001');
1.000001
> SELECT _FUNC_(days FROM interval 1 year 10 months 5 days);
5
> SELECT _FUNC_(seconds FROM interval 5 hours 30 seconds 1 milliseconds 1 microseconds);
30.001001
""",
since = "3.0.0")
case class Extract(field: Expression, source: Expression, child: Expression)
extends RuntimeReplaceable {

def this(field: Expression, source: Expression) = {
this(field, source, DatePartLike.toEquivalentExpr(field, source))
}

override def flatArguments: Iterator[Any] = Iterator(field, source)
override def sql: String = s"$prettyName(${field.sql} FROM ${source.sql})"
override def prettyName: String = "extract"
}

/**
* Returns the interval from startTimestamp to endTimestamp in which the `months` and `day` field
* is set to 0 and the `microseconds` field is initialized to the microsecond difference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1550,7 +1550,7 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
*/
override def visitExtract(ctx: ExtractContext): Expression = withOrigin(ctx) {
val arguments = Seq(Literal(ctx.field.getText), expression(ctx.source))
UnresolvedFunction("date_part", arguments, isDistinct = false)
UnresolvedFunction("extract", arguments, isDistinct = false)
}

/**
Expand Down
Loading