gt:                 return false; // LIMIT PARTITION ROWS depends on no columns
context: /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * Redistributions of source code must retain the above copyright notice, this
   * list of conditions and the following disclaimer.
   *
   * Redistributions in binary form must reproduce the above copyright notice,
   * this list of conditions and the following disclaimer in the documentation
   * and/or other materials provided with the distribution.
   *
   * Neither the name of the Hypersonic SQL Group nor the names of its
   * contributors may be used to endorse or promote products derived from this
   * software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * This software consists of voluntary contributions made by many individuals
   * on behalf of the Hypersonic SQL Group.
   *
   *
   * For work added by the HSQL Development Group:
   *
   * Copyright (c) 2001-2009, The HSQL Development Group
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * Redistributions of source code must retain the above copyright notice, this
   * list of conditions and the following disclaimer.
   *
   * Redistributions in binary form must reproduce the above copyright notice,
   * this list of conditions and the following disclaimer in the documentation
   * and/or other materials provided with the distribution.
   *
   * Neither the name of the HSQL Development Group nor the names of its
   * contributors may be used to endorse or promote products derived from this
   * software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  
  package org.hsqldb_voltpatches;
  
  import org.hsqldb_voltpatches.HsqlNameManager.HsqlName;
  import org.hsqldb_voltpatches.RangeVariable.RangeIteratorBase;
  import org.hsqldb_voltpatches.index.Index;
  import org.hsqldb_voltpatches.lib.ArrayUtil;
  import org.hsqldb_voltpatches.lib.OrderedHashSet;
  import org.hsqldb_voltpatches.navigator.RowIterator;
  import org.hsqldb_voltpatches.persist.PersistentStore;
  import org.hsqldb_voltpatches.result.Result;
  import org.hsqldb_voltpatches.rights.Grantee;
  
  // fredt@users 20020225 - patch 1.7.0 by boucherb@users - named constraints
  // fredt@users 20020320 - doc 1.7.0 - update
  // tony_lai@users 20020820 - patch 595156 - violation of Integrity constraint name
  
  /**
   * Implementation of a table constraint with references to the indexes used
   * by the constraint.<p>
   *
   * Partly based on Hypersonic code.
   *
   * @author Thomas Mueller (Hypersonic SQL Group)
   * @author Fred Toussi (fredt@users dot sourceforge.net)
   * @version 1.9.0
   * @since Hypersonic SQL
   */
  public final class Constraint implements SchemaObject {
  
      /*
       SQL CLI codes
  
       Referential Constraint 0 CASCADE
       Referential Constraint 1 RESTRICT
       Referential Constraint 2 SET NULL
       Referential Constraint 3 NO ACTION
       Referential Constraint 4 SET DEFAULT
       */
      public static final int CASCADE        = 0,
                              RESTRICT       = 1,
                              SET_NULL       = 2,
                              NO_ACTION      = 3,
                              SET_DEFAULT    = 4,
                              INIT_DEFERRED  = 5,
                              INIT_IMMEDIATE = 6,
                              NOT_DEFERRABLE = 7;
      public static final int FOREIGN_KEY    = 0,
                              MAIN           = 1,
                              UNIQUE         = 2,
                              CHECK          = 3,
                              PRIMARY_KEY    = 4,
                              TEMP           = 5,
      // A VoltDB extension to support LIMIT PARTITION ROWS syntax
                              LIMIT          = 6;
      // End of VoltDB extension
      ConstraintCore          core;
      private HsqlName        name;
      int                     constType;
      boolean                 isForward;
  
      //
      Expression      check;
      String          checkStatement;
      private boolean isNotNull;
      int             notNullColumnIndex;
      RangeVariable   rangeVariable;
      OrderedHashSet  schemaObjectNames;
  
      // for temp constraints only
      OrderedHashSet mainColSet;
      OrderedHashSet refColSet;
  
      //
      final public static Constraint[] emptyArray = new Constraint[]{};
  
      /**
       *  Constructor declaration for PK and UNIQUE
       */
      public Constraint(HsqlName name, Table t, Index index, int type) {
  
          core           = new ConstraintCore();
          this.name      = name;
          constType      = type;
          core.mainTable = t;
          core.mainIndex = index;
          core.mainCols  = index.getColumns();
      }
  
      /**
       *  Constructor for main constraints (foreign key references in PK table)
       */
      public Constraint(HsqlName name, Constraint fkconstraint) {
  
          this.name = name;
          constType = MAIN;
          core      = fkconstraint.core;
      }
  
      Constraint duplicate() {
  
          Constraint copy = new Constraint();
  
          copy.core      = core.duplicate();
          copy.name      = name;
          copy.constType = constType;
          copy.isForward = isForward;
  
          //
          copy.check              = check;
          copy.isNotNull          = isNotNull;
          copy.notNullColumnIndex = notNullColumnIndex;
          copy.rangeVariable      = rangeVariable;
          copy.schemaObjectNames  = schemaObjectNames;
          // A VoltDB extension to support the assume unique attribute
          copy.assumeUnique       = assumeUnique;
          // End of VoltDB extension
          // A VoltDB extension to support LIMIT PARTITION ROWS syntax
          copy.rowsLimit          = rowsLimit;
          copy.rowsLimitDeleteStmt = rowsLimitDeleteStmt;
          // End of VoltDB extension
          // A VoltDB extension to support indexed expressions
          copy.indexExprs         = indexExprs;
          // End of VoltDB extension
  
          return copy;
      }
  
      /**
       * General constructor for foreign key constraints.
       *
       * @param name name of constraint
       * @param refCols list of referencing columns
       * @param mainTableName referenced table
       * @param mainCols list of referenced columns
       * @param type constraint type
       * @param deleteAction triggered action on delete
       * @param updateAction triggered action on update
       *
       */
      public Constraint(HsqlName name, HsqlName refTableName,
                        OrderedHashSet refCols, HsqlName mainTableName,
                        OrderedHashSet mainCols, int type, int deleteAction,
                        int updateAction, int matchType) {
  
          core               = new ConstraintCore();
          this.name          = name;
          constType          = type;
          mainColSet         = mainCols;
          core.refTableName  = refTableName;
          core.mainTableName = mainTableName;
          refColSet          = refCols;
          core.deleteAction  = deleteAction;
          core.updateAction  = updateAction;
          core.matchType     = matchType;
      }
  
      public Constraint(HsqlName name, OrderedHashSet mainCols, int type) {
  
          core       = new ConstraintCore();
          this.name  = name;
          constType  = type;
          mainColSet = mainCols;
      }
  
      void setColumnsIndexes(Table table) {
  
          if (constType == Constraint.FOREIGN_KEY) {
              if (mainColSet == null) {
                  core.mainCols = core.mainTable.getPrimaryKey();
  
                  if (core.mainCols == null) {
                      throw Error.error(ErrorCode.X_42581);
                  }
              } else if (core.mainCols == null) {
                  core.mainCols = core.mainTable.getColumnIndexes(mainColSet);
              }
  
              if (core.refCols == null) {
                  core.refCols = table.getColumnIndexes(refColSet);
              }
          } else if (mainColSet != null) {
              core.mainCols = table.getColumnIndexes(mainColSet);
          }
      }
  
      private Constraint() {}
  
      public int getType() {
          return SchemaObject.CONSTRAINT;
      }
  
      /**
       * Returns the HsqlName.
       */
      public HsqlName getName() {
          return name;
      }
  
      public HsqlName getCatalogName() {
          return name.schema.schema;
      }
  
      public HsqlName getSchemaName() {
          return name.schema;
      }
  
      public Grantee getOwner() {
          return name.schema.owner;
      }
  
      public OrderedHashSet getReferences() {
  
          switch (constType) {
  
              case Constraint.CHECK :
                  return schemaObjectNames;
  
              case Constraint.FOREIGN_KEY :
                  OrderedHashSet set = new OrderedHashSet();
  
                  set.add(core.uniqueName);
  
                  return set;
          }
  
          return null;
      }
  
      public OrderedHashSet getComponents() {
          return null;
      }
  
      public void compile(Session session) {}
  
      public String getSQL() {
  
          StringBuffer sb = new StringBuffer();
  
          switch (getConstraintType()) {
  
              case Constraint.PRIMARY_KEY :
                  if (getMainColumns().length > 1
                          || (getMainColumns().length == 1
                              && !getName().isReservedName())) {
                      if (!getName().isReservedName()) {
                          sb.append(Tokens.T_CONSTRAINT).append(' ');
                          sb.append(getName().statementName).append(' ');
                      }
  
                      sb.append(Tokens.T_PRIMARY).append(' ').append(
                          Tokens.T_KEY);
                      getColumnList(getMain(), getMainColumns(),
                                    getMainColumns().length, sb);
                  }
                  break;
  
              case Constraint.UNIQUE :
                  if (!getName().isReservedName()) {
                      sb.append(Tokens.T_CONSTRAINT).append(' ');
                      sb.append(getName().statementName);
                      sb.append(' ');
                  }
  
                  sb.append(Tokens.T_UNIQUE);
  
                  // A VoltDB extension to support indexed expressions
                  if (indexExprs != null) {
                      return getExprList(sb);
                  }
                  // End of VoltDB extension
                  int[] col = getMainColumns();
  
                  getColumnList(getMain(), col, col.length, sb);
                  break;
  
              case Constraint.FOREIGN_KEY :
                  if (isForward) {
                      sb.append(Tokens.T_ALTER).append(' ').append(
                          Tokens.T_TABLE).append(' ');
                      sb.append(
                          getRef().getName().getSchemaQualifiedStatementName());
                      sb.append(' ').append(Tokens.T_ADD).append(' ');
                      getFKStatement(sb);
                  } else {
                      getFKStatement(sb);
                  }
                  break;
  
              case Constraint.CHECK :
                  if (isNotNull()) {
                      break;
                  }
  
                  if (!getName().isReservedName()) {
                      sb.append(Tokens.T_CONSTRAINT).append(' ');
                      sb.append(getName().statementName).append(' ');
                  }
  
                  sb.append(Tokens.T_CHECK).append('(');
                  sb.append(check.getSQL());
                  sb.append(')');
  
                  // should not throw as it is already tested OK
                  break;
          }
  
          return sb.toString();
      }
  
      /**
       * Generates the foreign key declaration for a given Constraint object.
       */
      private void getFKStatement(StringBuffer a) {
  
          if (!getName().isReservedName()) {
              a.append(Tokens.T_CONSTRAINT).append(' ');
              a.append(getName().statementName);
              a.append(' ');
          }
  
          a.append(Tokens.T_FOREIGN).append(' ').append(Tokens.T_KEY);
  
          int[] col = getRefColumns();
  
          getColumnList(getRef(), col, col.length, a);
          a.append(' ').append(Tokens.T_REFERENCES).append(' ');
          a.append(getMain().getName().getSchemaQualifiedStatementName());
  
          col = getMainColumns();
  
          getColumnList(getMain(), col, col.length, a);
  
          if (getDeleteAction() != Constraint.NO_ACTION) {
              a.append(' ').append(Tokens.T_ON).append(' ').append(
                  Tokens.T_DELETE).append(' ');
              a.append(getDeleteActionString());
          }
  
          if (getUpdateAction() != Constraint.NO_ACTION) {
              a.append(' ').append(Tokens.T_ON).append(' ').append(
                  Tokens.T_UPDATE).append(' ');
              a.append(getUpdateActionString());
          }
      }
  
      /**
       * Generates the column definitions for a table.
       */
      private static void getColumnList(Table t, int[] col, int len,
                                        StringBuffer a) {
  
          a.append('(');
  
          for (int i = 0; i < len; i++) {
              a.append(t.getColumn(col[i]).getName().statementName);
  
              if (i < len - 1) {
                  a.append(',');
              }
          }
  
          a.append(')');
      }
  
      public HsqlName getMainTableName() {
          return core.mainTableName;
      }
  
      public HsqlName getMainName() {
          return core.mainName;
      }
  
      public HsqlName getRefName() {
          return core.refName;
      }
  
      public HsqlName getUniqueName() {
          return core.uniqueName;
      }
  
      /**
       *  Returns the type of constraint
       */
      public int getConstraintType() {
          return constType;
      }
  
      /**
       *  Returns the main table
       */
      public Table getMain() {
          return core.mainTable;
      }
  
      /**
       *  Returns the main index
       */
      Index getMainIndex() {
          return core.mainIndex;
      }
  
      /**
       *  Returns the reference table
       */
      public Table getRef() {
          return core.refTable;
      }
  
      /**
       *  Returns the reference index
       */
      Index getRefIndex() {
          return core.refIndex;
      }
  
      /**
       * Returns the foreign key action rule.
       */
      private static String getActionString(int action) {
  
          switch (action) {
  
              case Constraint.RESTRICT :
                  return Tokens.T_RESTRICT;
  
              case Constraint.CASCADE :
                  return Tokens.T_CASCADE;
  
              case Constraint.SET_DEFAULT :
                  return Tokens.T_SET + ' ' + Tokens.T_DEFAULT;
  
              case Constraint.SET_NULL :
                  return Tokens.T_SET + ' ' + Tokens.T_NULL;
  
              default :
                  return Tokens.T_NO + ' ' + Tokens.T_ACTION;
          }
      }
  
      /**
       *  The ON DELETE triggered action of (foreign key) constraint
       */
      public int getDeleteAction() {
          return core.deleteAction;
      }
  
      public String getDeleteActionString() {
          return getActionString(core.deleteAction);
      }
  
      /**
       *  The ON UPDATE triggered action of (foreign key) constraint
       */
      public int getUpdateAction() {
          return core.updateAction;
      }
  
      public String getUpdateActionString() {
          return getActionString(core.updateAction);
      }
  
      public boolean hasTriggeredAction() {
  
          if (constType == Constraint.FOREIGN_KEY) {
              switch (core.deleteAction) {
  
                  case Constraint.CASCADE :
                  case Constraint.SET_DEFAULT :
                  case Constraint.SET_NULL :
                      return true;
              }
  
              switch (core.updateAction) {
  
                  case Constraint.CASCADE :
                  case Constraint.SET_DEFAULT :
                  case Constraint.SET_NULL :
                      return true;
              }
          }
  
          return false;
      }
  
      public int getDeferability() {
          return NOT_DEFERRABLE;
      }
  
      /**
       *  Returns the main table column index array
       */
      public int[] getMainColumns() {
          return core.mainCols;
      }
  
      /**
       *  Returns the reference table column index array
       */
      public int[] getRefColumns() {
          return core.refCols;
      }
  
      /**
       * Returns the SQL for the expression in CHECK clause
       */
      public String getCheckSQL() {
          return check.getSQL();
      }
  
      /**
       * Returns true if the expression in CHECK is a simple IS NOT NULL
       */
      public boolean isNotNull() {
          return isNotNull;
      }
  
      boolean hasColumnOnly(int colIndex) {
  
          switch (constType) {
  
              case CHECK :
                  return rangeVariable.usedColumns[colIndex] && ArrayUtil
                      .countTrueElements(rangeVariable.usedColumns) == 1;
  
              case PRIMARY_KEY :
              case UNIQUE :
                  return core.mainCols.length == 1
                         && core.mainCols[0] == colIndex;
  
              case MAIN :
                  return core.mainCols.length == 1
                         && core.mainCols[0] == colIndex
                         && core.mainTable == core.refTable;
  
              case FOREIGN_KEY :
                  return core.refCols.length == 1 && core.refCols[0] == colIndex
                         && core.mainTable == core.refTable;
              // A VoltDB extension to support LIMIT PARTITION ROWS syntax
              case LIMIT :
                  return false; // LIMIT PARTITION ROWS depends on no columns
              // End of VoltDB extension
              default :
                  throw Error.runtimeError(ErrorCode.U_S0500, "Constraint");
          }
      }
  
      boolean hasColumnPlus(int colIndex) {
  
          switch (constType) {
  
              case CHECK :
                  return rangeVariable.usedColumns[colIndex] && ArrayUtil
                      .countTrueElements(rangeVariable.usedColumns) > 1;
  
              case PRIMARY_KEY :
              case UNIQUE :
                  return core.mainCols.length != 1
                         && ArrayUtil.find(core.mainCols, colIndex) != -1;
  
              case MAIN :
                  return ArrayUtil.find(core.mainCols, colIndex) != -1
                         && (core.mainCols.length != 1
                             || core.mainTable != core.refTable);
  
              case FOREIGN_KEY :
                  return ArrayUtil.find(core.refCols, colIndex) != -1
                         && (core.mainCols.length != 1
                             || core.mainTable == core.refTable);
  
              // A VoltDB extension to support LIMIT PARTITION ROWS syntax
              case LIMIT :
  