package ModSQL;
import java.sql.*;

/* $Id: Function.java,v 1.9 2003/09/24 19:59:34 cvs Exp $
 *
 * Copyright (c) 2003 Chris Studholme <chris.studholme@utoronto.ca>
 *
 * May be copied or modified under the terms of the GNU General Public
 * License.  See COPYING for more information.
 */

/**
 * <p>This interface is at the root of all single-valued SQL expressions
 * (including row constructors).  The interface provides methods for
 * manipulating function and operator parameters, and for evaluating 
 * the function/operator/variable/literal and obtaining a specific value.
 *
 * <p>Many of the method specified by this interface may only be used either
 * before optimize() has been called, or after.  This documentation for
 * these methods will specify if this is case.
 *
 * @author chris.studholme@utoronto.ca
 */
public interface Function {

  /** Match operator (begins with). */
  public static final int MATCH_BEGINS = 0;
  /** Match operator (equal). */
  public static final int MATCH_EQU = 1;
  /** Match operator (greater than). */
  public static final int MATCH_GT  = 2;
  /** Match operator (greater or equal). */
  public static final int MATCH_GTE = 3;
  /** Match operator (less than). */
  public static final int MATCH_LT  = 4;
  /** Match operator (less or equal). */
  public static final int MATCH_LTE = 5;
  /** Match operator (not equal). */
  public static final int MATCH_NE  = 6;


  /****************  parameter handling methods  ****************/

  /**
   * <p>Get the number of parameters currently supplied to this function.  If
   * the function does not support/require parameters, this method should
   * return 0.
   *
   * @return number of parameters
   */
  public int getParameterCount();
  
  /**
   * <p>Get a particular parameter.  If the function does not support/require
   * parameters, this method should throw an IndexOutOfBoundsException
   * regardless of the index supplied.
   *
   * @param index index of parameter to get
   * @return parameter (function)
   * @throws IndexOutOfBoundsException if the index if out of range
   */
  public Function getParameter(int index);

  /**
   * <p>Adds a value (function) to the list of parameters required by this
   * function.  If the function does not support/require parameters, an
   * SQLException should be thrown.
   *
   * <p>This method can only be used before optimize() has been called.
   *
   * @param item function to add
   * @throws SQLException if the parameter is inappropriate in some way
   */
  public void addParameter(Function item) throws SQLException;

  /**
   * <p>Specify the order in which the parameters should be evaluated.  
   * ModSQL will determine the optimal order in which parameters should be 
   * evaluated and use this function to indicate this order.  The order
   * argument will be a number between 0 and num_parameters-1, and be a
   * permutation of those numbers.  The function is free to ignore this
   * suggested ordering, but it should attempt to follow the ordering for
   * optimal efficiency.  If the function does not support/require 
   * parameters, an IndexOutOfBoundsException should be thrown regardless
   * of the index.  
   *
   * <p>This method can only be used before optimize() has been called.
   *
   * @param index index of parameter
   * @param order number indicating the order in which the parameter should be evaluated
   * @throws IndexOutOfBoundsException if the index if out of range
   * @throws SQLException if optimize has already been called
   */
  public void evaluateOrder(int index, int order) throws SQLException;

  /**
   * <p>Some functions (most notably IndirectValue) need to register themselves
   * before optimize() can be called.  This method must call the registerWith()
   * method on all Function objects contained within (including, but not
   * limited to, all parameters).  Most implementations will simply pass this
   * call on to all contained parameters.
   *
   * <p>This method can only be used before optimize() has been called.
   *
   * @param o object to register with
   * @throws SQLException if an error occurs
   */
  public void registerWith(Object o) throws SQLException;

  /**
   * <p>Prepare the function for use.  This method must call optimize() for
   * each parameter or other contained Function and then prepare itself for
   * use.  
   *
   * <p>After this method has been called, the number and types of parameters
   * will not change.  If the number or type of parameters is incorrect, an
   * SQLException should be thrown.
   *
   * <p>This method may only be called once per object instance.
   *
   * @throws SQLException if an error occurs
   */
  public void optimize() throws SQLException;


  /****************  result meta-data  ****************/

  /**
   * <p>Determine if this function returns a constant value.  If all of the
   * functions parameters are constant, then the function is considered
   * constant as well.
   *
   * <p>This method can only be used after optimize() has been called.
   *
   * @return true if the value returned is constant
   * @throws SQLException if an error occurs
   */
  public boolean isConstant() throws SQLException;

  /**
   * <p>Determine if this function will return a value that is an aggregate of
   * many database rows.  If the function does not aggregate data itself, 
   * it is still considered an aggregate function if all of its parameters
   * are either aggregate or constant.  Columns that appear in the GROUP BY
   * clause will be marked as aggregate.  
   *
   * <p>This method is expected to throw an exception if it aggregates data but
   * contains parameters that also aggregate data, or if it does not aggregate
   * data but contains both aggregate parameters and non-aggregate, 
   * non-constant parameters.
   *
   * <p>This method can only be used after optimize() has been called.
   *
   * @return true if the function aggregates several rows of data
   * @throws SQLException if an error occurs
   */
  public boolean isAggregate() throws SQLException;

  /**
   * <p>Return the SQL type of the value that this function expects to return.
   * The data returned by the function must either be of this type, or null.
   *
   * <p>This method can only be used after optimize() has been called.
   *
   * @return SQL type of data to be returned
   * @throws SQLException if an error occurs
   */
  public int getSQLType() throws SQLException;

  /**
   * <p>Return the maximum number of characters that this function expects to
   * return in a String object.  If the function does not expect to return
   * a String object or if it cannot guess a maximum value, -1 should be
   * returned.
   *
   * <p>This method can only be used after optimize() has been called.
   *
   * @return maximum size of String returned or -1 if unknown
   * @throws SQLException if an error occurs
   */
  public int getMaxResultSize() throws SQLException;


  /****************  evaluation methods  ****************/

  /**
   * <p>In the case of aggregate functions, this method resets the state of
   * the function to the state it was in before the first call to evaluate().
   *
   * <p>This method is expected to call reset() for all of the function's
   * parameters and other contained Function objects.
   *
   * <p>This method can only be used after optimize() has been called.  The
   * function should be in a reset state immediately after optimize() has
   * been called.
   *
   * @throws SQLException if an error occurs
   */
  public void reset() throws SQLException;

  /**
   * <p>Evaluate parameters and compute the function.  The parameters should be
   * evaluated in the order indicated with evaluateOrder() for optimal query
   * efficiency.
   *
   * <p>If the function is an aggregate, this method may return null to
   * indicate that the aggregate is not yet available.  The method will be
   * called later with the aggregate parameter set to true to indicate that
   * the final aggregate value is required.  If the function is non-constant
   * and non-aggregate, it may throw an exception if the aggregate parameter
   * is true.  Functions that read data from the database should not advance
   * to a new row if aggregate is true.
   *
   * <p>This method can only be used after optimize() has been called.
   *
   * @param aggregate true to return final aggregate value
   * @return result object
   * @throws SQLException if an error occurs
   * @throws EndOfTable if a database was advanced beyond the end of the table
   */
  public Object evaluate(boolean aggregate) throws SQLException, EndOfTable;

  /**
   * <p>Same as evaluate(), except that a specific result is desired.  If
   * the desired result can only be obtained when a particular parameter
   * evaluates to a particular value, the evaulate() method for that parameter
   * should be passed that particular value in the hopes that it will be
   * returned.  Otherwise, if knowledge of a desired result does not 
   * sufficiently constrain the parameters, this method can simply call the
   * evaluate() method above and return what it returns.
   *
   * <p>This method is in no way obligated to return a value satisfying the
   * constraint.  If the constraint can be satisified, every effort should
   * me made to satisfy it; however, if during the calculation it becomes
   * obvious that the constraint cannot be satisfied, any non-satisfying
   * value may be returned (even if it's an incorrect evaluation).
   *
   * <p>The match_operator parameter will be one of the MATCH_* constants.  
   * The match condition can be considered a relation of the form:
   * <code>desired_value match_operator match_value</code>.  For example, 
   * <code>desired_value MATCH_LT match_value</code> implies 
   * <code>desired_value &lt; match_value</code>.  
   *
   * <p>If match_value is null or a Boolean object, match_operator must be
   * either MATCH_EQU or MATCH_NE.  If match_value is non-null, it should
   * be assumed that a non-null value is sought, except in the case where 
   * match_operator is MATCH_NE and match_value is a Boolean object.  In this
   * case, a value of either the null or !match_value is sought.
   *
   * <p>The type of the match_value object need not exactly match the return
   * type of the function, but it must be a compatible type.
   *
   * <p>This method can only be used after optimize() has been called.
   *
   * @param match_operator how desired value is matched
   * @param match_value value to match to
   * @return result object
   * @throws SQLException if an error occurs
   * @throws EndOfTable if a database was advanced beyond the end of the table
   */
  public Object evaluate(int match_operator, Object match_value)
    throws SQLException, EndOfTable;
  
};
