/***************************************************************************** * Copyright (C) 2008 EnterpriseDB Corporation. * Copyright (C) 2011 Stado Global Development Group. * * This file is part of Stado. * * Stado is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Stado 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Stado. If not, see <http://www.gnu.org/licenses/>. * * You can find Stado at http://www.stado.us * ****************************************************************************/ /* * SqlAlterAddPrimary.java * * */ package org.postgresql.stado.parser; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import org.postgresql.stado.common.util.ParseCmdLine; import org.postgresql.stado.common.util.Props; import org.postgresql.stado.common.util.XLogger; import org.postgresql.stado.engine.Engine; import org.postgresql.stado.engine.ExecutionResult; import org.postgresql.stado.engine.IPreparable; import org.postgresql.stado.engine.XDBSessionContext; import org.postgresql.stado.exception.ErrorMessageRepository; import org.postgresql.stado.exception.XDBServerException; import org.postgresql.stado.metadata.SyncAlterTablePrimaryKey; import org.postgresql.stado.metadata.SysColumn; import org.postgresql.stado.metadata.SysIndex; import org.postgresql.stado.metadata.SysPermission; import org.postgresql.stado.metadata.SysTable; import org.postgresql.stado.parser.core.syntaxtree.ColumnNameList; import org.postgresql.stado.parser.core.syntaxtree.Constraint; import org.postgresql.stado.parser.core.syntaxtree.PrimaryKeyDef; import org.postgresql.stado.parser.core.visitor.DepthFirstRetArguVisitor; import org.postgresql.stado.parser.handler.ColumnNameListHandler; import org.postgresql.stado.parser.handler.IdentifierHandler; /** * Class for adding a PRIMARY KEY to a table * * */ public class SqlAlterAddPrimary extends DepthFirstRetArguVisitor implements IPreparable { private static final XLogger logger = XLogger .getLogger(SqlAlterAddPrimary.class); private XDBSessionContext client; private SqlAlterTable parent; private String constraintName = null; private List<String> columnNameList = null; private int indexIdToUse = -1; // id of already existing Unique index to // use for the primary key private String[] commands; /** * @param table * @param client */ public SqlAlterAddPrimary(SqlAlterTable parent, XDBSessionContext client) { this.client = client; this.parent = parent; } /** * Grammar production: f0 -> <CONSTRAINT_> f1 -> * IdentifierAndUnreservedWords(prn) */ @Override public Object visit(Constraint n, Object argu) { constraintName = (String) n.f1.accept(this, argu); return null; } @Override public Object visit(ColumnNameList n, Object argu) { ColumnNameListHandler aNameListHandler = new ColumnNameListHandler(); n.accept(aNameListHandler, null); columnNameList = aNameListHandler.getColumnNameList(); return null; } /** * Grammar production: f0 -> <PRIMARYKEY_> f1 -> "(" f2 -> * ColumnNameList(prn) f3 -> ")" */ @Override public Object visit(PrimaryKeyDef n, Object argu) { ColumnNameListHandler aNameListHandler = new ColumnNameListHandler(); n.f2.accept(aNameListHandler, null); if (columnNameList != null) { throw new XDBServerException("multiple primary keys for table " + parent.getTableName() + " are not allowed"); } columnNameList = aNameListHandler.getColumnNameList(); return null; } public SqlAlterTable getParent() { return parent; } /** * * @return returns the index id used to create the primary key -1 if no such * index exists */ public int getIndexIDUsed() { return indexIdToUse; } public String getConstraintName() { return constraintName; } public List<String> getColumnNames() { return columnNameList; } /* * (non-Javadoc) * * @see org.postgresql.stado.Engine.IPreparable#isPrepared() */ public boolean isPrepared() { return commands != null; } /* * (non-Javadoc) * * @see org.postgresql.stado.Engine.IPreparable#prepare() */ public void prepare() throws Exception { final String method = "prepare"; LinkedList<String> comm = new LinkedList<String>(); String sql; logger.entering(method, new Object[] {}); try { SysTable table = parent.getTable(); table.ensurePermission(client.getCurrentUser(), SysPermission.PRIVILEGE_ALTER); for (Object element : columnNameList) { String columnName = (String) element; SysColumn column = table.getSysColumn(columnName); if (column == null) { throw new XDBServerException( ErrorMessageRepository.COLUMN_NOT_IN_TABLE + " (" + columnName + ", " + table.getTableName() + ")", 0, ErrorMessageRepository.COLUMN_NOT_IN_TABLE_CODE); } } List<SysColumn> oldKey = table.getPrimaryKey(); if (oldKey != null && oldKey.size() > 0) { throw new XDBServerException( ErrorMessageRepository.PRIMARY_INDEX_ALREADY_PRESENT + " (" + table.getTableName() + " )", 0, ErrorMessageRepository.PRIMARY_INDEX_ALREADY_PRESENT_CODE); } SysIndex indexToUse = table.getPrimaryOrUniqueIndex(columnNameList); indexIdToUse = indexToUse == null ? -1 : indexToUse.idxid; StringBuffer aColumnList = new StringBuffer(); for (String element : columnNameList) { aColumnList.append(IdentifierHandler.quote(element)).append(", "); } aColumnList.setLength(aColumnList.length() - 2); HashMap<String,String> arguments = new HashMap<String,String>(); arguments.put("table", IdentifierHandler.quote(table.getTableName())); arguments.put("col_list", aColumnList.toString()); if (constraintName == null) { constraintName = "PK_IDX_" + table.getTableName(); } arguments.put("constr_name", IdentifierHandler.quote(constraintName)); sql = ParseCmdLine.substitute( Props.XDB_SQLCOMMAND_ALTERTABLE_ADDPRIMARY, arguments); if (Props.XDB_SQLCOMMAND_ALTERTABLE_ADDPRIMARY_TO_PARENT) { parent.addCommonCommand(sql); } else { comm.add(sql); } commands = comm.toArray(new String[comm.size()]); } finally { logger.exiting(method); } } /* * (non-Javadoc) * * @see org.postgresql.stado.Engine.IExecutable#execute(org.postgresql.stado.Engine.Engine) */ public ExecutionResult execute(Engine engine) throws Exception { final String method = "execute"; logger.entering(method, new Object[] {}); try { engine.executeDDLOnMultipleNodes(commands, parent.getNodeList(), new SyncAlterTablePrimaryKey(this), client); return null; } finally { logger.exiting(method); } } @Override public boolean isReadOnly() { // TODO Auto-generated method stub return false; } }