Package org.apache.derby.impl.sql.execute

Source Code of org.apache.derby.impl.sql.execute.ConstraintConstantAction

/*

   Derby - Class org.apache.derby.impl.sql.execute.ConstraintConstantAction

   Copyright 1998, 2004 The Apache Software Foundation or its licensors, as applicable.

   Licensed 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.execute;

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

import org.apache.derby.catalog.UUID;
import org.apache.derby.iapi.services.uuid.UUIDFactory;

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

import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;

import org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor;
import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
import org.apache.derby.iapi.sql.dictionary.DataDictionary;
import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
import org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor;
import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
import org.apache.derby.iapi.sql.dictionary.TableDescriptor;

import org.apache.derby.iapi.types.DataValueFactory;

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

import org.apache.derby.iapi.sql.execute.ConstantAction;
import org.apache.derby.iapi.sql.execute.ExecRow;

import org.apache.derby.iapi.sql.ResultSet;
import org.apache.derby.iapi.sql.Statement;
import org.apache.derby.iapi.sql.PreparedStatement;

import org.apache.derby.iapi.types.NumberDataValue;

import org.apache.derby.iapi.store.access.ConglomerateController;
import org.apache.derby.iapi.store.access.GroupFetchScanController;
import org.apache.derby.iapi.store.access.ScanController;
import org.apache.derby.iapi.store.access.TransactionController;

import org.apache.derby.iapi.types.DataValueDescriptor;

import org.apache.derby.catalog.UUID;

import org.apache.derby.iapi.services.io.FormatableBitSet;
/**
*  This class  describes actions that are ALWAYS performed for a
*  constraint creation at Execution time.
*
@version 0.1
@author Jerry Brenner
*/

public abstract class ConstraintConstantAction extends DDLSingleTableConstantAction
{

  protected  String      constraintName;
  protected  int        constraintType;
  protected  String      tableName;
  protected  String      schemaName;
  protected  UUID      schemaId;
  protected  IndexConstantAction indexAction;

  // CONSTRUCTORS
  /**
   *  Make one of these puppies.
   *
   *  @param constraintName  Constraint name.
   *  @param constraintType  Constraint type.
   *  @param tableName    Table name.
   *  @param tableId      UUID of table.
   *  @param schemaName    schema that table and constraint lives in.
   *  @param tdSd        the schema that table lives in.
   *  @param indexAction    IndexConstantAction for constraint (if necessary)
   *  RESOLVE - the next parameter should go away once we use UUIDs
   *        (Generated constraint names will be based off of uuids)
   */
  ConstraintConstantAction(
                   String  constraintName,
             int    constraintType,
                   String  tableName,
             UUID    tableId,
             String  schemaName,
             IndexConstantAction indexAction)
  {
    super(tableId);
    this.constraintName = constraintName;
    this.constraintType = constraintType;
    this.tableName = tableName;
    this.indexAction = indexAction;
    this.schemaName = schemaName;

    if (SanityManager.DEBUG)
    {
      SanityManager.ASSERT(schemaName != null, "Constraint schema name is null");
    }
  }

  // Class implementation

  /**
   * Get the constraint type.
   *
   * @return The constraint type
   */
  public  int getConstraintType()
  {
    return constraintType;
  }

  /**
    *  Get the constraint name
    *
    *  @return  the constraint name
    */
    public  String  getConstraintName() { return constraintName; }

  /**
    *  Get the associated index constant action.
    *
    *  @return  the constant action for the backing index
    */
    public  IndexConstantAction  getIndexAction() { return indexAction; }

  /**
   * Make sure that the foreign key constraint is valid
   * with the existing data in the target table.  Open
   * the table, if there aren't any rows, ok.  If there
   * are rows, open a scan on the referenced key with
   * table locking at level 2.  Pass in the scans to
   * the BulkRIChecker.  If any rows fail, barf.
   *
   * @param  tc    transaction controller
   * @param  dd    data dictionary
   * @param  fk    foreign key constraint
   * @param  refcd  referenced key
   * @param   indexTemplateRow  index template row
   *
   * @exception StandardException on error
   */
  static void validateFKConstraint
  (
    TransactionController        tc,
    DataDictionary            dd,
    ForeignKeyConstraintDescriptor    fk,
    ReferencedKeyConstraintDescriptor  refcd,
    ExecRow               indexTemplateRow
  )
    throws StandardException
  {

    GroupFetchScanController refScan = null;

    GroupFetchScanController fkScan =
            tc.openGroupFetchScan(
                fk.getIndexConglomerateDescriptor(dd).getConglomerateNumber(),
                false,                             // hold
                0,                     // read only
                tc.MODE_TABLE,              // already locked
                tc.ISOLATION_READ_COMMITTED,      // whatever
                (FormatableBitSet)null,               // retrieve all fields
                (DataValueDescriptor[])null,          // startKeyValue
                ScanController.GE,                  // startSearchOp
                null,                               // qualifier
                (DataValueDescriptor[])null,        // stopKeyValue
                ScanController.GT                   // stopSearchOp
                );

    try
    {
      /*
      ** If we have no rows, then we are ok.  This will
      ** catch the CREATE TABLE T (x int references P) case
      ** (as well as an ALTER TABLE ADD CONSTRAINT where there
      ** are no rows in the target table).
      */ 
      if (!fkScan.next())
      {
        fkScan.close();
        return;
      }

      fkScan.reopenScan(
          (DataValueDescriptor[])null,        // startKeyValue
          ScanController.GE,                  // startSearchOp
          null,                               // qualifier
          (DataValueDescriptor[])null,        // stopKeyValue
          ScanController.GT                   // stopSearchOp
          );

      /*
      ** Make sure each row in the new fk has a matching
      ** referenced key.  No need to get any special locking
      ** on the referenced table because it cannot delete
      ** any keys we match because it will block on the table
      ** lock on the fk table (we have an ex tab lock on
      ** the target table of this ALTER TABLE command).
      ** Note that we are doing row locking on the referenced
      ** table.  We could speed things up and get table locking
      ** because we are likely to be hitting a lot of rows
      ** in the referenced table, but we are going to err
      ** on the side of concurrency here.
      */
      refScan =
                tc.openGroupFetchScan(
          refcd.getIndexConglomerateDescriptor(dd).getConglomerateNumber(),
                        false,                         // hold
                        0,                 // read only
                        tc.MODE_RECORD,
                        tc.ISOLATION_READ_COMMITTED,  // read committed is good enough
                        (FormatableBitSet)null,           // retrieve all fields
                        (DataValueDescriptor[])null,    // startKeyValue
                        ScanController.GE,              // startSearchOp
                        null,                           // qualifier
                        (DataValueDescriptor[])null,    // stopKeyValue
                        ScanController.GT               // stopSearchOp
                        );

      RIBulkChecker riChecker = new RIBulkChecker(refScan,
                    fkScan,
                    indexTemplateRow,  
                    true,         // fail on 1st failure
                    (ConglomerateController)null,
                    (ExecRow)null);

      int numFailures = riChecker.doCheck();
      if (numFailures > 0)
      {
        StandardException se = StandardException.newException(SQLState.LANG_ADD_FK_CONSTRAINT_VIOLATION,
                  fk.getConstraintName(),
                  fk.getTableDescriptor().getName());
        throw se;
      }
    }
    finally
    {
      if (fkScan != null)
      {
        fkScan.close();
        fkScan = null;
      }
      if (refScan != null)
      {
        refScan.close();
        refScan = null;
      }
    }
  }

  /**
   * Evaluate a check constraint or not null column constraint. 
   * Generate a query of the
   * form SELECT COUNT(*) FROM t where NOT(<check constraint>)
   * and run it by compiling and executing it.   Will
   * work ok if the table is empty and query returns null.
   *
   * @param constraintName  constraint name
   * @param constraintText  constraint text
   * @param td        referenced table
   * @param lcc        the language connection context
   * @param isCheckConstraint  the constraint is a check constraint
     *
   * @return true if null constraint passes, false otherwise
   *
   * @exception StandardException if check constraint fails
   */
   static boolean validateConstraint
  (
    String              constraintName,
    String              constraintText,
    TableDescriptor          td,
    LanguageConnectionContext    lcc,
    boolean              isCheckConstraint
  )
    throws StandardException
  {
    StringBuffer checkStmt = new StringBuffer();
    /* should not use select sum(not(<check-predicate>) ? 1: 0) because
     * that would generate much more complicated code and may exceed Java
     * limits if we have a large number of check constraints, beetle 4347
     */
    checkStmt.append("SELECT COUNT(*) FROM ");
    checkStmt.append(td.getQualifiedName());
    checkStmt.append(" WHERE NOT(");
    checkStmt.append(constraintText);
    checkStmt.append(")");
 
    ResultSet rs = null;
    try
    {
      PreparedStatement ps = lcc.prepareInternalStatement(td.getSchemaDescriptor(), checkStmt.toString());

      rs = ps.execute(lcc, false);
      ExecRow row = rs.getNextRow();
      if (SanityManager.DEBUG)
      {
        if (row == null)
        {
          SanityManager.THROWASSERT("did not get any rows back from query: "+checkStmt.toString());
        }
      }

      DataValueDescriptor[] rowArray = row.getRowArray();
      Number value = ((Number)((NumberDataValue)row.getRowArray()[0]).getObject());
      /*
      ** Value may be null if there are no rows in the
      ** table.
      */
      if ((value != null) && (value.longValue() != 0))
      { 
        //check constraint violated
        if (isCheckConstraint)
          throw StandardException.newException(SQLState.LANG_ADD_CHECK_CONSTRAINT_FAILED,
            constraintName, td.getQualifiedName(), value.toString());
        /*
         * for not null constraint violations exception will be thrown in caller
         * check constraint will not get here since exception is thrown
         * above
         */
        return false;
      }
    }
    finally
    {
      if (rs != null)
      {
        rs.close();
      }
    }
    return true;
  }
}
TOP

Related Classes of org.apache.derby.impl.sql.execute.ConstraintConstantAction

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.