Package org.apache.derby.impl.sql.compile

Source Code of org.apache.derby.impl.sql.compile.AlterTableNode

/*

   Derby - Class org.apache.derby.impl.sql.compile.AlterTableNode

   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.derby.impl.sql.compile;

import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.reference.Limits;

import org.apache.derby.iapi.services.io.FormatableBitSet;
import org.apache.derby.iapi.services.sanity.SanityManager;

import org.apache.derby.iapi.error.StandardException;

import org.apache.derby.iapi.sql.compile.C_NodeTypes;
import org.apache.derby.iapi.sql.compile.Visitable;
import org.apache.derby.iapi.sql.compile.Visitor;

import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
import org.apache.derby.iapi.sql.dictionary.DataDictionary;
import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
import org.apache.derby.iapi.sql.dictionary.TableDescriptor;

import org.apache.derby.iapi.sql.execute.ConstantAction;
import org.apache.derby.iapi.types.StringDataValue;

import org.apache.derby.impl.sql.execute.ColumnInfo;
import org.apache.derby.impl.sql.execute.ConstraintConstantAction;
import org.apache.derby.impl.sql.execute.CreateConstraintConstantAction;

/**
* A AlterTableNode represents a DDL statement that alters a table.
* It contains the name of the object to be created.
*
*/

public class AlterTableNode extends DDLStatementNode
{
  // The alter table action
  public  TableElementList  tableElementList = null;
  public  char        lockGranularity;

  /**
   * updateStatistics will indicate that we are here for updating the
   * statistics. It could be statistics of just one index or all the
   * indexes on a given table.
   */
  private  boolean        updateStatistics = false;
  /**
   * The flag updateStatisticsAll will tell if we are going to update the
   * statistics of all indexes or just one index on a table.
   */
  private  boolean        updateStatisticsAll = false;
  /**
   * If statistic is getting updated for just one index, then
   * indexNameForUpdateStatistics will tell the name of the specific index
   * whose statistics need to be updated.
   */
  private  String        indexNameForUpdateStatistics;
 
  public  boolean        compressTable = false;
  public  boolean        sequential = false;
  //The following three (purge, defragment and truncateEndOfTable) apply for
  //inplace compress
  public  boolean        purge = false;
  public  boolean        defragment = false;
  public  boolean        truncateEndOfTable = false;
 
  public  int          behavior;  // currently for drop column

  public  TableDescriptor    baseTable;

  protected  int            numConstraints;

  private    int        changeType = UNKNOWN_TYPE;

  private boolean             truncateTable = false;

  // constant action arguments

  protected  SchemaDescriptor      schemaDescriptor = null;
  protected  ColumnInfo[]         colInfos = null;
  protected  ConstraintConstantAction[]  conActions = null;


  /**
   * Initializer for a TRUNCATE TABLE
   *
   * @param objectName    The name of the table being truncated
   * @exception StandardException    Thrown on error
   */

  public void init(Object objectName)
    throws StandardException
  {

    //truncate table is not suppotted in this release
    //semantics are not yet clearly defined by SQL Council yet
    //truncate will be allowed only in DEBUG builds for testing purposes.
    if (SanityManager.DEBUG)
    {
      initAndCheck(objectName);
      /* For now, this init() only called for truncate table */
      truncateTable = true;
      schemaDescriptor = getSchemaDescriptor();
    }else
    {
      throw StandardException.newException(SQLState.NOT_IMPLEMENTED,
                         "truncate table");
    }
  }

  /**
   * Initializer for a AlterTableNode for updating the statistics. The user
   * can ask for update statistic of all the indexes or only a specific index
   *
   * @param objectName    The name of the table whose index(es) will have
   *                          their statistics updated.
   * @param updateStatisticsAll  If true then update the statistics of all
   *                          the indexes on the table. If false, then update
   *                          the statistics of only the index provided as
   *                          3rd parameter here
   * @param indexName      Only used if updateStatisticsAll is set to
   *                          false.
   *
   * @exception StandardException    Thrown on error
   */
  public void init(Object objectName,
      Object updateStatisticsAll,
      Object indexName)
  throws StandardException
  {
    initAndCheck(objectName);
    this.updateStatisticsAll = ((Boolean) updateStatisticsAll).booleanValue();
    this.indexNameForUpdateStatistics = (String)indexName;
    schemaDescriptor = getSchemaDescriptor();
    updateStatistics = true;
  }
 
  /**
   * Initializer for a AlterTableNode for COMPRESS using temporary tables
   * rather than inplace compress
   *
   * @param objectName    The name of the table being altered
   * @param sequential    Whether or not the COMPRESS is SEQUENTIAL
   *
   * @exception StandardException    Thrown on error
   */

  public void init(Object objectName,
           Object sequential)
    throws StandardException
  {
    initAndCheck(objectName);

    this.sequential = ((Boolean) sequential).booleanValue();
    /* For now, this init() only called for compress table */
    compressTable = true;

    schemaDescriptor = getSchemaDescriptor();
  }

  /**
   * Initializer for a AlterTableNode for INPLACE COMPRESS
   *
   * @param objectName      The name of the table being altered
   * @param purge          PURGE during INPLACE COMPRESS?
   * @param defragment      DEFRAGMENT during INPLACE COMPRESS?
   * @param truncateEndOfTable  TRUNCATE END during INPLACE COMPRESS?
   *
   * @exception StandardException    Thrown on error
   */

  public void init(Object objectName,
       Object purge,
       Object defragment,
       Object truncateEndOfTable)
    throws StandardException
  {
    initAndCheck(objectName);

    this.purge = ((Boolean) purge).booleanValue();
    this.defragment = ((Boolean) defragment).booleanValue();
    this.truncateEndOfTable = ((Boolean) truncateEndOfTable).booleanValue();
    compressTable = true;
    schemaDescriptor = getSchemaDescriptor(true, false);
  }

  /**
   * Initializer for a AlterTableNode
   *
   * @param objectName    The name of the table being altered
   * @param tableElementList  The alter table action
   * @param lockGranularity  The new lock granularity, if any
   * @param changeType    ADD_TYPE or DROP_TYPE
   * @param behavior      If drop column is CASCADE or RESTRICTED
   *
   * @exception StandardException    Thrown on error
   */

  public void init(
              Object objectName,
              Object tableElementList,
              Object lockGranularity,
              Object changeType,
              Object behavior )
    throws StandardException
  {
    initAndCheck(objectName);
    this.tableElementList = (TableElementList) tableElementList;
    this.lockGranularity = ((Character) lockGranularity).charValue();

    int[]  ct = (int[]) changeType, bh = (int[]) behavior;
    this.changeType = ct[0];
    this.behavior = bh[0];
    switch ( this.changeType )
    {
        case ADD_TYPE:
        case DROP_TYPE:
        case MODIFY_TYPE:
        case LOCKING_TYPE:

        break;

        default:

        throw StandardException.newException(SQLState.NOT_IMPLEMENTED);
    }

    schemaDescriptor = getSchemaDescriptor();
  }

  /**
   * Convert this object to a String.  See comments in QueryTreeNode.java
   * for how this should be done for tree printing.
   *
   * @return  This object as a String
   */

  public String toString()
  {
    if (SanityManager.DEBUG)
    {
      return super.toString() +
        "objectName: " + getObjectName() + "\n" +
        "lockGranularity: " + lockGranularity + "\n" +
        "compressTable: " + compressTable + "\n" +
        "sequential: " + sequential + "\n" +
        "truncateTable: " + truncateTable + "\n" +
        "purge: " + purge + "\n" +
        "defragment: " + defragment + "\n" +
        "truncateEndOfTable: " + truncateEndOfTable + "\n" +
        "updateStatistics: " + updateStatistics + "\n" +
        "updateStatisticsAll: " + updateStatisticsAll + "\n" +
        "indexNameForUpdateStatistics: " +
             indexNameForUpdateStatistics + "\n";
    }
    else
    {
      return "";
    }
  }

  /**
   * Prints the sub-nodes of this object.  See QueryTreeNode.java for
   * how tree printing is supposed to work.
   * @param depth    The depth to indent the sub-nodes
   */
  public void printSubNodes(int depth) {
    if (SanityManager.DEBUG) {
      if (tableElementList != null) {
        printLabel(depth, "tableElementList: ");
        tableElementList.treePrint(depth + 1);
      }

    }
  }

public String statementToString()
  {
    if(truncateTable)
      return "TRUNCATE TABLE";
    else
      return "ALTER TABLE";
  }

  public  int  getChangeType() { return changeType; }

  // We inherit the generate() method from DDLStatementNode.

  /**
   * Bind this AlterTableNode.  This means doing any static error
   * checking that can be done before actually creating the table.
   * For example, verifying that the user is not trying to add a
   * non-nullable column.
   *
   *
   * @exception StandardException    Thrown on error
   */
  public void bindStatement() throws StandardException
  {
    DataDictionary  dd = getDataDictionary();
    int          numCheckConstraints = 0;
    int numReferenceConstraints = 0;
        int numGenerationClauses = 0;
    int numBackingIndexes = 0;

    /*
    ** Get the table descriptor.  Checks the schema
    ** and the table.
    */
    if(compressTable && (purge || defragment || truncateEndOfTable)) {
      //We are dealing with inplace compress here and inplace compress is
      //allowed on system schemas. In order to support inplace compress
      //on user as well as system tables, we need to use special
      //getTableDescriptor(boolean) call to get TableDescriptor. This
      //getTableDescriptor(boolean) allows getting TableDescriptor for
      //system tables without throwing an exception.
      baseTable = getTableDescriptor(false);
    } else
      baseTable = getTableDescriptor();

    //throw an exception if user is attempting to alter a temporary table
    if (baseTable.getTableType() == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE)
    {
        throw StandardException.newException(SQLState.LANG_NOT_ALLOWED_FOR_DECLARED_GLOBAL_TEMP_TABLE);
    }

    /* Statement is dependent on the TableDescriptor */
    getCompilerContext().createDependency(baseTable);

    //If we are dealing with add column character type, then set that
    //column's collation type to be the collation type of the schema.
    //The collation derivation of such a column would be "implicit".
    if (changeType == ADD_TYPE) {//the action is of type add.
      if (tableElementList != null) {//check if is is add column
        for (int i=0; i<tableElementList.size();i++) {
          if (tableElementList.elementAt(i) instanceof ColumnDefinitionNode) {
            ColumnDefinitionNode cdn = (ColumnDefinitionNode) tableElementList.elementAt(i);
            //check if we are dealing with add character column
                        //
                        // For generated columns which omit an explicit
                        // datatype, we have to defer this work until we bind
                        // the generation clause
                        //

                        if ( cdn.hasGenerationClause() && ( cdn.getType() == null ) ) { continue; }
                       
            if (cdn.getType().getTypeId().isStringTypeId()) {
              //we found what we are looking for. Set the
              //collation type of this column to be the same as
              //schema descriptor's collation. Set the collation
              //derivation as implicit
              cdn.setCollationType(schemaDescriptor.getCollationType());
                }           
          }
        }
       
      }
    }
    if (tableElementList != null)
    {
      tableElementList.validate(this, dd, baseTable);

      /* Only 1012 columns allowed per table */
      if ((tableElementList.countNumberOfColumns() + baseTable.getNumberOfColumns()) > Limits.DB2_MAX_COLUMNS_IN_TABLE)
      {
        throw StandardException.newException(SQLState.LANG_TOO_MANY_COLUMNS_IN_TABLE_OR_VIEW,
          String.valueOf(tableElementList.countNumberOfColumns() + baseTable.getNumberOfColumns()),
          getRelativeName(),
          String.valueOf(Limits.DB2_MAX_COLUMNS_IN_TABLE));
      }
      /* Number of backing indexes in the alter table statment */
      numBackingIndexes = tableElementList.countConstraints(DataDictionary.PRIMARYKEY_CONSTRAINT) +
                  tableElementList.countConstraints(DataDictionary.FOREIGNKEY_CONSTRAINT) +
                  tableElementList.countConstraints(DataDictionary.UNIQUE_CONSTRAINT);
      /* Check the validity of all check constraints */
      numCheckConstraints = tableElementList.countConstraints(
                  DataDictionary.CHECK_CONSTRAINT);
           
            numReferenceConstraints = tableElementList.countConstraints(
                  DataDictionary.FOREIGNKEY_CONSTRAINT);
           
            numGenerationClauses = tableElementList.countGenerationClauses();
    }

    //If the sum of backing indexes for constraints in alter table statement and total number of indexes on the table
    //so far is more than 32767, then we need to throw an exception
    if ((numBackingIndexes + baseTable.getTotalNumberOfIndexes()) > Limits.DB2_MAX_INDEXES_ON_TABLE)
    {
      throw StandardException.newException(SQLState.LANG_TOO_MANY_INDEXES_ON_TABLE,
        String.valueOf(numBackingIndexes + baseTable.getTotalNumberOfIndexes()),
        getRelativeName(),
        String.valueOf(Limits.DB2_MAX_INDEXES_ON_TABLE));
    }

    if ( (numCheckConstraints > 0) || (numGenerationClauses > 0) || (numReferenceConstraints > 0))
    {
      /* In order to check the validity of the check constraints and
       * generation clauses
       * we must goober up a FromList containing a single table,
       * the table being alter, with an RCL containing the existing and
       * new columns and their types.  This will allow us to
       * bind the constraint definition trees against that
       * FromList.  When doing this, we verify that there are
       * no nodes which can return non-deterministic results.
       */
      FromList fromList = makeFromList( dd, tableElementList, false );
            FormatableBitSet    generatedColumns = baseTable.makeColumnMap( baseTable.getGeneratedColumns() );

      /* Now that we've finally goobered stuff up, bind and validate
       * the check constraints and generation clauses.
       */
      if  (numGenerationClauses > 0)
            { tableElementList.bindAndValidateGenerationClauses( schemaDescriptor, fromList, generatedColumns, baseTable ); }
      if  (numCheckConstraints > 0) { tableElementList.bindAndValidateCheckConstraints(fromList); }
            if ( numReferenceConstraints > 0) { tableElementList.validateForeignKeysOnGenerationClauses( fromList, generatedColumns ); }
    }

        // must be done after resolving the datatypes of the generation clauses
        if (tableElementList != null) { tableElementList.validatePrimaryKeyNullability(); }

    //Check if we are in alter table to update the statistics. If yes, then
    //check if we are here to update the statistics of a specific index. If
    //yes, then verify that the indexname provided is a valid one.
    if (updateStatistics && !updateStatisticsAll)
    {
      ConglomerateDescriptor  cd = null;
      if (schemaDescriptor.getUUID() != null)
        cd = dd.getConglomerateDescriptor(indexNameForUpdateStatistics, schemaDescriptor, false);

      if (cd == null)
      {
        throw StandardException.newException(
            SQLState.LANG_INDEX_NOT_FOUND,
            schemaDescriptor.getSchemaName() + "." + indexNameForUpdateStatistics);
      }     
    }

    /* Unlike most other DDL, we will make this ALTER TABLE statement
     * dependent on the table being altered.  In general, we try to
     * avoid this for DDL, but we are already requiring the table to
     * exist at bind time (not required for create index) and we don't
     * want the column ids to change out from under us before
     * execution.
     */
    getCompilerContext().createDependency(baseTable);
  }

  /**
   * Return true if the node references SESSION schema tables (temporary or permanent)
   *
   * @return  true if references SESSION schema tables, else false
   *
   * @exception StandardException    Thrown on error
   */
  public boolean referencesSessionSchema()
    throws StandardException
  {
    //If alter table is on a SESSION schema table, then return true.
    return isSessionSchema(baseTable.getSchemaName());
  }

  /**
   * Create the Constant information that will drive the guts of Execution.
   *
   * @exception StandardException    Thrown on failure
   */
  public ConstantAction  makeConstantAction() throws StandardException
  {
    prepConstantAction();

    return  getGenericConstantActionFactory().getAlterTableConstantAction(schemaDescriptor,
                       getRelativeName(),
                       baseTable.getUUID(),
                       baseTable.getHeapConglomerateId(),
                       TableDescriptor.BASE_TABLE_TYPE,
                       colInfos,
                       conActions,
                       lockGranularity,
                       compressTable,
                       behavior,
                             sequential,
                          truncateTable,
                          purge,
                          defragment,
                          truncateEndOfTable,
                          updateStatistics,
                          updateStatisticsAll,
                          indexNameForUpdateStatistics);
  }

  /**
    *  Generate arguments to constant action. Called by makeConstantAction() in this class and in
    *  our subclass RepAlterTableNode.
    *
    *
    * @exception StandardException    Thrown on failure
    */
  private void  prepConstantAction() throws StandardException
  {
    if (tableElementList != null)
    {
      genColumnInfo();
    }

    /* If we've seen a constraint, then build a constraint list */

    if (numConstraints > 0)
    {
      conActions = new ConstraintConstantAction[numConstraints];

      tableElementList.genConstraintActions(false, conActions, getRelativeName(), schemaDescriptor,
                          getDataDictionary());

      for (int conIndex = 0; conIndex < conActions.length; conIndex++)
      {
        ConstraintConstantAction cca = conActions[conIndex];

        if (cca instanceof CreateConstraintConstantAction)
        {
          int constraintType = cca.getConstraintType();
          if (constraintType == DataDictionary.PRIMARYKEY_CONSTRAINT)
          {
            DataDictionary dd = getDataDictionary();
            // Check to see if a constraint of the same type
            // already exists
            ConstraintDescriptorList cdl =
                                dd.getConstraintDescriptors(baseTable);

            if (cdl.getPrimaryKey() != null)
            {
              throw StandardException.newException(
                                    SQLState.LANG_ADD_PRIMARY_KEY_FAILED1,
                                    baseTable.getQualifiedName());
            }
          }
        }
      }
    }
  }
   
  /**
    *  Generate the ColumnInfo argument for the constant action. Return the number of constraints.
    */
  public  void  genColumnInfo()
        throws StandardException
  {
    // for each column, stuff system.column
    colInfos = new ColumnInfo[tableElementList.countNumberOfColumns()];

      numConstraints = tableElementList.genColumnInfos(colInfos);
  }


  /**
   * Accept the visitor for all visitable children of this node.
   *
   * @param v the visitor
   *
   * @exception StandardException on error
   */
  void acceptChildren(Visitor v)
    throws StandardException
  {
    super.acceptChildren(v);

    if (tableElementList != null)
    {
      tableElementList.accept(v);
    }
  }

  /*
   * class interface
   */
}




 
TOP

Related Classes of org.apache.derby.impl.sql.compile.AlterTableNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.