/* * Copyright 2014-2015 the original author or authors * * 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. */ // Created on 2015年4月12日 // $Id$ package com.wplatform.ddal.excutor.ddl; import java.util.Map; import com.wplatform.ddal.command.CommandInterface; import com.wplatform.ddal.command.ddl.AlterTableAddConstraint; import com.wplatform.ddal.dbobject.Right; import com.wplatform.ddal.dbobject.table.IndexColumn; import com.wplatform.ddal.dbobject.table.TableMate; import com.wplatform.ddal.dispatch.rule.TableNode; import com.wplatform.ddal.message.DbException; import com.wplatform.ddal.message.ErrorCode; import com.wplatform.ddal.util.StatementBuilder; import com.wplatform.ddal.util.StringUtils; /** * @author <a href="mailto:jorgie.mail@gmail.com">jorgie li</a> */ public class AlterTableAddConstraintExecutor extends DefineCommandExecutor<AlterTableAddConstraint> { /** * @param session * @param prepared */ public AlterTableAddConstraintExecutor(AlterTableAddConstraint prepared) { super(prepared); } @Override public int executeUpdate() { String tableName = prepared.getTableName(); TableMate table = getTableMate(tableName); session.getUser().checkRight(table, Right.ALL); TableNode[] tableNodes = table.getPartitionNode(); int type = prepared.getType(); switch (type) { case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_REFERENTIAL: { String refTableName = prepared.getRefTableName(); TableMate refTable = getTableMate(refTableName); TableNode[] refTableNode = table.getPartitionNode(); Map<TableNode, TableNode> symmetryRelation = getSymmetryRelation(tableNodes, refTableNode); if (symmetryRelation == null) { throw DbException.get(ErrorCode.CHECK_CONSTRAINT_INVALID, "The original table and reference table should be symmetrical."); } session.getUser().checkRight(refTable, Right.ALL); } case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY: case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_UNIQUE: case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_CHECK: { execute(tableNodes); break; } default: throw DbException.throwInternalError("type=" + type); } return 0; } @Override protected String doTranslate(TableNode tableNode) { String tableName = prepared.getTableName(); TableMate table = getTableMate(tableName); String forTable = tableNode.getCompositeObjectName(); IndexColumn.mapColumns(prepared.getIndexColumns(), table); switch (prepared.getType()) { case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY: { return doBuildUnique(forTable, AlterTableAddConstraint.PRIMARY_KEY); } case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_UNIQUE: { String uniqueType = AlterTableAddConstraint.UNIQUE + " KEY"; return doBuildUnique(forTable, uniqueType); } case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_CHECK: { /* * MySQL. The CHECK clause is parsed but ignored by all storage * engines. */ return doBuildCheck(forTable); } case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_REFERENTIAL: { /* * MySQL. The FOREIGN KEY and REFERENCES clauses are supported by * the InnoDB and NDB storage engines */ String refTableName = prepared.getRefTableName(); TableMate refTable = getTableMate(refTableName); Map<TableNode, TableNode> symmetryRelation = getSymmetryRelation(table.getPartitionNode(), refTable.getPartitionNode()); TableNode relation = symmetryRelation.get(tableNode); if (relation == null) { throw DbException.get(ErrorCode.CHECK_CONSTRAINT_INVALID, "The original table and reference table should be symmetrical."); } return doBuildReferences(forTable, relation.getCompositeObjectName()); } default: throw DbException.throwInternalError("type=" + prepared.getType()); } } private String doBuildUnique(String forTable, String uniqueType) { StatementBuilder buff = new StatementBuilder("ALTER TABLE "); buff.append(identifier(forTable)).append(" ADD CONSTRAINT "); String constraintName = prepared.getConstraintName(); // MySQL constraintName is optional if (!StringUtils.isNullOrEmpty(constraintName)) { buff.append(constraintName); } buff.append(' ').append(uniqueType); if (prepared.isPrimaryKeyHash()) { buff.append(" USING ").append("HASH"); } buff.append('('); for (IndexColumn c : prepared.getIndexColumns()) { buff.appendExceptFirst(", "); buff.append(identifier(c.column.getName())); } buff.append(')'); return buff.toString(); } private String doBuildCheck(String forTable) { StringBuilder buff = new StringBuilder("ALTER TABLE "); buff.append(identifier(forTable)).append(" ADD CONSTRAINT "); String constraintName = prepared.getConstraintName(); if (!StringUtils.isNullOrEmpty(constraintName)) { buff.append(constraintName); } String enclose = StringUtils.enclose(prepared.getCheckExpression().getSQL()); buff.append(" CHECK").append(enclose).append(" NOCHECK"); return buff.toString(); } private String doBuildReferences(String forTable, String forRefTable) { StatementBuilder buff = new StatementBuilder("ALTER TABLE "); buff.append(identifier(forTable)).append(" ADD CONSTRAINT "); String constraintName = prepared.getConstraintName(); if (!StringUtils.isNullOrEmpty(constraintName)) { buff.append(constraintName); } IndexColumn[] cols = prepared.getIndexColumns(); IndexColumn[] refCols = prepared.getRefIndexColumns(); buff.append(" FOREIGN KEY("); for (IndexColumn c : cols) { buff.appendExceptFirst(", "); buff.append(c.getSQL()); } buff.append(')'); buff.append(" REFERENCES "); buff.append(forRefTable).append('('); buff.resetCount(); for (IndexColumn r : refCols) { buff.appendExceptFirst(", "); buff.append(r.getSQL()); } buff.append(')'); if (prepared.getDeleteAction() != AlterTableAddConstraint.RESTRICT) { buff.append(" ON DELETE "); appendAction(buff, prepared.getDeleteAction()); } if (prepared.getUpdateAction() != AlterTableAddConstraint.RESTRICT) { buff.append(" ON UPDATE "); appendAction(buff, prepared.getDeleteAction()); } return buff.toString(); } private static void appendAction(StatementBuilder buff, int action) { switch (action) { case AlterTableAddConstraint.CASCADE: buff.append("CASCADE"); break; case AlterTableAddConstraint.SET_DEFAULT: buff.append("SET DEFAULT"); break; case AlterTableAddConstraint.SET_NULL: buff.append("SET NULL"); break; default: DbException.throwInternalError("action=" + action); } } }