content: /*
   * 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.
   */
  package org.apache.calcite.sql;
  
  import org.apache.calcite.adapter.enumerable.EnumUtils;
  import org.apache.calcite.rel.type.RelDataType;
  import org.apache.calcite.rel.type.RelDataTypeFactory;
  import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
  import org.apache.calcite.runtime.CalciteException;
  import org.apache.calcite.runtime.Resources;
  import org.apache.calcite.sql.type.SqlTypeName;
  import org.apache.calcite.sql.type.SqlTypeTransform;
  import org.apache.calcite.sql.validate.SqlMonotonicity;
  import org.apache.calcite.sql.validate.SqlValidatorException;
  import org.apache.calcite.util.NlsString;
  
  import org.checkerframework.checker.nullness.qual.Nullable;
  
  import java.util.AbstractList;
  import java.util.List;
  
  /**
   * <code>SqlOperatorBinding</code> represents the binding of an
   * {@link SqlOperator} to actual operands, along with any additional information
   * required to validate those operands if needed.
   */
  public abstract class SqlOperatorBinding {
    //~ Instance fields --------------------------------------------------------
  
    protected final RelDataTypeFactory typeFactory;
    private final SqlOperator sqlOperator;
  
    //~ Constructors -----------------------------------------------------------
  
    /**
     * Creates a SqlOperatorBinding.
     *
     * @param typeFactory Type factory
     * @param sqlOperator Operator which is subject of this call
     */
    protected SqlOperatorBinding(
        RelDataTypeFactory typeFactory,
        SqlOperator sqlOperator) {
      this.typeFactory = typeFactory;
      this.sqlOperator = sqlOperator;
    }
  
    //~ Methods ----------------------------------------------------------------
  
    /**
     * If the operator call occurs in an aggregate query, returns the number of
     * columns in the GROUP BY clause. For example, for "SELECT count(*) FROM emp
     * GROUP BY deptno, gender", returns 2.
     *
     * <p>Returns 0 if the query is implicitly "GROUP BY ()" because of an
     * aggregate expression. For example, "SELECT sum(sal) FROM emp".
     *
     * <p>Returns -1 if the query is not an aggregate query.
     */
    @Deprecated
    public int getGroupCount() {
      return -1;
    }
  
    /**
     * If the operator call occurs in an aggregate query, returns whether there are
     * empty groups in the GROUP BY clause. For example,
     *
     * <pre>
     * SELECT count(*) FROM emp GROUP BY deptno, gender;            returns false
     * SELECT count(*) FROM emp;                                    returns true
     * SELECT count(*) FROM emp GROUP BY ROLLUP(deptno, gender);    returns true
     * </pre>
     * Returns false if the query is not an aggregate query.
     */
    public boolean hasEmptyGroup() {
      return false;
    }
  
    /**
     * Returns whether the operator is an aggregate function with a filter.
     */
    public boolean hasFilter() {
      return false;
    }
  
    /** Returns the bound operator. */
    public SqlOperator getOperator() {
      return sqlOperator;
    }
  
    /** Returns the factory for type creation. */
    public RelDataTypeFactory getTypeFactory() {
      return typeFactory;
    }
  
    /**
     * Gets the string value of a string literal operand.
     *
     * @param ordinal zero-based ordinal of operand of interest
     * @return string value
     */
    @Deprecated // to be removed before 2.0
    public @Nullable String getStringLiteralOperand(int ordinal) {
      throw new UnsupportedOperationException();
    }
  
    /**
     * Gets the integer value of a numeric literal operand.
     *
     * @param ordinal zero-based ordinal of operand of interest
     * @return integer value
     */
    @Deprecated // to be removed before 2.0
    public int getIntLiteralOperand(int ordinal) {
      throw new UnsupportedOperationException();
    }
  
    /**
     * Gets the value of a literal operand.
     *
     * <p>Cases:
     * <ul>
     * <li>If the operand is not a literal, the value is null.
     *
     * <li>If the operand is a string literal,
     * the value will be of type {@link org.apache.calcite.util.NlsString}.
     *
     * <li>If the operand is a numeric literal,
     * the value will be of type {@link java.math.BigDecimal}.
     *
     * <li>If the operand is an interval qualifier,
     * the value will be of type {@link SqlIntervalQualifier}</li>
     *
     * <li>Otherwise the type is undefined, and the value may be null.
     * </ul>
     *
     * @param ordinal zero-based ordinal of operand of interest
     * @param clazz Desired valued type
     *
     * @return value of operand
     */
    public <T extends Object> @Nullable T getOperandLiteralValue(int ordinal, Class<T> clazz) {
      throw new UnsupportedOperationException();
    }
  
    /**
     * Gets the value of a literal operand as a Calcite type.
     *
     * @param ordinal zero-based ordinal of operand of interest
     * @param type Desired valued type
     *
     * @return value of operand
     */
    public @Nullable Object getOperandLiteralValue(int ordinal, RelDataType type) {
      if (!(type instanceof RelDataTypeFactoryImpl.JavaType)) {
        return null;
      }
      final Class<?> clazz = ((RelDataTypeFactoryImpl.JavaType) type).getJavaClass();
      final Object o = getOperandLiteralValue(ordinal, Object.class);
      if (o == null) {
        return null;
      }
      if (clazz.isInstance(o)) {
        return clazz.cast(o);
      }
      final Object o2 = o instanceof NlsString ? ((NlsString) o).getValue() : o;
      return EnumUtils.evaluate(o2, clazz);
    }
  
  
    @Deprecated // to be removed before 2.0
    public @Nullable Comparable getOperandLiteralValue(int ordinal) {
      return getOperandLiteralValue(ordinal, Comparable.class);
    }
  
    /**
     * Determines whether a bound operand is NULL.
     *
     * <p>This is only relevant for SQL validation.
     *
     * @param ordinal   zero-based ordinal of operand of interest
     * @param allowCast whether to regard CAST(constant) as a constant
     * @return whether operand is null; false for everything except SQL
     * validation
     */
    public boolean isOperandNull(int ordinal, boolean allowCast) {
      throw new UnsupportedOperationException();
    }
  
    /**
     * Determines whether an operand is a literal.
     *
     * @param ordinal   zero-based ordinal of operand of interest
     * @param allowCast whether to regard CAST(literal) as a literal
     * @return whether operand is literal
     */
    public boolean isOperandLiteral(int ordinal, boolean allowCast) {
      throw new UnsupportedOperationException();
    }
  
    /**
     * Returns whether an operand is a time frame.
     *
     * @param ordinal   zero-based ordinal of operand of interest
     * @return whether operand is a time frame
     */
    public boolean isOperandTimeFrame(int ordinal) {
      return getOperandCount() > 0
          && SqlTypeName.TIME_FRAME_TYPES.contains(
              getOperandType(ordinal).getSqlTypeName());
    }
  
    /** Returns the number of bound operands.
     * Includes pre-operands and regular operands. */
    public abstract int getOperandCount();
  
    /** Returns the number of pre-operands.
     * Zero except for a few aggregate functions. */
    public int getPreOperandCount() {
      return 0;
    }
  
    /**
     * Gets the type of a bound operand.
     *
     * @param ordinal zero-based ordinal of operand of interest
     * @return bound operand type
     */
    public abstract RelDataType getOperandType(int ordinal);
  
    /**
     * Gets the monotonicity of a bound operand.
     *
     * @param ordinal zero-based ordinal of operand of interest
     * @return monotonicity of operand
     */
    public SqlMonotonicity getOperandMonotonicity(int ordinal) {
      return SqlMonotonicity.NOT_MONOTONIC;
    }
  
  
    /**
     * Returns the collation type.
     */
    public RelDataType getCollationType() {
      throw new UnsupportedOperationException();
    }
  
    /**
     * Collects the types of the bound operands into a list.
     *
     * @return collected list
     */
    public List<RelDataType> collectOperandTypes() {
      return new AbstractList<RelDataType>() {
        @Override public RelDataType get(int index) {
          return getOperandType(index);
        }
  
        @Override public int size() {
          return getOperandCount();
        }
      };
    }
  
    /**
     * Returns the rowtype of the <code>ordinal</code>th operand, which is a
     * cursor.
     *
     * <p>This is only implemented for {@link SqlCallBinding}.
     *
     * @param ordinal Ordinal of the operand
     * @return Rowtype of the query underlying the cursor
     */
    public @Nullable RelDataType getCursorOperand(int ordinal) {
      throw new UnsupportedOperationException();
    }
  
    /**
     * Retrieves information about a column list parameter.
     *
     * @param ordinal    ordinal position of the column list parameter
     * @param paramName  name of the column list parameter
     * @param columnList returns a list of the column names that are referenced
     *                   in the column list parameter
     * @return the name of the parent cursor referenced by the column list
     * parameter if it is a column list parameter; otherwise, null is returned
     */
    public @Nullable String getColumnListParamInfo(
        int ordinal,
        String paramName,
        List<String> columnList) {
      throw new UnsupportedOperationException();
    }
  
    /**
     * Wraps a validation error with context appropriate to this operator call.
     *
     * @param e Validation error, not null
     * @return Error wrapped, if possible, with positional information
     */
    public abstract CalciteException newError(
        Resources.ExInst<SqlValidatorException> e);
  
    /** Returns an operator binding equivalent that is equivalent to this
     * except that a transform has been applied to each operand type. */
    public SqlOperatorBinding transform(SqlTypeTransform typeTransform) {
      final SqlOperatorBinding operatorBinding = this;
      return new SqlOperatorBinding(typeFactory, sqlOperator) {
        @Override public int getOperandCount() {
          return operatorBinding.getOperandCount();
        }
  
        @Override public RelDataType getOperandType(int ordinal) {
          return typeTransform.transformType(operatorBinding,
              operatorBinding.getOperandType(ordinal));
        }
  
        @Override public CalciteException newError(
            Resources.ExInst<SqlValidatorException> e) {
          return operatorBinding.newError(e);
        }
      };
    }
  }
  