/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * 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.jkiss.dbeaver.ext.postgresql.edit; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.ext.postgresql.model.*; import org.jkiss.dbeaver.model.DBPEvaluationContext; import org.jkiss.dbeaver.model.DBUtils; import org.jkiss.dbeaver.model.edit.DBECommandContext; import org.jkiss.dbeaver.model.edit.DBEObjectRenamer; import org.jkiss.dbeaver.model.edit.DBEPersistAction; import org.jkiss.dbeaver.model.impl.DBSObjectCache; import org.jkiss.dbeaver.model.impl.edit.DBECommandAbstract; import org.jkiss.dbeaver.model.impl.edit.SQLDatabasePersistAction; import org.jkiss.dbeaver.model.impl.sql.edit.struct.SQLTableColumnManager; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.sql.SQLUtils; import org.jkiss.dbeaver.model.struct.DBSObject; import org.jkiss.dbeaver.ui.UITask; import org.jkiss.dbeaver.ui.editors.object.struct.AttributeEditPage; import org.jkiss.utils.CommonUtils; import java.sql.Types; import java.util.List; /** * Postgre table column manager */ public class PostgreTableColumnManager extends SQLTableColumnManager<PostgreTableColumn, PostgreTableBase> implements DBEObjectRenamer<PostgreTableColumn> { protected final ColumnModifier<PostgreTableColumn> PostgreDataTypeModifier = new ColumnModifier<PostgreTableColumn>() { @Override public void appendModifier(PostgreTableColumn column, StringBuilder sql, DBECommandAbstract<PostgreTableColumn> command) { sql.append(' '); final PostgreDataType dataType = column.getDataType(); final PostgreDataType rawType = dataType.getElementType(); if (rawType != null) { sql.append(rawType.getTypeName()); } else { sql.append(dataType.getTypeName()); } switch (dataType.getDataKind()) { case STRING: final long length = column.getMaxLength(); if (length > 0) { sql.append('(').append(length).append(')'); } break; case NUMERIC: if (dataType.getTypeID() == Types.NUMERIC) { final int precision = column.getPrecision(); final int scale = column.getScale(); if (scale > 0 || precision > 0) { sql.append('('); if (precision > 0) { sql.append(precision); } if (scale > 0) { if (precision > 0) { sql.append(','); } sql.append(scale); } sql.append(')'); } } break; } if (rawType != null) { sql.append("[]"); } } }; @Nullable @Override public DBSObjectCache<? extends DBSObject, PostgreTableColumn> getObjectsCache(PostgreTableColumn object) { return object.getParentObject().getContainer().tableCache.getChildrenCache(object.getParentObject()); } protected ColumnModifier[] getSupportedModifiers(PostgreTableColumn column) { return new ColumnModifier[] {PostgreDataTypeModifier, NullNotNullModifier, DefaultModifier}; } @Override public StringBuilder getNestedDeclaration(PostgreTableBase owner, DBECommandAbstract<PostgreTableColumn> command) { StringBuilder decl = super.getNestedDeclaration(owner, command); final PostgreAttribute column = command.getObject(); return decl; } @Override protected PostgreTableColumn createDatabaseObject(final DBRProgressMonitor monitor, final DBECommandContext context, final PostgreTableBase parent, Object copyFrom) { return new UITask<PostgreTableColumn>() { @Override protected PostgreTableColumn runTask() { final PostgreTableColumn column = new PostgreTableColumn(parent); column.setName(getNewColumnName(monitor, context, parent)); final PostgreDataType dataType = parent.getDatabase().getDataType(PostgreOid.VARCHAR); column.setDataType(dataType); //$NON-NLS-1$ column.setOrdinalPosition(-1); AttributeEditPage page = new AttributeEditPage(null, column); if (!page.edit()) { return null; } // Varchar length doesn't make much sense for PG // if (column.getDataKind() == DBPDataKind.STRING && !column.getTypeName().contains("text") && column.getMaxLength() <= 0) { // column.setMaxLength(100); // } return column; } }.execute(); } @Override protected void addObjectModifyActions(List<DBEPersistAction> actionList, ObjectChangeCommand command) { final PostgreAttribute column = command.getObject(); // PostgreSQL can't perform all changes by one query // ALTER [ COLUMN ] column [ SET DATA ] TYPE data_type [ COLLATE collation ] [ USING expression ] // ALTER [ COLUMN ] column SET DEFAULT expression // ALTER [ COLUMN ] column DROP DEFAULT // ALTER [ COLUMN ] column { SET | DROP } NOT NULL // ALTER [ COLUMN ] column SET STATISTICS integer // ALTER [ COLUMN ] column SET ( attribute_option = value [, ... ] ) // ALTER [ COLUMN ] column RESET ( attribute_option [, ... ] ) // ALTER [ COLUMN ] column SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN } String prefix = "ALTER TABLE " + DBUtils.getObjectFullName(column.getTable(), DBPEvaluationContext.DDL) + " ALTER COLUMN " + DBUtils.getQuotedIdentifier(column) + " "; String typeClause = column.getFullTypeName(); if (column.getDataType() != null) { typeClause += " USING " + DBUtils.getQuotedIdentifier(column) + "::" + column.getDataType().getName(); } if (command.getProperty("dataType") != null || command.getProperty("maxLength") != null || command.getProperty("precision") != null || command.getProperty("scale") != null) { actionList.add(new SQLDatabasePersistAction("Set column type", prefix + "TYPE " + typeClause)); } if (command.getProperty("required") != null) { actionList.add(new SQLDatabasePersistAction("Set column nullability", prefix + (column.isRequired() ? "SET" : "DROP") + " NOT NULL")); } if (command.getProperty("defaultValue") != null) { if (CommonUtils.isEmpty(column.getDefaultValue())) { actionList.add(new SQLDatabasePersistAction("Drop column default", prefix + "DROP DEFAULT")); } else { actionList.add(new SQLDatabasePersistAction("Set column default", prefix + "SET DEFAULT " + column.getDefaultValue())); } } if (command.getProperty("description") != null) { actionList.add(new SQLDatabasePersistAction("Set column comment", "COMMENT ON COLUMN " + DBUtils.getObjectFullName(column.getTable(), DBPEvaluationContext.DDL) + "." + DBUtils.getQuotedIdentifier(column) + " IS " + SQLUtils.quoteString(CommonUtils.notEmpty(column.getDescription())))); } } @Override public void renameObject(DBECommandContext commandContext, PostgreTableColumn object, String newName) throws DBException { processObjectRename(commandContext, object, newName); final PostgreTableBase table = object.getTable(); if (table.isPersisted() && table instanceof PostgreViewBase) { table.setObjectDefinitionText(null); commandContext.addCommand(new EmptyCommand(table), new RefreshObjectReflector(), true); } } @Override protected void addObjectRenameActions(List<DBEPersistAction> actions, ObjectRenameCommand command) { final PostgreAttribute column = command.getObject(); actions.add( new SQLDatabasePersistAction( "Rename column", "ALTER TABLE " + DBUtils.getObjectFullName(column.getTable(), DBPEvaluationContext.DDL) + " RENAME COLUMN " + DBUtils.getQuotedIdentifier(column.getDataSource(), command.getOldName()) + " TO " + DBUtils.getQuotedIdentifier(column.getDataSource(), command.getNewName()))); } }