// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.


#ifndef IMPALA_EXPRS_SCALAR_FN_CALL_H_
#define IMPALA_EXPRS_SCALAR_FN_CALL_H_

#include <string>

#include "exprs/scalar-expr.h"
#include "udf/udf.h"

namespace impala {

using impala_udf::FunctionContext;
using impala_udf::AnyVal;
using impala_udf::BooleanVal;
using impala_udf::TinyIntVal;
using impala_udf::SmallIntVal;
using impala_udf::IntVal;
using impala_udf::BigIntVal;
using impala_udf::FloatVal;
using impala_udf::DoubleVal;
using impala_udf::TimestampVal;
using impala_udf::StringVal;
using impala_udf::DecimalVal;
using impala_udf::DateVal;

class ScalarExprEvaluator;
class TExprNode;

/// Expr for evaluating a pre-compiled native or LLVM IR function that uses the UDF
/// interface (i.e. a scalar function). This class overrides GetCodegendComputeFnImpl() to
/// return a function that calls any child exprs and passes the results as arguments to
/// the specified scalar function.
///
/// If codegen is disabled, some native functions can be called without codegen, depending
/// on the native function's signature. However, since we can't write static code to call
/// every possible function signature, codegen may be required to generate the call to the
/// function even if codegen is disabled. Codegen will also be used for IR UDFs (note that
/// there is no way to specify both a native and IR library for a single UDF).
///
/// Scalar function call: An expr that returns a single scalar value and can be
/// implemented using the UDF interface. Note that this includes builtins, which although
/// not being user-defined still use the same interface as UDFs (i.e., they are
/// implemented as functions with signature "*Val (FunctionContext*, *Val, *Val...)").
///
/// TODO:
/// - Fix error reporting, e.g. reporting leaks
/// - Testing
///    - Test cancellation
///    - Type descs in UDA test harness
///    - Allow more functions to be NULL in UDA test harness
class ScalarFnCall : public ScalarExpr {
 public:
  virtual Status GetCodegendComputeFnImpl(LlvmCodeGen* codegen, llvm::Function** fn)
      override WARN_UNUSED_RESULT;
  virtual std::string DebugString() const override;

 protected:
  friend class ScalarExpr;
  friend class ScalarExprEvaluator;

  virtual bool HasFnCtx() const override { return true; }

  ScalarFnCall(const TExprNode& node);
  virtual Status Init(const RowDescriptor& row_desc, bool is_entry_point,
      RuntimeState* state) override WARN_UNUSED_RESULT;
  virtual Status OpenEvaluator(FunctionContext::FunctionStateScope scope,
      RuntimeState* state, ScalarExprEvaluator* eval) const override WARN_UNUSED_RESULT;
  virtual void CloseEvaluator(FunctionContext::FunctionStateScope scope,
      RuntimeState* state, ScalarExprEvaluator* eval) const override;
  virtual int ComputeVarArgsBufferSize() const override;
  /// Not all scalars functions are interpretable - see class comment.
  virtual bool IsInterpretable() const override;

  GENERATE_GET_VAL_INTERPRETED_OVERRIDES_FOR_ALL_SCALAR_TYPES

 private:
  /// If this function has var args, children()[vararg_start_idx_] is the first vararg
  /// argument.
  /// If this function does not have varargs, it is set to -1.
  const int vararg_start_idx_;

  /// Vector of all non-constant children expressions that need to be evaluated for
  /// each input row. The first element of each pair is the child expression and the
  /// second element in the value it must be evaluated into.
  std::vector<std::pair<Expr*, impala_udf::AnyVal*>> non_constant_children_;

  /// The UDF's prepare function, if specified. This is initialized in Prepare() and
  /// called in Open() (since we may have needed to codegen the function if it's from an
  /// IR module).
  impala_udf::UdfPrepare prepare_fn_;

  /// THe UDF's close function, if specified. This is initialized in Prepare() and called
  /// in Close().
  impala_udf::UdfClose close_fn_;

  /// A pointer to the function implementation, used by the interpreted code path. Set in
  /// Init() for BUILTIN and NATIVE functions. Not set for IR UDFs.
  void* scalar_fn_;

  /// Returns the number of non-vararg arguments
  int NumFixedArgs() const {
    return vararg_start_idx_ >= 0 ? vararg_start_idx_ : children_.size();
  }

  virtual int NumVarArgs() const { return children_.size() - NumFixedArgs(); }

  const ColumnType& VarArgsType() const {
    DCHECK_GE(NumVarArgs(), 1);
    return children_.back()->type();
  }

  /// Loads the native or IR function 'symbol' from HDFS and puts the result in *fn.
  /// If the function is loaded from an IR module, it cannot be called until the module
  /// has been JIT'd (i.e. after GetCodegendComputeFnImpl() has been called).
  Status GetFunction(
      LlvmCodeGen* codegen, const std::string& symbol, void** fn) WARN_UNUSED_RESULT;

  /// Loads the Prepare() and Close() functions for this ScalarFnCall. They could be
  /// native or IR functions. To load IR functions, the codegen object must have
  /// been created and any external LLVM module must have been linked already.
  Status LoadPrepareAndCloseFn(LlvmCodeGen* codegen) WARN_UNUSED_RESULT;

  /// Evaluates the non-constant children exprs. Used in the interpreted path.
  void EvaluateNonConstantChildren(
      ScalarExprEvaluator* eval, const TupleRow* row) const;

  /// Function to call scalar_fn_. Used in the interpreted path.
  template <typename RETURN_TYPE>
  RETURN_TYPE InterpretEval(ScalarExprEvaluator* eval, const TupleRow* row) const;
};
}

#endif
