From f532129c36e255980af82ba3627096f084c019b5 Mon Sep 17 00:00:00 2001 From: Anastasiya <45152336+LonwoLonwo@users.noreply.github.com> Date: Mon, 28 Mar 2022 19:09:34 +0300 Subject: [PATCH] =?UTF-8?q?#15733=20ability=20to=20add=20recreate=20mappin?= =?UTF-8?q?g=20status=20for=20non=20existing=20tables=E2=80=A6=20(#15888)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #15733 ability to add recreate mapping status for non existing tables added; keep recreate status in task editor * #15733 keep create status for recreate table columns in tasks * #15733 check cache after table recreating; fix data import in the recreated table * #15733 add extra code comments * #15733 refactor update attribute mapping code --- .../database/DatabaseConsumerPageMapping.java | 62 ++++---- .../database/DatabaseMappingAttribute.java | 140 +++++++++--------- .../database/DatabaseMappingContainer.java | 16 +- .../database/DatabaseTransferConsumer.java | 7 +- .../database/DatabaseTransferUtils.java | 13 +- 5 files changed, 123 insertions(+), 115 deletions(-) diff --git a/plugins/org.jkiss.dbeaver.data.transfer.ui/src/org/jkiss/dbeaver/tools/transfer/ui/pages/database/DatabaseConsumerPageMapping.java b/plugins/org.jkiss.dbeaver.data.transfer.ui/src/org/jkiss/dbeaver/tools/transfer/ui/pages/database/DatabaseConsumerPageMapping.java index 38af6f4f8b..c1a79daf15 100644 --- a/plugins/org.jkiss.dbeaver.data.transfer.ui/src/org/jkiss/dbeaver/tools/transfer/ui/pages/database/DatabaseConsumerPageMapping.java +++ b/plugins/org.jkiss.dbeaver.data.transfer.ui/src/org/jkiss/dbeaver/tools/transfer/ui/pages/database/DatabaseConsumerPageMapping.java @@ -28,22 +28,12 @@ import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Tree; -import org.eclipse.swt.widgets.TreeColumn; -import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.swt.widgets.*; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.model.DBIcon; -import org.jkiss.dbeaver.model.DBPDataSource; -import org.jkiss.dbeaver.model.DBPDataSourceContainer; -import org.jkiss.dbeaver.model.DBPDataSourcePermission; -import org.jkiss.dbeaver.model.DBPEvaluationContext; -import org.jkiss.dbeaver.model.DBUtils; +import org.jkiss.dbeaver.model.*; import org.jkiss.dbeaver.model.app.DBPProject; import org.jkiss.dbeaver.model.edit.DBEPersistAction; import org.jkiss.dbeaver.model.exec.DBCExecutionContext; @@ -65,11 +55,7 @@ import org.jkiss.dbeaver.tools.transfer.registry.DataTransferAttributeTransforme import org.jkiss.dbeaver.tools.transfer.registry.DataTransferRegistry; import org.jkiss.dbeaver.tools.transfer.ui.internal.DTUIMessages; import org.jkiss.dbeaver.tools.transfer.ui.pages.DataTransferPageNodeSettings; -import org.jkiss.dbeaver.ui.DBeaverIcons; -import org.jkiss.dbeaver.ui.DefaultViewerToolTipSupport; -import org.jkiss.dbeaver.ui.SharedTextColors; -import org.jkiss.dbeaver.ui.UIIcon; -import org.jkiss.dbeaver.ui.UIUtils; +import org.jkiss.dbeaver.ui.*; import org.jkiss.dbeaver.ui.controls.CustomComboBoxCellEditor; import org.jkiss.dbeaver.ui.controls.ObjectContainerSelectorPanel; import org.jkiss.dbeaver.ui.controls.TreeContentProvider; @@ -79,9 +65,8 @@ import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.CommonUtils; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; public class DatabaseConsumerPageMapping extends DataTransferPageNodeSettings { @@ -530,10 +515,8 @@ public class DatabaseConsumerPageMapping extends DataTransferPageNodeSettings { return newName; } if (mapping instanceof DatabaseMappingContainer) { - if (mapping.getMappingType() == DatabaseMappingType.existing || mapping.getMappingType() == DatabaseMappingType.recreate) { - return ((DatabaseMappingContainer) mapping).getTarget(); - } - return mapping.getTargetName(); + DBSDataManipulator target = ((DatabaseMappingContainer) mapping).getTarget(); + return target != null ? target : mapping.getTargetName(); } else { if (mapping.getMappingType() == DatabaseMappingType.existing) { return ((DatabaseMappingAttribute) mapping).getTarget(); @@ -587,10 +570,16 @@ public class DatabaseConsumerPageMapping extends DataTransferPageNodeSettings { mappingTypes.add(mappingType.name()); } if (mapping instanceof DatabaseMappingContainer) { - if (mappingType == DatabaseMappingType.existing) { + if (mappingType == DatabaseMappingType.existing || mappingType == DatabaseMappingType.create) { + // Recreate can be used for not-existing in this moment tables if user will save this mapping in the task mappingTypes.add(DatabaseMappingType.recreate.name()); } else if (mappingType == DatabaseMappingType.recreate) { - mappingTypes.add(DatabaseMappingType.existing.name()); + // Depends on the existence of the target table + if (mapping.getTarget() != null) { + mappingTypes.add(DatabaseMappingType.existing.name()); + } else { + mappingTypes.add(DatabaseMappingType.create.name()); + } } } if (mapping instanceof DatabaseMappingAttribute) { @@ -623,7 +612,8 @@ public class DatabaseConsumerPageMapping extends DataTransferPageNodeSettings { try { DatabaseMappingObject mapping = (DatabaseMappingObject) element; DatabaseMappingType mappingType = DatabaseMappingType.valueOf(value.toString()); - if (mappingType == DatabaseMappingType.recreate) { + if (mapping.getMappingType() != DatabaseMappingType.recreate && mappingType == DatabaseMappingType.recreate) { + // Show this confirmation if mapping is not recreate at this moment boolean confirmed = UIUtils.confirmAction( getShell(), DTUIMessages.database_consumer_page_mapping_recreate_confirm_title, @@ -831,8 +821,13 @@ public class DatabaseConsumerPageMapping extends DataTransferPageNodeSettings { String unQuotedNameForSearch = DBUtils.getUnQuotedIdentifier(container.getDataSource(), name); for (DBSObject child : container.getChildren(new VoidProgressMonitor())) { if (child instanceof DBSDataManipulator && unQuotedNameForSearch.equalsIgnoreCase(child.getName())) { - containerMapping.setTarget((DBSDataManipulator)child); - containerMapping.refreshMappingType(getWizard().getRunnableContext(), DatabaseMappingType.existing, false); + containerMapping.setTarget((DBSDataManipulator) child); + if (forceRefresh && mapping.getMappingType() == DatabaseMappingType.recreate) { + // Keep container mapping type, refresh only attributes + containerMapping.refreshOnlyAttributesMappingTypes(getWizard().getRunnableContext(),false); + } else { + containerMapping.refreshMappingType(getWizard().getRunnableContext(), DatabaseMappingType.existing, false); + } DataTransferPipe pipeFromCurrentSelection = getPipeFromCurrentSelection(); if (pipeFromCurrentSelection != null) { IDataTransferConsumer consumer = pipeFromCurrentSelection.getConsumer(); @@ -845,9 +840,14 @@ public class DatabaseConsumerPageMapping extends DataTransferPageNodeSettings { } } } - containerMapping.refreshMappingType(getWizard().getRunnableContext(), DatabaseMappingType.create, forceRefresh); - ((DatabaseMappingContainer) mapping).setTarget(null); - ((DatabaseMappingContainer) mapping).setTargetName(name); + if (forceRefresh && mapping.getMappingType() == DatabaseMappingType.recreate) { + // Keep container mapping type, refresh only attributes + containerMapping.refreshOnlyAttributesMappingTypes(getWizard().getRunnableContext(),false); + } else { + containerMapping.refreshMappingType(getWizard().getRunnableContext(), DatabaseMappingType.create, forceRefresh); + ((DatabaseMappingContainer) mapping).setTarget(null); + ((DatabaseMappingContainer) mapping).setTargetName(name); + } } else { DatabaseMappingAttribute attrMapping = (DatabaseMappingAttribute) mapping; DBPDataSource targetDataSource = settings.getTargetDataSource(mapping); diff --git a/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseMappingAttribute.java b/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseMappingAttribute.java index 1b26a6660d..054c78de91 100644 --- a/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseMappingAttribute.java +++ b/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseMappingAttribute.java @@ -144,88 +144,84 @@ public class DatabaseMappingAttribute implements DatabaseMappingObject { } public void updateMappingType(DBRProgressMonitor monitor, boolean forceRefresh) throws DBException { - switch (parent.getMappingType()) { - case recreate: - case existing: { - if (mappingType == DatabaseMappingType.skip) { - // We already have mapping for the attribute with the skip type - break; - } - mappingType = DatabaseMappingType.unspecified; - if (parent.getTarget() instanceof DBSEntity) { - if (forceRefresh || CommonUtils.isEmpty(targetName)) { - targetName = getSourceLabelOrName(source, true); - } - DBSEntity targetEntity = (DBSEntity) parent.getTarget(); - List targetAttributes = targetEntity.getAttributes(monitor); - if (targetAttributes != null) { + if (mappingType == DatabaseMappingType.skip) { + // We already have mapping for the attribute with the skip type + return; + } + if (parent.getMappingType() == DatabaseMappingType.skip) { + mappingType = DatabaseMappingType.skip; + return; + } + + mappingType = DatabaseMappingType.unspecified; + if (parent.getTarget() instanceof DBSEntity) { + if (forceRefresh || CommonUtils.isEmpty(targetName)) { + targetName = getSourceLabelOrName(source, true); + } + DBSEntity targetEntity = (DBSEntity) parent.getTarget(); + List targetAttributes = targetEntity.getAttributes(monitor); + if (CommonUtils.isEmpty(targetAttributes) && targetEntity instanceof DBPRefreshableObject) { + // Reload table attributes cache. It can be empty after table deleting + ((DBPRefreshableObject) targetEntity).refreshObject(monitor); + targetAttributes = targetEntity.getAttributes(monitor); + } + if (targetAttributes != null) { + target = CommonUtils.findBestCaseAwareMatch( + targetAttributes, + DBUtils.getUnQuotedIdentifier(targetEntity.getDataSource(), targetName), + DBSEntityAttribute::getName + ); + } else { + target = null; + } + + if (source instanceof StreamDataImporterColumnInfo && targetAttributes != null) { + StreamDataImporterColumnInfo source = (StreamDataImporterColumnInfo) this.source; + + if (!source.isMappingMetadataPresent()) { + List suitableTargetAttributes = targetAttributes + .stream() + .filter(attr -> !DBUtils.isPseudoAttribute(attr) && !DBUtils.isHiddenObject(attr)) + .sorted(Comparator.comparing(DBSEntityAttribute::getOrdinalPosition)) + .collect(Collectors.toList()); + + if (source.getOrdinalPosition() < suitableTargetAttributes.size()) { + DBSEntityAttribute targetAttribute = suitableTargetAttributes.get(source.getOrdinalPosition()); target = CommonUtils.findBestCaseAwareMatch( targetAttributes, DBUtils.getUnQuotedIdentifier(targetEntity.getDataSource(), targetName), DBSEntityAttribute::getName ); - } else { - target = null; - } - - if (source instanceof StreamDataImporterColumnInfo && targetAttributes != null) { - StreamDataImporterColumnInfo source = (StreamDataImporterColumnInfo) this.source; - - if (!source.isMappingMetadataPresent()) { - List suitableTargetAttributes = targetAttributes - .stream() - .filter(attr -> !DBUtils.isPseudoAttribute(attr) && !DBUtils.isHiddenObject(attr)) - .sorted(Comparator.comparing(DBSEntityAttribute::getOrdinalPosition)) - .collect(Collectors.toList()); - - if (source.getOrdinalPosition() < suitableTargetAttributes.size()) { - DBSEntityAttribute targetAttribute = suitableTargetAttributes.get(source.getOrdinalPosition()); - target = CommonUtils.findBestCaseAwareMatch( - targetAttributes, - DBUtils.getUnQuotedIdentifier(targetEntity.getDataSource(), targetName), - DBSEntityAttribute::getName - ); - if (target != null && !targetAttribute.getName().equalsIgnoreCase(target.getName())) { - // In case of violated order (some columns are missing in the source, for example), if it turned out to find a suitable column by name - targetName = target.getName(); - } else { - targetName = targetAttribute.getName(); - } - } - } - - if (target != null) { - source.setTypeName(target.getTypeName()); - source.setMaxLength(target.getMaxLength()); - source.setDataKind(target.getDataKind()); - } - } - if (this.target != null) { - if (parent.getMappingType() == DatabaseMappingType.recreate) { - mappingType = DatabaseMappingType.create; + if (target != null && !targetAttribute.getName().equalsIgnoreCase(target.getName())) { + // In case of violated order (some columns are missing in the source, for example), if it turned out to find a suitable column by name + targetName = target.getName(); } else { - mappingType = DatabaseMappingType.existing; + targetName = targetAttribute.getName(); } - } else { - mappingType = DatabaseMappingType.create; } } - break; + + if (target != null) { + source.setTypeName(target.getTypeName()); + source.setMaxLength(target.getMaxLength()); + source.setDataKind(target.getDataKind()); + } } - case create: - if (mappingType != DatabaseMappingType.skip) { // We already have mapping for the attribute with the skip type + if (this.target != null) { + if (parent.getMappingType() == DatabaseMappingType.recreate) { mappingType = DatabaseMappingType.create; + } else { + mappingType = DatabaseMappingType.existing; } - if (forceRefresh || CommonUtils.isEmpty(targetName)) { - targetName = getSourceLabelOrName(source, true); - } - break; - case skip: - mappingType = DatabaseMappingType.skip; - break; - default: - mappingType = DatabaseMappingType.unspecified; - break; + } else { + mappingType = DatabaseMappingType.create; + } + } else { + // Case recreate container mapping in the new table or just create + mappingType = DatabaseMappingType.create; + if (forceRefresh || CommonUtils.isEmpty(targetName)) { + targetName = getSourceLabelOrName(source, true); + } } if (mappingType == DatabaseMappingType.create && !CommonUtils.isEmpty(targetName)) { @@ -349,8 +345,8 @@ public class DatabaseMappingAttribute implements DatabaseMappingObject { } } - if (target != null && newMappingType == DatabaseMappingType.create) { - // Change create to existing. + if (target != null && newMappingType == DatabaseMappingType.create && parent.getMappingType() != DatabaseMappingType.recreate) { + // Change create to existing. Do not change mapping type for the recreate type newMappingType = DatabaseMappingType.existing; } else if (target == null && newMappingType == DatabaseMappingType.existing) { newMappingType = DatabaseMappingType.create; diff --git a/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseMappingContainer.java b/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseMappingContainer.java index b106e136cd..40430311c2 100644 --- a/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseMappingContainer.java +++ b/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseMappingContainer.java @@ -105,8 +105,16 @@ public class DatabaseMappingContainer implements DatabaseMappingObject { refreshMappingType(new VoidProgressMonitor(), mappingType, forceRefresh); } + public void refreshOnlyAttributesMappingTypes(DBRRunnableContext context, boolean forceRefresh) throws DBException { + refreshAttributesMappingTypes(new VoidProgressMonitor(), forceRefresh); + } + private void refreshMappingType(DBRProgressMonitor monitor, DatabaseMappingType mappingType, boolean forceRefresh) throws DBException { this.mappingType = mappingType; + refreshAttributesMappingTypes(monitor, forceRefresh); + } + + private void refreshAttributesMappingTypes(DBRProgressMonitor monitor, boolean forceRefresh) throws DBException { final Collection mappings = getAttributeMappings(monitor); if (!CommonUtils.isEmpty(mappings)) { for (DatabaseMappingAttribute attr : mappings) { @@ -179,11 +187,13 @@ public class DatabaseMappingContainer implements DatabaseMappingObject { switch (mappingType) { case existing: case recreate: - return target.getName(); - case create: + if (target != null) { + return target.getName(); + } return targetTableName; case skip: return DatabaseMappingAttribute.TARGET_NAME_SKIP; + case create: default: return targetTableName; } @@ -277,7 +287,7 @@ public class DatabaseMappingContainer implements DatabaseMappingObject { if (target != null && newMappingType == DatabaseMappingType.create) { // Change create to existing. newMappingType = DatabaseMappingType.existing; - } else if (target == null && (newMappingType == DatabaseMappingType.existing || newMappingType == DatabaseMappingType.recreate)) { + } else if (target == null && newMappingType == DatabaseMappingType.existing) { newMappingType = DatabaseMappingType.create; } refreshMappingType(context, newMappingType, false); diff --git a/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseTransferConsumer.java b/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseTransferConsumer.java index 5dc756a572..3b047515a6 100644 --- a/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseTransferConsumer.java +++ b/plugins/org.jkiss.dbeaver.data.transfer/src/org/jkiss/dbeaver/tools/transfer/database/DatabaseTransferConsumer.java @@ -35,7 +35,6 @@ import org.jkiss.dbeaver.model.navigator.DBNEvent; import org.jkiss.dbeaver.model.navigator.DBNUtils; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor; -import org.jkiss.dbeaver.model.sql.SQLState; import org.jkiss.dbeaver.model.sql.registry.SQLInsertReplaceMethodDescriptor; import org.jkiss.dbeaver.model.sql.registry.SQLInsertReplaceMethodRegistry; import org.jkiss.dbeaver.model.struct.*; @@ -653,10 +652,8 @@ public class DatabaseTransferConsumer implements IDataTransferConsumer actions = new ArrayList<>(); - if (containerMapping.getMappingType() == DatabaseMappingType.recreate) { + if (containerMapping.getMappingType() == DatabaseMappingType.recreate && containerMapping.getTarget() != null) { sql.append("DROP TABLE "); getTableFullName(schema, dataSource, sql, tableName); sql.append(dataSource.getSQLDialect().getScriptDelimiters()[0]); } - if (containerMapping.getMappingType() == DatabaseMappingType.create) { + if (containerMapping.getMappingType() == DatabaseMappingType.create || containerMapping.getMappingType() == DatabaseMappingType.recreate) { sql.append("CREATE TABLE "); getTableFullName(schema, dataSource, sql, tableName); sql.append("(\n"); @@ -230,7 +233,9 @@ public class DatabaseTransferUtils { DBSEntity table; DBECommand createCommand = null; - if (containerMapping.getMappingType() == DatabaseMappingType.create) { + if (containerMapping.getMappingType() == DatabaseMappingType.create || + (containerMapping.getMappingType() == DatabaseMappingType.recreate && containerMapping.getTarget() == null)) + { table = tableManager.createNewObject(monitor, commandContext, schema, null, options); tableFinalName = getTableFinalName(containerMapping.getTargetName(), tableClass, table); createCommand = tableManager.makeCreateCommand(table, options); -- GitLab