package ModSQL;
import java.sql.*;
import java.util.ArrayList;

/* $Id: LiteralRow.java,v 1.10 2003/05/29 04:58:40 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 class represents a literal row constructor.  That is, a row
 * constructor of the form '(value,...)', where each value is of type
 * Function.
 *
 * <p>Columns are added to the row constructor using the addParameter()
 * method.
 *
 * @author chris.studholme@utoronto.ca
 */
public class LiteralRow extends AbstractFunction implements RowConstructor {

  /**
   * Default constructor (no columns).
   */
  public LiteralRow() {
  }
  /**
   * Constructor to set first column.
   *
   * @param first_column Function representing first column
   * @throws SQLException if an error occurs
   */
  public LiteralRow(Function first_column) throws SQLException {
    addParameter(first_column);
  }

  /****************  setup methods  ****************/

  /**
   * Prepare the row for use.  A row constructor must consist of at least
   * one column (otherwise, an exception is thrown).  Furthermore, if any
   * of the columns are constant, they are evaluated here.
   *
   * @throws SQLException if an error occurs
   */
  public void optimize() throws SQLException {
    super.optimize();
    if (parameters.length<=0)
      throw new SQLException("LiteralRow requires at least one column");
    evaluateConstantParameters();
  }

  /**
   * Function name is blank (empty String) for row constructors.
   */
  public String functionName() {
    return "";
  }

  /**
   * Returns "column1" or "(column1,column2,...)".
   *
   * @return human-readable version of row constructor
   */
  public String toString() {
    if (parameters_array!=null) {
      if (parameters_array.size()>1)
	return super.toString();
      if (parameters_array.size()==1)
	return parameters_array.get(0).toString();
      else
	return "[EMPTY ROW]";
    }
    else {
      if (parameters.length>1)
	return super.toString();
      return parameters[0].toString();
    }
  }

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

  /**
   * <p>Returns the number of columns the row has.  The row will always have
   * at least one column.  
   *
   * <p>This method should only be called after optimize().
   *
   * @return number of columns in row
   */
  public int getColumnCount() {
    return getParameterCount();
  }

  /**
   * Return the SQL type of the value that this function expects to return.
   * This version of this method can only be used if the row has exactly
   * one column.  Otherwise, an exception is thrown.
   *
   * @return SQL type of data to be returned
   * @throws SQLException if an error occurs
   */
  public int getSQLType() throws SQLException {
    if (parameters==null)
      throw new SQLException("cannot call getSQLType before optimize");
    if (parameters.length!=1)
      throw new SQLException("row has more than one column");
    return parameters[0].getSQLType();
  }

  /**
   * Return the SQL type of the value in the specified column.
   *
   * @param column column number (starting from zero)
   * @return SQL type of data to be returned
   * @throws SQLException if an error occurs
   */
  public int getSQLType(int column) throws SQLException {
    if (parameters==null)
      throw new SQLException("cannot call getSQLType before optimize");
    return parameters[column].getSQLType();
  }

  /**
   * Return the maximum number of characters that this function expects to
   * return in a String object.  This version of this method can only be
   * used if the row has exactly one column.  Otherwise, an exception is
   * thrown.
   *
   * @return maximum size of String returned or -1 if unknown
   * @throws SQLException if an error occurs
   */
  public int getMaxResultSize() throws SQLException {
    if (parameters==null)
      throw new SQLException("cannot call getMaxResultSize before optimize");
    if (parameters.length!=1)
      throw new SQLException("row has more than one column");
    return parameters[0].getMaxResultSize();
  }

  /**
   * Return the maximum number of characters String values in the specified
   * column will have.  If the column is not of String type or if the maximum
   * length is not known, -1 should be returned.
   *
   * @param column column number (starting from zero)
   * @return maximum size of String returned or -1 if unknown
   * @throws SQLException if an error occurs
   */
  public int getMaxResultSize(int column) throws SQLException {
    if (parameters==null)
      throw new SQLException("cannot call getMaxResultSize before optimize");
    return parameters[column].getMaxResultSize();
  }


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

  /**
   * Evaluate row.  This version of this method can only be used if the row
   * has exactly one column.  Otherwise, an exception is thrown.
   *
   * @param aggregate true to return final aggregate value
   * @return result object
   * @throws SQLException if an error occurs
   * @throws EndOfTable if thrown by a column
   */
  public Object evaluate(boolean aggregate) throws SQLException, EndOfTable {
    if (parameters.length!=1)
      throw new SQLException("column number not specified");
    if (!parameter_constant[0])
      parameter_value[0] = parameters[0].evaluate(aggregate);
    return parameter_value[0];
  }

  /**
   * Evaluate row.  This version of this method can only be used if the row
   * has exactly one column.  Otherwise, an exception is thrown.
   *
   * @param match_op how desired value is matched
   * @param match_value value to match to
   * @return result object
   * @throws SQLException if an error occurs
   * @throws EndOfTable if thrown by a column
   */
  public Object evaluate(int match_op, Object match_value)
    throws SQLException, EndOfTable {
    if (parameters.length!=1)
      throw new SQLException("column number not specified");
    if (!parameter_constant[0])
      parameter_value[0] = parameters[0].evaluate(match_op,match_value);
    return parameter_value[0];
  }


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

  /**
   * Evaluate each column of the row and return the results as an array
   * of length equal to the value returned by getColumnCount().  
   *
   * @return array of objects
   * @throws SQLException if an error occurs
   * @throws EndOfTable if thrown by a column
   */
  public Object[] evaluateRow(boolean aggregate)
    throws SQLException, EndOfTable {
    evaluateParameters(aggregate);
    return parameter_value;
  }

};
