<commit_before>/**
 * Copyright (C) 2009-2013 FoundationDB, LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.foundationdb.sql.aisddl;

import com.foundationdb.ais.model.Sequence;
import com.foundationdb.server.error.ColumnAlreadyGeneratedException;
import com.foundationdb.server.error.ColumnNotGeneratedException;
import com.foundationdb.server.error.SQLParserInternalException;
import com.foundationdb.sql.parser.AlterDropIndexNode;
import com.foundationdb.sql.parser.AlterTableRenameColumnNode;
import com.foundationdb.sql.parser.AlterTableRenameNode;
import com.foundationdb.ais.AISCloner;
import com.foundationdb.ais.model.AISBuilder;
import com.foundationdb.ais.model.AkibanInformationSchema;
import com.foundationdb.ais.model.Column;
import com.foundationdb.ais.model.Columnar;
import com.foundationdb.ais.model.DefaultIndexNameGenerator;
import com.foundationdb.ais.model.ForeignKey;
import com.foundationdb.ais.model.Index;
import com.foundationdb.ais.model.IndexColumn;
import com.foundationdb.ais.model.IndexNameGenerator;
import com.foundationdb.ais.model.Join;
import com.foundationdb.ais.model.Routine;
import com.foundationdb.ais.model.SQLJJar;
import com.foundationdb.ais.model.Table;
import com.foundationdb.ais.model.TableIndex;
import com.foundationdb.ais.model.TableName;
import com.foundationdb.ais.protobuf.ProtobufWriter;
import com.foundationdb.ais.util.TableChange;
import com.foundationdb.qp.operator.QueryContext;
import com.foundationdb.server.api.DDLFunctions;
import com.foundationdb.server.api.DMLFunctions;
import com.foundationdb.server.error.ForeignKeyPreventsAlterColumnException;
import com.foundationdb.server.error.JoinToMultipleParentsException;
import com.foundationdb.server.error.NoSuchColumnException;
import com.foundationdb.server.error.NoSuchConstraintException;
import com.foundationdb.server.error.NoSuchForeignKeyException;
import com.foundationdb.server.error.NoSuchGroupingFKException;
import com.foundationdb.server.error.NoSuchIndexException;
import com.foundationdb.server.error.NoSuchTableException;
import com.foundationdb.server.error.NoSuchUniqueException;
import com.foundationdb.server.error.UnsupportedCheckConstraintException;
import com.foundationdb.server.error.UnsupportedFKIndexException;
import com.foundationdb.server.error.UnsupportedSQLException;
import com.foundationdb.server.service.session.Session;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.sql.StandardException;
import com.foundationdb.sql.parser.AlterAddIndexNode;
import com.foundationdb.sql.parser.AlterTableNode;
import com.foundationdb.sql.parser.ColumnDefinitionNode;
import com.foundationdb.sql.parser.ConstraintDefinitionNode;
import com.foundationdb.sql.parser.FKConstraintDefinitionNode;
import com.foundationdb.sql.parser.IndexConstraintDefinitionNode;
import com.foundationdb.sql.parser.ModifyColumnNode;
import com.foundationdb.sql.parser.NodeTypes;
import com.foundationdb.sql.parser.QueryTreeNode;
import com.foundationdb.sql.parser.StatementType;
import com.foundationdb.sql.parser.TableElementList;
import com.foundationdb.sql.parser.TableElementNode;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.foundationdb.ais.util.TableChangeValidator.ChangeLevel;
import static com.foundationdb.ais.util.TableChange.ChangeType;
import static com.foundationdb.sql.aisddl.DDLHelper.convertName;
import static com.foundationdb.sql.parser.ConstraintDefinitionNode.ConstraintType;

public class AlterTableDDL {
    private AlterTableDDL() {}

    public static ChangeLevel alterTable(DDLFunctions ddlFunctions,
                                         DMLFunctions dmlFunctions,
                                         Session session,
                                         String defaultSchemaName,
                                         AlterTableNode alterTable,
                                         QueryContext context) {
        final AkibanInformationSchema curAIS = ddlFunctions.getAIS(session);
        final TableName tableName = convertName(defaultSchemaName, alterTable.getObjectName());
        final Table table = curAIS.getTable(tableName);
        if(table == null) {
            throw new NoSuchTableException(tableName);
        }

        if (alterTable.isUpdateStatistics()) {
            Collection<String> indexes = null;
            if (!alterTable.isUpdateStatisticsAll())
                indexes = Collections.singletonList(alterTable.getIndexNameForUpdateStatistics());
            ddlFunctions.updateTableStatistics(session, tableName, indexes);
            return null;
        }

        if (alterTable.isTruncateTable()) {
            dmlFunctions.truncateTable(session, table.getTableId(), alterTable.isCascade());
            return null;
        }

        ChangeLevel level = null;
        if((alterTable.tableElementList != null) && !alterTable.tableElementList.isEmpty()) {
            level = processAlter(ddlFunctions, session, defaultSchemaName, table, alterTable.tableElementList, context);
        }

        if(level == null) {
            throw new UnsupportedSQLException (alterTable.statementToString(), alterTable);
        }
        return level;
    }

    private static ChangeLevel processAlter(DDLFunctions ddl,
                                            Session session,
                                            String defaultSchema,
                                            Table origTable,
                                            TableElementList elements,
                                            QueryContext context) {
        List<TableChange> columnChanges = new ArrayList<>();
        List<TableChange> indexChanges = new ArrayList<>();
        List<ColumnDefinitionNode> columnDefNodes = new ArrayList<>();
        List<FKConstraintDefinitionNode> fkDefNodes= new ArrayList<>();
        List<ConstraintDefinitionNode> conDefNodes = new ArrayList<>();
        List<IndexConstraintDefinitionNode> indexDefNodes = new ArrayList<>();

        for(TableElementNode node : elements) {
            switch(node.getNodeType()) {
                case NodeTypes.COLUMN_DEFINITION_NODE: {
                    ColumnDefinitionNode cdn = (ColumnDefinitionNode) node;
                    columnChanges.add(TableChange.createAdd(cdn.getColumnName()));
                    columnDefNodes.add(cdn);
                } break;

                case NodeTypes.DROP_COLUMN_NODE: {
                    String columnName = ((ModifyColumnNode)node).getColumnName();
                    columnChanges.add(TableChange.createDrop(columnName));
                } break;

                case NodeTypes.MODIFY_COLUMN_DEFAULT_NODE:
                case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE:
                case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE:
                case NodeTypes.MODIFY_COLUMN_TYPE_NODE: {
                    String columnName = ((ModifyColumnNode)node).getColumnName();
                    columnChanges.add(TableChange.createModify(columnName, columnName));
                    columnDefNodes.add((ColumnDefinitionNode) node);
                } break;

                case NodeTypes.FK_CONSTRAINT_DEFINITION_NODE: {
                    FKConstraintDefinitionNode fkNode = (FKConstraintDefinitionNode) node;
                    if (!fkNode.isGrouping() && 
                        (fkNode.getConstraintType() == ConstraintType.DROP)) {
                        if (fkNode.getConstraintName() == null) {
                            Collection<ForeignKey> fkeys = origTable.getReferencingForeignKeys();
                            if (fkeys.size() != 1) {
                                throw new UnsupportedFKIndexException();
                            }
                            try {
                                fkNode.setConstraintName(fkeys.iterator().next().getConstraintName());
                            }
                            catch (StandardException ex) {
                                throw new SQLParserInternalException(ex);
                            }
                        }
                        // Also drop the referencing index.
                        indexChanges.add(TableChange.createDrop(fkNode.getConstraintName().getTableName()));
                    }
                    fkDefNodes.add(fkNode);
                } break;

                case NodeTypes.CONSTRAINT_DEFINITION_NODE: {
                    ConstraintDefinitionNode cdn = (ConstraintDefinitionNode) node;
                    if(cdn.getConstraintType() == ConstraintType.DROP) {
                        String name = cdn.getName();
                        switch(cdn.getVerifyType()) {
                            case PRIMARY_KEY:
                                name = Index.PRIMARY_KEY_CONSTRAINT;
                            break;
                            case DROP: // TODO : Generic Drop
                                boolean found = false;
                                if (checkFKConstraint(origTable, name, node, fkDefNodes)) {
                                    found = true;
                                } else if (name.equalsIgnoreCase(Index.PRIMARY_KEY_CONSTRAINT)) {
                                    name = Index.PRIMARY_KEY_CONSTRAINT;
                                    found = true;
                                } else if (origTable.getIndex(name) != null) {
                                    if (origTable.getIndex(name).isUnique()) {
                                        found = true;
                                    }
                                } else if (origTable.getParentJoin() != null && origTable.getParentJoin().getName().equals(name)) {
                                    found = true;
                                    try {
                                        QueryTreeNode gfkName = node.getParserContext().getNodeFactory().getNode(NodeTypes.TABLE_NAME,
                                                null, 
                                                name,
                                                node.getParserContext());

                                        FKConstraintDefinitionNode fkNode = 
                                                (FKConstraintDefinitionNode)node.getParserContext().getNodeFactory().getNode(
                                                    NodeTypes.FK_CONSTRAINT_DEFINITION_NODE,
                                                    gfkName,
                                                    ConstraintDefinitionNode.ConstraintType.DROP,
                                                    StatementType.DROP_DEFAULT,
                                                    Boolean.TRUE,
                                                    node.getParserContext());
                                        fkDefNodes.add(fkNode);
                                    } catch (StandardException ex) {
                                        // TODO: Anything? 
                                    }
                                    name = null;
                                }
                                if (!found) {
                                    throw new NoSuchConstraintException(origTable.getName(), name);
                                }
                                break;
                            case UNIQUE:
                                Index index = origTable.getIndex(name);
                                if(index == null || !index.isUnique()) {
                                    throw new NoSuchUniqueException(origTable.getName(), cdn.getName());
                                }
                            break;
                            case CHECK:
                                throw new UnsupportedCheckConstraintException();
                        }
                        if (name != null)
                            indexChanges.add(TableChange.createDrop(name));
                    } else if (cdn.getConstraintType() == ConstraintType.PRIMARY_KEY) {
                        if (origTable.getPrimaryKey() == null && origTable.getPrimaryKeyIncludingInternal().isAkibanPK())
                        {
                            columnChanges.add(TableChange.createDrop(Column.AKIBAN_PK_NAME));
                        }
                        conDefNodes.add(cdn);
                    } else {
                        conDefNodes.add(cdn);
                    }
                } break;

                case NodeTypes.AT_ADD_INDEX_NODE:
                    AlterAddIndexNode aain = (AlterAddIndexNode)node;
                    IndexConstraintDefinitionNode icdnT = new IndexConstraintDefinitionNode();
                    com.foundationdb.sql.parser.TableName tableName = new com.foundationdb.sql.parser.TableName();
                    tableName.init(origTable.getName().getSchemaName() , origTable.getName().getTableName());
                    icdnT.init(tableName, aain.getIndexColunmList(), aain.getName(), aain.getJoinType(), aain.getStorageFormat());
                    indexDefNodes.add(icdnT);
                    indexChanges.add(TableChange.createAdd(icdnT.getName()));
                    break;
                    
                case NodeTypes.INDEX_CONSTRAINT_NODE:
                    IndexConstraintDefinitionNode icdn = (IndexConstraintDefinitionNode)node;
                    indexDefNodes.add(icdn);
                    indexChanges.add(TableChange.createAdd(icdn.getName()));
                    break;
                    
                case NodeTypes.AT_DROP_INDEX_NODE:
                    indexChanges.add(TableChange.createDrop(((AlterDropIndexNode)node).getIndexName()));
                    break;

                case NodeTypes.AT_RENAME_NODE:
                    TableName newName = DDLHelper.convertName(defaultSchema,
                                                              ((AlterTableRenameNode)node).newName());
                    TableName oldName = origTable.getName();
                    ddl.renameTable(session, oldName, newName);
                    return ChangeLevel.METADATA;
                    
                case NodeTypes.AT_RENAME_COLUMN_NODE:
                    AlterTableRenameColumnNode alterRenameCol = (AlterTableRenameColumnNode) node;
                    String oldColName = alterRenameCol.getName();
                    String newColName = alterRenameCol.newName();
                    final Column oldCol = origTable.getColumn(oldColName);
                    if (oldCol == null) {
                        throw new NoSuchColumnException(oldColName);
                    }
                    columnChanges.add(TableChange.createModify(oldColName, newColName));
                break;

                default:
                    return null; // Something unsupported
            }
        }
        
        for (ForeignKey foreignKey : origTable.getForeignKeys()) {
            if (foreignKey.getReferencingTable() == origTable) {
                checkForeignKeyAlterColumns(columnChanges, foreignKey.getReferencingColumns(),
                                            foreignKey, origTable);
            }
            if (foreignKey.getReferencedTable() == origTable) {
                checkForeignKeyAlterColumns(columnChanges, foreignKey.getReferencedColumns(),
                                            foreignKey, origTable);
            }
        }

        final AkibanInformationSchema origAIS = origTable.getAIS();
        final Table tableCopy = copyTable(ddl.getAISCloner(), origTable, columnChanges);
        final AkibanInformationSchema aisCopy = tableCopy.getAIS();
        final TypesTranslator typesTranslator = ddl.getTypesTranslator();
        final AISBuilder builder = new AISBuilder(aisCopy);

        int pos = origTable.getColumns().size();
        for(ColumnDefinitionNode cdn : columnDefNodes) {
            if(cdn instanceof ModifyColumnNode) {
                ModifyColumnNode modNode = (ModifyColumnNode) cdn;<commit_msg>Include internal columns size on add column pos<commit_after>/**
 * Copyright (C) 2009-2013 FoundationDB, LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.foundationdb.sql.aisddl;

import com.foundationdb.ais.model.Sequence;
import com.foundationdb.server.error.ColumnAlreadyGeneratedException;
import com.foundationdb.server.error.ColumnNotGeneratedException;
import com.foundationdb.server.error.SQLParserInternalException;
import com.foundationdb.sql.parser.AlterDropIndexNode;
import com.foundationdb.sql.parser.AlterTableRenameColumnNode;
import com.foundationdb.sql.parser.AlterTableRenameNode;
import com.foundationdb.ais.AISCloner;
import com.foundationdb.ais.model.AISBuilder;
import com.foundationdb.ais.model.AkibanInformationSchema;
import com.foundationdb.ais.model.Column;
import com.foundationdb.ais.model.Columnar;
import com.foundationdb.ais.model.DefaultIndexNameGenerator;
import com.foundationdb.ais.model.ForeignKey;
import com.foundationdb.ais.model.Index;
import com.foundationdb.ais.model.IndexColumn;
import com.foundationdb.ais.model.IndexNameGenerator;
import com.foundationdb.ais.model.Join;
import com.foundationdb.ais.model.Routine;
import com.foundationdb.ais.model.SQLJJar;
import com.foundationdb.ais.model.Table;
import com.foundationdb.ais.model.TableIndex;
import com.foundationdb.ais.model.TableName;
import com.foundationdb.ais.protobuf.ProtobufWriter;
import com.foundationdb.ais.util.TableChange;
import com.foundationdb.qp.operator.QueryContext;
import com.foundationdb.server.api.DDLFunctions;
import com.foundationdb.server.api.DMLFunctions;
import com.foundationdb.server.error.ForeignKeyPreventsAlterColumnException;
import com.foundationdb.server.error.JoinToMultipleParentsException;
import com.foundationdb.server.error.NoSuchColumnException;
import com.foundationdb.server.error.NoSuchConstraintException;
import com.foundationdb.server.error.NoSuchForeignKeyException;
import com.foundationdb.server.error.NoSuchGroupingFKException;
import com.foundationdb.server.error.NoSuchIndexException;
import com.foundationdb.server.error.NoSuchTableException;
import com.foundationdb.server.error.NoSuchUniqueException;
import com.foundationdb.server.error.UnsupportedCheckConstraintException;
import com.foundationdb.server.error.UnsupportedFKIndexException;
import com.foundationdb.server.error.UnsupportedSQLException;
import com.foundationdb.server.service.session.Session;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.sql.StandardException;
import com.foundationdb.sql.parser.AlterAddIndexNode;
import com.foundationdb.sql.parser.AlterTableNode;
import com.foundationdb.sql.parser.ColumnDefinitionNode;
import com.foundationdb.sql.parser.ConstraintDefinitionNode;
import com.foundationdb.sql.parser.FKConstraintDefinitionNode;
import com.foundationdb.sql.parser.IndexConstraintDefinitionNode;
import com.foundationdb.sql.parser.ModifyColumnNode;
import com.foundationdb.sql.parser.NodeTypes;
import com.foundationdb.sql.parser.QueryTreeNode;
import com.foundationdb.sql.parser.StatementType;
import com.foundationdb.sql.parser.TableElementList;
import com.foundationdb.sql.parser.TableElementNode;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.foundationdb.ais.util.TableChangeValidator.ChangeLevel;
import static com.foundationdb.ais.util.TableChange.ChangeType;
import static com.foundationdb.sql.aisddl.DDLHelper.convertName;
import static com.foundationdb.sql.parser.ConstraintDefinitionNode.ConstraintType;

public class AlterTableDDL {
    private AlterTableDDL() {}

    public static ChangeLevel alterTable(DDLFunctions ddlFunctions,
                                         DMLFunctions dmlFunctions,
                                         Session session,
                                         String defaultSchemaName,
                                         AlterTableNode alterTable,
                                         QueryContext context) {
        final AkibanInformationSchema curAIS = ddlFunctions.getAIS(session);
        final TableName tableName = convertName(defaultSchemaName, alterTable.getObjectName());
        final Table table = curAIS.getTable(tableName);
        if(table == null) {
            throw new NoSuchTableException(tableName);
        }

        if (alterTable.isUpdateStatistics()) {
            Collection<String> indexes = null;
            if (!alterTable.isUpdateStatisticsAll())
                indexes = Collections.singletonList(alterTable.getIndexNameForUpdateStatistics());
            ddlFunctions.updateTableStatistics(session, tableName, indexes);
            return null;
        }

        if (alterTable.isTruncateTable()) {
            dmlFunctions.truncateTable(session, table.getTableId(), alterTable.isCascade());
            return null;
        }

        ChangeLevel level = null;
        if((alterTable.tableElementList != null) && !alterTable.tableElementList.isEmpty()) {
            level = processAlter(ddlFunctions, session, defaultSchemaName, table, alterTable.tableElementList, context);
        }

        if(level == null) {
            throw new UnsupportedSQLException (alterTable.statementToString(), alterTable);
        }
        return level;
    }

    private static ChangeLevel processAlter(DDLFunctions ddl,
                                            Session session,
                                            String defaultSchema,
                                            Table origTable,
                                            TableElementList elements,
                                            QueryContext context) {
        List<TableChange> columnChanges = new ArrayList<>();
        List<TableChange> indexChanges = new ArrayList<>();
        List<ColumnDefinitionNode> columnDefNodes = new ArrayList<>();
        List<FKConstraintDefinitionNode> fkDefNodes= new ArrayList<>();
        List<ConstraintDefinitionNode> conDefNodes = new ArrayList<>();
        List<IndexConstraintDefinitionNode> indexDefNodes = new ArrayList<>();

        for(TableElementNode node : elements) {
            switch(node.getNodeType()) {
                case NodeTypes.COLUMN_DEFINITION_NODE: {
                    ColumnDefinitionNode cdn = (ColumnDefinitionNode) node;
                    columnChanges.add(TableChange.createAdd(cdn.getColumnName()));
                    columnDefNodes.add(cdn);
                } break;

                case NodeTypes.DROP_COLUMN_NODE: {
                    String columnName = ((ModifyColumnNode)node).getColumnName();
                    columnChanges.add(TableChange.createDrop(columnName));
                } break;

                case NodeTypes.MODIFY_COLUMN_DEFAULT_NODE:
                case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE:
                case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE:
                case NodeTypes.MODIFY_COLUMN_TYPE_NODE: {
                    String columnName = ((ModifyColumnNode)node).getColumnName();
                    columnChanges.add(TableChange.createModify(columnName, columnName));
                    columnDefNodes.add((ColumnDefinitionNode) node);
                } break;

                case NodeTypes.FK_CONSTRAINT_DEFINITION_NODE: {
                    FKConstraintDefinitionNode fkNode = (FKConstraintDefinitionNode) node;
                    if (!fkNode.isGrouping() && 
                        (fkNode.getConstraintType() == ConstraintType.DROP)) {
                        if (fkNode.getConstraintName() == null) {
                            Collection<ForeignKey> fkeys = origTable.getReferencingForeignKeys();
                            if (fkeys.size() != 1) {
                                throw new UnsupportedFKIndexException();
                            }
                            try {
                                fkNode.setConstraintName(fkeys.iterator().next().getConstraintName());
                            }
                            catch (StandardException ex) {
                                throw new SQLParserInternalException(ex);
                            }
                        }
                        // Also drop the referencing index.
                        indexChanges.add(TableChange.createDrop(fkNode.getConstraintName().getTableName()));
                    }
                    fkDefNodes.add(fkNode);
                } break;

                case NodeTypes.CONSTRAINT_DEFINITION_NODE: {
                    ConstraintDefinitionNode cdn = (ConstraintDefinitionNode) node;
                    if(cdn.getConstraintType() == ConstraintType.DROP) {
                        String name = cdn.getName();
                        switch(cdn.getVerifyType()) {
                            case PRIMARY_KEY:
                                name = Index.PRIMARY_KEY_CONSTRAINT;
                            break;
                            case DROP: // TODO : Generic Drop
                                boolean found = false;
                                if (checkFKConstraint(origTable, name, node, fkDefNodes)) {
                                    found = true;
                                } else if (name.equalsIgnoreCase(Index.PRIMARY_KEY_CONSTRAINT)) {
                                    name = Index.PRIMARY_KEY_CONSTRAINT;
                                    found = true;
                                } else if (origTable.getIndex(name) != null) {
                                    if (origTable.getIndex(name).isUnique()) {
                                        found = true;
                                    }
                                } else if (origTable.getParentJoin() != null && origTable.getParentJoin().getName().equals(name)) {
                                    found = true;
                                    try {
                                        QueryTreeNode gfkName = node.getParserContext().getNodeFactory().getNode(NodeTypes.TABLE_NAME,
                                                null, 
                                                name,
                                                node.getParserContext());

                                        FKConstraintDefinitionNode fkNode = 
                                                (FKConstraintDefinitionNode)node.getParserContext().getNodeFactory().getNode(
                                                    NodeTypes.FK_CONSTRAINT_DEFINITION_NODE,
                                                    gfkName,
                                                    ConstraintDefinitionNode.ConstraintType.DROP,
                                                    StatementType.DROP_DEFAULT,
                                                    Boolean.TRUE,
                                                    node.getParserContext());
                                        fkDefNodes.add(fkNode);
                                    } catch (StandardException ex) {
                                        // TODO: Anything? 
                                    }
                                    name = null;
                                }
                                if (!found) {
                                    throw new NoSuchConstraintException(origTable.getName(), name);
                                }
                                break;
                            case UNIQUE:
                                Index index = origTable.getIndex(name);
                                if(index == null || !index.isUnique()) {
                                    throw new NoSuchUniqueException(origTable.getName(), cdn.getName());
                                }
                            break;
                            case CHECK:
                                throw new UnsupportedCheckConstraintException();
                        }
                        if (name != null)
                            indexChanges.add(TableChange.createDrop(name));
                    } else if (cdn.getConstraintType() == ConstraintType.PRIMARY_KEY) {
                        if (origTable.getPrimaryKey() == null && origTable.getPrimaryKeyIncludingInternal().isAkibanPK())
                        {
                            columnChanges.add(TableChange.createDrop(Column.AKIBAN_PK_NAME));
                        }
                        conDefNodes.add(cdn);
                    } else {
                        conDefNodes.add(cdn);
                    }
                } break;

                case NodeTypes.AT_ADD_INDEX_NODE:
                    AlterAddIndexNode aain = (AlterAddIndexNode)node;
                    IndexConstraintDefinitionNode icdnT = new IndexConstraintDefinitionNode();
                    com.foundationdb.sql.parser.TableName tableName = new com.foundationdb.sql.parser.TableName();
                    tableName.init(origTable.getName().getSchemaName() , origTable.getName().getTableName());
                    icdnT.init(tableName, aain.getIndexColunmList(), aain.getName(), aain.getJoinType(), aain.getStorageFormat());
                    indexDefNodes.add(icdnT);
                    indexChanges.add(TableChange.createAdd(icdnT.getName()));
                    break;
                    
                case NodeTypes.INDEX_CONSTRAINT_NODE:
                    IndexConstraintDefinitionNode icdn = (IndexConstraintDefinitionNode)node;
                    indexDefNodes.add(icdn);
                    indexChanges.add(TableChange.createAdd(icdn.getName()));
                    break;
                    
                case NodeTypes.AT_DROP_INDEX_NODE:
                    indexChanges.add(TableChange.createDrop(((AlterDropIndexNode)node).getIndexName()));
                    break;

                case NodeTypes.AT_RENAME_NODE:
                    TableName newName = DDLHelper.convertName(defaultSchema,
                                                              ((AlterTableRenameNode)node).newName());
                    TableName oldName = origTable.getName();
                    ddl.renameTable(session, oldName, newName);
                    return ChangeLevel.METADATA;
                    
                case NodeTypes.AT_RENAME_COLUMN_NODE:
                    AlterTableRenameColumnNode alterRenameCol = (AlterTableRenameColumnNode) node;
                    String oldColName = alterRenameCol.getName();
                    String newColName = alterRenameCol.newName();
                    final Column oldCol = origTable.getColumn(oldColName);
                    if (oldCol == null) {
                        throw new NoSuchColumnException(oldColName);
                    }
                    columnChanges.add(TableChange.createModify(oldColName, newColName));
                break;

                default:
                    return null; // Something unsupported
            }
        }
        
        for (ForeignKey foreignKey : origTable.getForeignKeys()) {
            if (foreignKey.getReferencingTable() == origTable) {
                checkForeignKeyAlterColumns(columnChanges, foreignKey.getReferencingColumns(),
                                            foreignKey, origTable);
            }
            if (foreignKey.getReferencedTable() == origTable) {
                checkForeignKeyAlterColumns(columnChanges, foreignKey.getReferencedColumns(),
                                            foreignKey, origTable);
            }
        }

        final AkibanInformationSchema origAIS = origTable.getAIS();
        final Table tableCopy = copyTable(ddl.getAISCloner(), origTable, columnChanges);
        final AkibanInformationSchema aisCopy = tableCopy.getAIS();
        final TypesTranslator typesTranslator = ddl.getTypesTranslator();
        final AISBuilder builder = new AISBuilder(aisCopy);

        int pos = origTable.getColumnsIncludingInternal().size();
        for(ColumnDefinitionNode cdn : columnDefNodes) {
            if(cdn instanceof ModifyColumnNode) {
                ModifyColumnNode modNode = (ModifyColumnNode) cdn;
{'fraction_non_alphanumeric': 0.0771400576026604, 'fraction_numerical': 0.0005938418599127053, 'mean_word_length': 1.7333225125791267, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 142, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5829934', 'n_tokens_mistral': 8022, 'n_tokens_neox': 7635, 'n_words': 1392}