<commit_before>/*
 * DBeaver - Universal Database Manager
 * Copyright (C) 2010-2019 <NAME> (<EMAIL>)
 * Copyright (C) 2011-2012 <NAME> (<EMAIL>)
 *
 * 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.mysql.edit;

import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.ext.mysql.MySQLConstants;
import org.jkiss.dbeaver.ext.mysql.model.MySQLTable;
import org.jkiss.dbeaver.ext.mysql.model.MySQLTableBase;
import org.jkiss.dbeaver.ext.mysql.model.MySQLTableColumn;
import org.jkiss.dbeaver.model.DBPDataKind;
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.DBEObjectReorderer;
import org.jkiss.dbeaver.model.edit.DBEPersistAction;
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
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.DBSDataType;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.model.struct.cache.DBSObjectCache;
import org.jkiss.utils.CommonUtils;

import java.sql.Types;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * MySQL table column manager
 */
public class MySQLTableColumnManager extends SQLTableColumnManager<MySQLTableColumn, MySQLTableBase>
    implements DBEObjectRenamer<MySQLTableColumn>, DBEObjectReorderer<MySQLTableColumn>
{

    private final ColumnModifier<MySQLTableColumn> MySQLDataTypeModifier = (monitor, column, sql, command) ->
        sql.append(' ').append(column.getFullTypeName());

    private final ColumnModifier<MySQLTableColumn> CharsetModifier = (monitor, column, sql, command) -> {
        if (column.getDataKind() == DBPDataKind.STRING && column.getCharset() != null) {
            sql.append(" CHARACTER SET ").append(column.getCharset().getName()); //$NON-NLS-1$
        }
    };

    private final ColumnModifier<MySQLTableColumn> CollationModifier = (monitor, column, sql, command) -> {
        if (column.getDataKind() == DBPDataKind.STRING && column.getCollation() != null) {
            sql.append(" COLLATE ").append(column.getCollation().getName()); //$NON-NLS-1$
        }
    };

    private final ColumnModifier<MySQLTableColumn> ExtraInfoModifier = (monitor, column, sql, command) -> {
        if (!CommonUtils.isEmpty(column.getExtraInfo())) {
            if (MySQLConstants.EXTRA_INFO_VIRTUAL_GENERATED.equalsIgnoreCase(column.getExtraInfo())) {
                if (!CommonUtils.isEmpty(column.getGenExpression())) {
                    sql.append(" GENERATED ALWAYS AS (").append(column.getGenExpression()).append(") VIRTUAL"); //$NON-NLS-1$ //$NON-NLS-2$
                } else {
                    log.debug("No virtual column generate expression found for " + column.getName());
                }
            } else {
                sql.append(" ").append(column.getExtraInfo()); //$NON-NLS-1$
            }
        }
    };

    @Nullable
    @Override
    public DBSObjectCache<? extends DBSObject, MySQLTableColumn> getObjectsCache(MySQLTableColumn object)
    {
        return object.getParentObject().getContainer().getTableCache().getChildrenCache(object.getParentObject());
    }

    protected ColumnModifier[] getSupportedModifiers(MySQLTableColumn column, Map<String, Object> options)
    {
        return new ColumnModifier[] {MySQLDataTypeModifier, CharsetModifier, CollationModifier, DefaultModifier, ExtraInfoModifier, NullNotNullModifier};
    }

    @Override
    public StringBuilder getNestedDeclaration(DBRProgressMonitor monitor, MySQLTableBase owner, DBECommandAbstract<MySQLTableColumn> command, Map<String, Object> options)
    {
        StringBuilder decl = super.getNestedDeclaration(monitor, owner, command, options);
        final MySQLTableColumn column = command.getObject();
        if (column.isAutoGenerated() &&
            (CommonUtils.isEmpty(column.getExtraInfo()) || !column.getExtraInfo().toLowerCase(Locale.ENGLISH).contains(MySQLConstants.EXTRA_AUTO_INCREMENT)))
        {
            decl.append(" AUTO_INCREMENT"); //$NON-NLS-1$
        }
        if (!CommonUtils.isEmpty(column.getComment())) {
            decl.append(" COMMENT ").append(SQLUtils.quoteString(column, column.getComment())); //$NON-NLS-1$
        }
        return decl;
    }

    @Override
    protected MySQLTableColumn createDatabaseObject(final DBRProgressMonitor monitor, final DBECommandContext context, final Object container, Object copyFrom, Map<String, Object> options)
    {
        MySQLTable table = (MySQLTable) container;

        MySQLTableColumn column = new MySQLTableColumn(table);
        DBSDataType columnType = findBestDataType(table.getDataSource(), "varchar"); //$NON-NLS-1$
        column.setName(getNewColumnName(monitor, context, table));
        final String typeName = columnType == null ? "integer" : columnType.getName().toLowerCase();
        column.setTypeName(typeName); //$NON-NLS-1$
        column.setMaxLength(columnType != null && columnType.getDataKind() == DBPDataKind.STRING ? 100 : 0);
        column.setValueType(columnType == null ? Types.INTEGER : columnType.getTypeID());
        column.setOrdinalPosition(table.getCachedAttributes().size() + 1);
        column.setFullTypeName(DBUtils.getFullTypeName(column));
        return column;
    }

    @Override
    protected void addObjectModifyActions(DBRProgressMonitor monitor, DBCExecutionContext executionContext, List<DBEPersistAction> actionList, ObjectChangeCommand command, Map<String, Object> options)
    {
        final MySQLTableColumn column = command.getObject();

        actionList.add(
            new SQLDatabasePersistAction(
                "Modify column",
                "ALTER TABLE " + column.getTable().getFullyQualifiedName(DBPEvaluationContext.DDL) + " MODIFY COLUMN " + getNestedDeclaration(monitor, column.getTable(), command, options))); //$NON-NLS-1$ //$NON-NLS-2$
    }

    @Override
    public void renameObject(DBECommandContext commandContext, MySQLTableColumn object, String newName) throws DBException {
        processObjectRename(commandContext, object, newName);
    }

    @Override
    protected void addObjectRenameActions(DBRProgressMonitor monitor, DBCExecutionContext executionContext, List<DBEPersistAction> actions, ObjectRenameCommand command, Map<String, Object> options)
    {
        final MySQLTableColumn column = command.getObject();

        actions.add(<commit_msg>MySQL table column copy<commit_after>/*
 * DBeaver - Universal Database Manager
 * Copyright (C) 2010-2019 <NAME> (<EMAIL>)
 * Copyright (C) 2011-2012 <NAME> (<EMAIL>)
 *
 * 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.mysql.edit;

import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.ext.mysql.MySQLConstants;
import org.jkiss.dbeaver.ext.mysql.model.MySQLTable;
import org.jkiss.dbeaver.ext.mysql.model.MySQLTableBase;
import org.jkiss.dbeaver.ext.mysql.model.MySQLTableColumn;
import org.jkiss.dbeaver.model.DBPDataKind;
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.DBEObjectReorderer;
import org.jkiss.dbeaver.model.edit.DBEPersistAction;
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
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.DBSDataType;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.model.struct.cache.DBSObjectCache;
import org.jkiss.utils.CommonUtils;

import java.sql.Types;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * MySQL table column manager
 */
public class MySQLTableColumnManager extends SQLTableColumnManager<MySQLTableColumn, MySQLTableBase>
    implements DBEObjectRenamer<MySQLTableColumn>, DBEObjectReorderer<MySQLTableColumn>
{

    private final ColumnModifier<MySQLTableColumn> MySQLDataTypeModifier = (monitor, column, sql, command) ->
        sql.append(' ').append(column.getFullTypeName());

    private final ColumnModifier<MySQLTableColumn> CharsetModifier = (monitor, column, sql, command) -> {
        if (column.getDataKind() == DBPDataKind.STRING && column.getCharset() != null) {
            sql.append(" CHARACTER SET ").append(column.getCharset().getName()); //$NON-NLS-1$
        }
    };

    private final ColumnModifier<MySQLTableColumn> CollationModifier = (monitor, column, sql, command) -> {
        if (column.getDataKind() == DBPDataKind.STRING && column.getCollation() != null) {
            sql.append(" COLLATE ").append(column.getCollation().getName()); //$NON-NLS-1$
        }
    };

    private final ColumnModifier<MySQLTableColumn> ExtraInfoModifier = (monitor, column, sql, command) -> {
        if (!CommonUtils.isEmpty(column.getExtraInfo())) {
            if (MySQLConstants.EXTRA_INFO_VIRTUAL_GENERATED.equalsIgnoreCase(column.getExtraInfo())) {
                if (!CommonUtils.isEmpty(column.getGenExpression())) {
                    sql.append(" GENERATED ALWAYS AS (").append(column.getGenExpression()).append(") VIRTUAL"); //$NON-NLS-1$ //$NON-NLS-2$
                } else {
                    log.debug("No virtual column generate expression found for " + column.getName());
                }
            } else {
                sql.append(" ").append(column.getExtraInfo()); //$NON-NLS-1$
            }
        }
    };

    @Nullable
    @Override
    public DBSObjectCache<? extends DBSObject, MySQLTableColumn> getObjectsCache(MySQLTableColumn object)
    {
        return object.getParentObject().getContainer().getTableCache().getChildrenCache(object.getParentObject());
    }

    protected ColumnModifier[] getSupportedModifiers(MySQLTableColumn column, Map<String, Object> options)
    {
        return new ColumnModifier[] {MySQLDataTypeModifier, CharsetModifier, CollationModifier, DefaultModifier, ExtraInfoModifier, NullNotNullModifier};
    }

    @Override
    public StringBuilder getNestedDeclaration(DBRProgressMonitor monitor, MySQLTableBase owner, DBECommandAbstract<MySQLTableColumn> command, Map<String, Object> options)
    {
        StringBuilder decl = super.getNestedDeclaration(monitor, owner, command, options);
        final MySQLTableColumn column = command.getObject();
        if (column.isAutoGenerated() &&
            (CommonUtils.isEmpty(column.getExtraInfo()) || !column.getExtraInfo().toLowerCase(Locale.ENGLISH).contains(MySQLConstants.EXTRA_AUTO_INCREMENT)))
        {
            decl.append(" AUTO_INCREMENT"); //$NON-NLS-1$
        }
        if (!CommonUtils.isEmpty(column.getComment())) {
            decl.append(" COMMENT ").append(SQLUtils.quoteString(column, column.getComment())); //$NON-NLS-1$
        }
        return decl;
    }

    @Override
    protected MySQLTableColumn createDatabaseObject(final DBRProgressMonitor monitor, final DBECommandContext context, final Object container, Object copyFrom, Map<String, Object> options) throws DBException {
        MySQLTable table = (MySQLTable) container;

        MySQLTableColumn column;
        if (copyFrom instanceof MySQLTableColumn) {
            column = new MySQLTableColumn(monitor, table, (MySQLTableColumn)copyFrom);
        } else {
            column = new MySQLTableColumn(table);
            DBSDataType columnType = findBestDataType(table.getDataSource(), "varchar"); //$NON-NLS-1$
            column.setName(getNewColumnName(monitor, context, table));
            final String typeName = columnType == null ? "integer" : columnType.getName().toLowerCase();
            column.setTypeName(typeName); //$NON-NLS-1$
            column.setMaxLength(columnType != null && columnType.getDataKind() == DBPDataKind.STRING ? 100 : 0);
            column.setValueType(columnType == null ? Types.INTEGER : columnType.getTypeID());
            column.setOrdinalPosition(table.getCachedAttributes().size() + 1);
            column.setFullTypeName(DBUtils.getFullTypeName(column));
        }
        return column;
    }

    @Override
    protected void addObjectModifyActions(DBRProgressMonitor monitor, DBCExecutionContext executionContext, List<DBEPersistAction> actionList, ObjectChangeCommand command, Map<String, Object> options)
    {
        final MySQLTableColumn column = command.getObject();

        actionList.add(
            new SQLDatabasePersistAction(
                "Modify column",
                "ALTER TABLE " + column.getTable().getFullyQualifiedName(DBPEvaluationContext.DDL) + " MODIFY COLUMN " + getNestedDeclaration(monitor, column.getTable(), command, options))); //$NON-NLS-1$ //$NON-NLS-2$
    }

    @Override
    public void renameObject(DBECommandContext commandContext, MySQLTableColumn object, String newName) throws DBException {
        processObjectRename(commandContext, object, newName);
    }

    @Override
    protected void addObjectRenameActions(DBRProgressMonitor monitor, DBCExecutionContext executionContext, List<DBEPersistAction> actions, ObjectRenameCommand command, Map<String, Object> options)
    {
        final MySQLTableColumn column = command.getObject();

        actions.add(
{'fraction_non_alphanumeric': 0.11209617838672846, 'fraction_numerical': 0.0048357848075760625, 'mean_word_length': 3.840702210663199, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2410595', 'n_tokens_mistral': 4336, 'n_tokens_neox': 4284, 'n_words': 877}