private def validateFunction()

in sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionResolution.scala [126:254]


  private def validateFunction(
      func: Expression,
      numArgs: Int,
      u: UnresolvedFunction): Expression = {
    func match {
      case owg: SupportsOrderingWithinGroup if !owg.isDistinctSupported && u.isDistinct =>
        throw QueryCompilationErrors.distinctWithOrderingFunctionUnsupportedError(owg.prettyName)
      case owg: SupportsOrderingWithinGroup
          if owg.isOrderingMandatory && !owg.orderingFilled && u.orderingWithinGroup.isEmpty =>
        throw QueryCompilationErrors.functionMissingWithinGroupError(owg.prettyName)
      case owg: SupportsOrderingWithinGroup
          if owg.orderingFilled && u.orderingWithinGroup.nonEmpty =>
        // e.g mode(expr1) within group (order by expr2) is not supported
        throw QueryCompilationErrors.wrongNumOrderingsForFunctionError(
          owg.prettyName,
          0,
          u.orderingWithinGroup.length
        )
      case f if !f.isInstanceOf[SupportsOrderingWithinGroup] && u.orderingWithinGroup.nonEmpty =>
        throw QueryCompilationErrors.functionWithUnsupportedSyntaxError(
          func.prettyName,
          "WITHIN GROUP (ORDER BY ...)"
        )
      // AggregateWindowFunctions are AggregateFunctions that can only be evaluated within
      // the context of a Window clause. They do not need to be wrapped in an
      // AggregateExpression.
      case wf: AggregateWindowFunction =>
        if (u.isDistinct) {
          throw QueryCompilationErrors.functionWithUnsupportedSyntaxError(wf.prettyName, "DISTINCT")
        } else if (u.filter.isDefined) {
          throw QueryCompilationErrors.functionWithUnsupportedSyntaxError(
            wf.prettyName,
            "FILTER clause"
          )
        } else if (u.ignoreNulls) {
          wf match {
            case nthValue: NthValue =>
              nthValue.copy(ignoreNulls = u.ignoreNulls)
            case _ =>
              throw QueryCompilationErrors.functionWithUnsupportedSyntaxError(
                wf.prettyName,
                "IGNORE NULLS"
              )
          }
        } else {
          wf
        }
      case owf: FrameLessOffsetWindowFunction =>
        if (u.isDistinct) {
          throw QueryCompilationErrors.functionWithUnsupportedSyntaxError(
            owf.prettyName,
            "DISTINCT"
          )
        } else if (u.filter.isDefined) {
          throw QueryCompilationErrors.functionWithUnsupportedSyntaxError(
            owf.prettyName,
            "FILTER clause"
          )
        } else if (u.ignoreNulls) {
          owf match {
            case lead: Lead =>
              lead.copy(ignoreNulls = u.ignoreNulls)
            case lag: Lag =>
              lag.copy(ignoreNulls = u.ignoreNulls)
          }
        } else {
          owf
        }
      // We get an aggregate function, we need to wrap it in an AggregateExpression.
      case agg: AggregateFunction =>
        // Note: PythonUDAF does not support these advanced clauses.
        if (agg.isInstanceOf[PythonUDAF]) checkUnsupportedAggregateClause(agg, u)
        // After parse, the functions not set the ordering within group yet.
        val newAgg = agg match {
          case owg: SupportsOrderingWithinGroup
              if !owg.orderingFilled && u.orderingWithinGroup.nonEmpty =>
            owg.withOrderingWithinGroup(u.orderingWithinGroup)
          case _ =>
            agg
        }

        u.filter match {
          case Some(filter) if !filter.deterministic =>
            throw QueryCompilationErrors.nonDeterministicFilterInAggregateError(filterExpr = filter)
          case Some(filter) if filter.dataType != BooleanType =>
            throw QueryCompilationErrors.nonBooleanFilterInAggregateError(filterExpr = filter)
          case Some(filter) if filter.exists(_.isInstanceOf[AggregateExpression]) =>
            throw QueryCompilationErrors.aggregateInAggregateFilterError(
              filterExpr = filter,
              aggExpr = filter.find(_.isInstanceOf[AggregateExpression]).get
            )
          case Some(filter) if filter.exists(_.isInstanceOf[WindowExpression]) =>
            throw QueryCompilationErrors.windowFunctionInAggregateFilterError(
              filterExpr = filter,
              windowExpr = filter.find(_.isInstanceOf[WindowExpression]).get
            )
          case _ =>
        }
        if (u.ignoreNulls) {
          val aggFunc = newAgg match {
            case first: First => first.copy(ignoreNulls = u.ignoreNulls)
            case last: Last => last.copy(ignoreNulls = u.ignoreNulls)
            case any_value: AnyValue => any_value.copy(ignoreNulls = u.ignoreNulls)
            case _ =>
              throw QueryCompilationErrors.functionWithUnsupportedSyntaxError(
                newAgg.prettyName,
                "IGNORE NULLS"
              )
          }
          aggFunc.toAggregateExpression(u.isDistinct, u.filter)
        } else {
          newAgg.toAggregateExpression(u.isDistinct, u.filter)
        }
      // This function is not an aggregate function, just return the resolved one.
      case other =>
        checkUnsupportedAggregateClause(other, u)
        if (other.isInstanceOf[String2TrimExpression] && numArgs == 2) {
          if (trimWarningEnabled.get) {
            log.warn(
              "Two-parameter TRIM/LTRIM/RTRIM function signatures are deprecated." +
              " Use SQL syntax `TRIM((BOTH | LEADING | TRAILING)? trimStr FROM str)`" +
              " instead."
            )
            trimWarningEnabled.set(false)
          }
        }
        other
    }
  }