From 243decdb7903fb61e93180796de02aab679b17fb Mon Sep 17 00:00:00 2001 From: Sonia Zorba <zorba@oats.inaf.it> Date: Tue, 29 Aug 2017 16:53:33 +0200 Subject: [PATCH] Consistency checking improvements --- .../src/main/java/it/inaf/ia2/tsm/Column.java | 11 ++- .../java/it/inaf/ia2/tsm/ColumnHolder.java | 7 +- .../it/inaf/ia2/tsm/ConsistencyChecks.java | 41 ++++++++- .../ia2/tsm/InconsistentColumnProperty.java | 22 +++-- .../src/main/java/it/inaf/ia2/tsm/Table.java | 18 +++- .../java/it/inaf/ia2/tsm/TapSchemaLoader.java | 33 ++++--- .../java/it/inaf/ia2/tsm/TapSchemaMender.java | 21 +++-- .../java/it/inaf/ia2/tsm/WrongDataType.java | 91 +++++++++++++++++++ .../it/inaf/ia2/tsm/datalayer/DBBroker.java | 4 +- .../ia2/tsm/datalayer/DBBrokerTemplate.java | 53 ++++++++++- .../tsm/datalayer/mysql/MySQLDBBroker.java | 38 +++++++- .../tsm/datalayer/pgsql/PostgresDBBroker.java | 79 +++++++++++++++- .../it/inaf/ia2/tsm/model/ColumnModel.java | 33 +++++++ .../tsm/model/CommaSeparatedListAdapter.java | 59 ++++++++++++ .../it/inaf/ia2/tsm/model/TypesMapping.java | 20 ++++ .../resources/schema_definition/ivoa-1_1.xml | 34 +------ .../schema_definition/tap_schema-1.xml | 4 - .../schema_definition/tap_schema-1_1.xml | 2 - .../test/java/it/inaf/ia2/tsm/TestAll.java | 6 -- .../ia2/tsm/webapp/ConsistencyChecksBean.java | 10 +- .../ia2/tsm/webapp/TapSchemaEditingBean.java | 12 +++ .../inaf/ia2/tsm/webapp/TapSchemaLoader.java | 12 ++- .../src/main/webapp/consistencyChecks.xhtml | 48 ++++++++-- .../src/main/webapp/credentialsEditing.xhtml | 6 +- .../main/webapp/resources/js/async-loader.js | 3 + .../src/main/webapp/tapSchemaEditing.xhtml | 10 +- 26 files changed, 569 insertions(+), 108 deletions(-) create mode 100644 TASMAN-core/src/main/java/it/inaf/ia2/tsm/WrongDataType.java create mode 100644 TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/CommaSeparatedListAdapter.java diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Column.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Column.java index 96cf36c..dd168a0 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Column.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Column.java @@ -44,6 +44,9 @@ public class Column extends ChildEntity<Table> { public final static String UCD_KEY = "ucd"; public final static String UNIT_KEY = "unit"; + // Original datatype (computed from information_schema data), used for consistency checking + public final static String ORIGINAL_DATATYPE_KEY = "original_datatype"; + private static final long serialVersionUID = 9175956487892235521L; private static final Logger LOG = LoggerFactory.getLogger(Column.class); @@ -51,15 +54,17 @@ public class Column extends ChildEntity<Table> { private Key foreignKey; private Table parentTable; + private boolean mandatory; private Column() { // for serialization super(); } - protected Column(TapSchema tapSchema, Table table, String columnName) { + protected Column(TapSchema tapSchema, Table table, String columnName, boolean mandatory) { super(tapSchema, tapSchema.getTableModel(TapSchema.COLUMNS_TABLE), table.getColumnMetadata(columnName)); parentTable = table; + this.mandatory = mandatory; setStatus(Status.LOADED); } @@ -114,6 +119,10 @@ public class Column extends ChildEntity<Table> { return (boolean) getMetadata(PRIMARY_KEY); } + public boolean isMandatory() { + return mandatory; + } + @Override public int hashCode() { int hash = 7; diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ColumnHolder.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ColumnHolder.java index 8f782bb..57a870d 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ColumnHolder.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ColumnHolder.java @@ -24,7 +24,6 @@ package it.inaf.ia2.tsm; import java.io.Serializable; import java.util.Objects; -import java.util.regex.Pattern; /** * @@ -47,6 +46,12 @@ public class ColumnHolder implements Serializable { this.columnName = columnName; } + public ColumnHolder(Column column) { + this.schemaName = column.getParent().getParent().getName(); + this.tableName = column.getParent().getName(); + this.columnName = column.getName(); + } + public String getSchemaName() { return schemaName; } diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ConsistencyChecks.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ConsistencyChecks.java index 74aa204..7b34732 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ConsistencyChecks.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/ConsistencyChecks.java @@ -53,9 +53,13 @@ public class ConsistencyChecks implements Serializable { private final Map<String, Set<String>> tablesToAdd; private final Map<ColumnHolder, ColumnModel> missingColumns; private final Set<ColumnHolder> columnsToAdd; + private final List<WrongDataType> wrongDataTypes; private boolean missingObscore; private boolean obscoreToAdd; + // This will not consider an inconsistency: it is only used to display a warning + private final Set<ColumnHolder> unaddedOptionalColumns; + public ConsistencyChecks() { inconsistencies = new ArrayList<>(); unexisingSchemas = new HashSet<>(); @@ -66,6 +70,8 @@ public class ConsistencyChecks implements Serializable { tablesToAdd = new HashMap<>(); missingColumns = new HashMap<>(); columnsToAdd = new HashSet<>(); + unaddedOptionalColumns = new HashSet<>(); + wrongDataTypes = new ArrayList<>(); } public void addInconsistency(InconsistentColumnProperty problemDescription) { @@ -182,11 +188,44 @@ public class ConsistencyChecks implements Serializable { this.obscoreToAdd = obscoreToAdd; } + public void addUnaddedOptionalColumn(ColumnHolder columnHolder) { + unaddedOptionalColumns.add(columnHolder); + } + + public Set<ColumnHolder> getUnaddedOptionalColumns() { + return unaddedOptionalColumns; + } + + public void addWrongDataType(ColumnHolder columnHolder, String wrongDataType, String correctDataType, String adqlCorrectDataType, Integer size) { + // If datatype needs to be changed inconsistency on it doesn't make sense anymore. + Iterator<InconsistentColumnProperty> ite = inconsistencies.iterator(); + while (ite.hasNext()) { + InconsistentColumnProperty inconsistency = ite.next(); + if (inconsistency.getColumnHolder().equals(columnHolder) + && (inconsistency.getKey().equals(Column.DATATYPE_KEY) + || inconsistency.getKey().equals(Column.SIZE_KEY) + || inconsistency.getKey().equals(Column.ARRAYSIZE_KEY))) { + ite.remove(); + } + } + + WrongDataType wdt = new WrongDataType(columnHolder, wrongDataType, correctDataType, adqlCorrectDataType, size); + wrongDataTypes.add(wdt); + } + + public List<WrongDataType> getWrongDataTypes() { + return wrongDataTypes; + } + public boolean isInconsistent() { - return !inconsistencies.isEmpty() + return !inconsistencies.isEmpty() || !wrongDataTypes.isEmpty() || !unexisingSchemas.isEmpty() || !unexisingTables.isEmpty() || !unexistingColumns.isEmpty() || !missingTables.isEmpty() || !missingColumns.isEmpty() || !columnsToAdd.isEmpty() || !tablesToAdd.isEmpty() || obscoreToAdd || missingObscore; } + + public boolean isHasWarnings() { + return !unaddedOptionalColumns.isEmpty(); + } } diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/InconsistentColumnProperty.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/InconsistentColumnProperty.java index e368bed..fc567ab 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/InconsistentColumnProperty.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/InconsistentColumnProperty.java @@ -32,8 +32,7 @@ public class InconsistentColumnProperty implements Serializable { private static final long serialVersionUID = -5145865322582594970L; - private String tableCompleteName; - private String columnName; + private ColumnHolder columnHolder; private String key; private Object currentValue; private Object correctValue; @@ -41,22 +40,29 @@ public class InconsistentColumnProperty implements Serializable { private InconsistentColumnProperty() { } - public InconsistentColumnProperty(String tableCompleteName, String columnName, String key, Object currentValue, Object correctValue) { - this.tableCompleteName = tableCompleteName; - this.columnName = columnName; + public InconsistentColumnProperty(ColumnHolder columnHolder, String key, Object currentValue, Object correctValue) { + this.columnHolder = columnHolder; this.key = key; this.currentValue = currentValue; this.correctValue = correctValue; } + public ColumnHolder getColumnHolder() { + return columnHolder; + } + + public void setColumnHolder(ColumnHolder columnHolder) { + this.columnHolder = columnHolder; + } + public String getTableCompleteName() { - return tableCompleteName; + return String.format("%s.%s", columnHolder.getSchemaName(), columnHolder.getTableName()); } public String getColumnName() { - return columnName; + return columnHolder.getColumnName(); } - + public String getKey() { return key; } diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Table.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Table.java index a5a4a83..fb8388d 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Table.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/Table.java @@ -52,12 +52,15 @@ public class Table extends ChildEntity<Schema> implements EntitiesContainer<Colu private String simpleName; private Schema parentSchema; + // WARNING: this is different from tableModel inherited field. + private TableModel tableTableModel; + private Table() { // for serialization super(); } - private TableModel getModel() { + private TableModel getTableTableModel() { if (tapSchema.getName().equals(parentSchema.getName())) { return tapSchema.getTapSchemaModel().getTable(simpleName); } @@ -77,7 +80,9 @@ public class Table extends ChildEntity<Schema> implements EntitiesContainer<Colu columns = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); DBBroker broker = tapSchema.getDBBroker(schema.getName()); - columnsMetadata = broker.getAllColumnsMetadata(schema.getName(), tableSimpleName, getModel(), tapSchema.getVersion()); + tableTableModel = getTableTableModel(); + columnsMetadata = broker.getAllColumnsMetadata(schema.getName(), tableSimpleName, tableTableModel, tapSchema.getDataTypeMode()); + for (Map.Entry<String, Map<String, Object>> entry : columnsMetadata.entrySet()) { // Adding table names to columns metadata entry.getValue().put(Column.TABLE_NAME_KEY, schema.getName() + "." + tableSimpleName); @@ -103,6 +108,13 @@ public class Table extends ChildEntity<Schema> implements EntitiesContainer<Colu return getValue(TABLE_NAME_KEY, String.class); } + private boolean isMandatory(String columnName) { + if (tableTableModel != null) { + return tableTableModel.get(columnName).isMandatory(); + } + return false; + } + /** * {@inheritDoc } */ @@ -117,7 +129,7 @@ public class Table extends ChildEntity<Schema> implements EntitiesContainer<Colu } else { Column column = columns.get(columnName); if (column == null) { - column = new Column(tapSchema, this, columnName); + column = new Column(tapSchema, this, columnName, isMandatory(columnName)); columns.put(columnName, column); column.setStatus(Status.ADDED_NOT_PERSISTED); } else { diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaLoader.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaLoader.java index beebaec..2f75ae8 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaLoader.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaLoader.java @@ -28,10 +28,10 @@ import static it.inaf.ia2.tsm.TapSchema.KEY_COLUMNS_TABLE; import static it.inaf.ia2.tsm.TapSchema.SCHEMAS_TABLE; import static it.inaf.ia2.tsm.TapSchema.TABLES_TABLE; import it.inaf.ia2.tsm.datalayer.DBBroker; -import it.inaf.ia2.tsm.datalayer.DataTypeMode; import it.inaf.ia2.tsm.model.ColumnModel; import it.inaf.ia2.tsm.model.SchemaModel; import it.inaf.ia2.tsm.model.TableModel; +import it.inaf.ia2.tsm.model.TypeMapping; import it.inaf.ia2.tsm.model.TypesMapping; import java.sql.SQLException; import java.util.ArrayList; @@ -117,15 +117,27 @@ public class TapSchemaLoader { Column column = table.getChild(columnModel.getName()); - if (columnModel.isMandatory() && column == null) { + ColumnHolder ch = new ColumnHolder(schemaName, + table.getName(), columnModel.getName()); - ColumnHolder ch = new ColumnHolder(schemaName, - table.getName(), columnModel.getName()); - - if (table.isAddable(columnModel.getName())) { - consistencyChecks.addColumnToAdd(ch); - } else { - consistencyChecks.addMissingColumn(ch, columnModel); + if (column == null) { + if (columnModel.isMandatory()) { + if (table.isAddable(columnModel.getName())) { + consistencyChecks.addColumnToAdd(ch); + } else { + consistencyChecks.addMissingColumn(ch, columnModel); + } + } else if (table.isAddable(columnModel.getName())) { + consistencyChecks.addUnaddedOptionalColumn(ch); + } + } else { + // Data type checking + String originalDataType = (String) column.getMetadata(Column.ORIGINAL_DATATYPE_KEY); + String modelDataType = (String) column.getMetadata(Column.DATATYPE_KEY); + TypeMapping originalType = TypesMapping.getTypeMapping(originalDataType, tapSchema.getDataTypeMode()); + TypeMapping modelType = TypesMapping.getTypeMapping(modelDataType, tapSchema.getDataTypeMode()); + if (originalType.getJavaType() != modelType.getJavaType()) { + consistencyChecks.addWrongDataType(ch, originalDataType, modelDataType, columnModel.getType(), columnModel.getSize()); } } } @@ -203,8 +215,7 @@ public class TapSchemaLoader { Object correctValue = getCorrectValue(column, key); if (!Objects.equals(savedValue, correctValue)) { InconsistentColumnProperty inconsistentValue = new InconsistentColumnProperty( - column.getTableCompleteName(), - column.getName(), + new ColumnHolder(column), key, savedValue, correctValue diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaMender.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaMender.java index 18f1152..9a8c424 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaMender.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/TapSchemaMender.java @@ -47,15 +47,7 @@ public class TapSchemaMender { } public static void amendTapSchema(TapSchema tapSchema) throws SQLException { - int counter = 0; - while (tapSchema.getConsistencyChecks() != null && tapSchema.getConsistencyChecks().isInconsistent()) { - new TapSchemaMender(tapSchema).amendTapSchema(); - tapSchema.load(); - counter++; - if (counter > 20) { - throw new RuntimeException("Unable to amend TAP_SCHEMA"); - } - } + new TapSchemaMender(tapSchema).amendTapSchema(); } private void amendTapSchema() throws SQLException { @@ -63,6 +55,7 @@ public class TapSchemaMender { fixObscore(); createMissingTables(); createMissingColumns(); + fixDataTypes(); deleteUnexistingEntities(); addUnaddedTables(); addUnaddedColumns(); @@ -107,6 +100,16 @@ public class TapSchemaMender { } } + private void fixDataTypes() throws SQLException { + for (WrongDataType wrongDataType : consistencyChecks.getWrongDataTypes()) { + ColumnHolder columnHolder = wrongDataType.getColumnHolder(); + DBBroker broker = tapSchema.getDBBroker(columnHolder.getSchemaName()); + broker.alterDataType(columnHolder.getSchemaName(), + columnHolder.getTableName(), columnHolder.getColumnName(), + wrongDataType.getAdqlCorrectDataType(), wrongDataType.getSize()); + } + } + private void deleteUnexistingEntities() throws SQLException { String tapSchemaName = tapSchema.getName(); DBBroker tapSchemaDBBroker = tapSchema.getTapSchemaDBBroker(); diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/WrongDataType.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/WrongDataType.java new file mode 100644 index 0000000..cd429eb --- /dev/null +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/WrongDataType.java @@ -0,0 +1,91 @@ +/* + * _____________________________________________________________________________ + * + * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of + * Trieste INAF - IA2 Italian Center for Astronomical Archives + * _____________________________________________________________________________ + * + * Copyright (C) 2017 Istituto Nazionale di Astrofisica + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License Version 3 as published by the + * Free Software Foundation. + * + * This program 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 + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package it.inaf.ia2.tsm; + +import java.io.Serializable; + +/** + * + * @author Sonia Zorba {@literal <zorba at oats.inaf.it>} + */ +public class WrongDataType implements Serializable { + + private static final long serialVersionUID = 1541867434766884291L; + + private ColumnHolder columnHolder; + private String wrongDataType; + private String correctDataType; + private String adqlCorrectDataType; + private Integer size; + + public WrongDataType() { + } + + public WrongDataType(ColumnHolder columnHolder, String wrongDataType, String correctDataType, String adqlCorrectDataType, Integer size) { + this.columnHolder = columnHolder; + this.wrongDataType = wrongDataType; + this.correctDataType = correctDataType; + this.adqlCorrectDataType = adqlCorrectDataType; + this.size = size; + } + + public ColumnHolder getColumnHolder() { + return columnHolder; + } + + public void setColumnHolder(ColumnHolder columnHolder) { + this.columnHolder = columnHolder; + } + + public String getWrongDataType() { + return wrongDataType; + } + + public void setWrongDataType(String wrongDataType) { + this.wrongDataType = wrongDataType; + } + + public String getCorrectDataType() { + return correctDataType; + } + + public void setCorrectDataType(String correctDataType) { + this.correctDataType = correctDataType; + } + + public String getAdqlCorrectDataType() { + return adqlCorrectDataType; + } + + public void setAdqlCorrectDataType(String adqlCorrectDataType) { + this.adqlCorrectDataType = adqlCorrectDataType; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } +} diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBroker.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBroker.java index bd8f8ab..e60eea6 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBroker.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBroker.java @@ -56,7 +56,7 @@ public interface DBBroker { List<String> getAllColumnsNames(String schemaName, String tableName) throws SQLException; - Map<String, Map<String, Object>> getAllColumnsMetadata(String schemaName, String tableSimpleName, TableModel tableModel, String tapSchemaVersion) throws SQLException; + Map<String, Map<String, Object>> getAllColumnsMetadata(String schemaName, String tableSimpleName, TableModel tableModel, DataTypeMode dataTypeMode) throws SQLException; List<Key> getKeys(TapSchema tapSchema, String schemaName) throws SQLException; @@ -89,4 +89,6 @@ public interface DBBroker { Set<String> getKeysToRemoveFromUnexistingColumn(String tapSchemaName, ColumnHolder unexistingColumn) throws SQLException; void updateTapSchemaColumnValue(String tapSchemaName, String completeTableName, String columnName, String key, Object value) throws SQLException; + + void alterDataType(String schemaName, String tableName, String columnName, String adqlDataType, Integer size) throws SQLException; } diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerTemplate.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerTemplate.java index 538e7fd..af964c8 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerTemplate.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/DBBrokerTemplate.java @@ -781,17 +781,25 @@ public abstract class DBBrokerTemplate implements DBBroker { protected abstract Map<String, Map<String, Object>> getAllColumnsOriginalMetadata(String schemaName, String tableName) throws SQLException; @Override - public Map<String, Map<String, Object>> getAllColumnsMetadata(String schemaName, String tableName, TableModel tableModel, String tapSchemaVersion) throws SQLException { + public Map<String, Map<String, Object>> getAllColumnsMetadata(String schemaName, String tableName, TableModel tableModel, DataTypeMode dataTypeMode) throws SQLException { Map<String, Map<String, Object>> metadata = getAllColumnsOriginalMetadata(schemaName, tableName); - // Overriding data type from models + // Special behavior for data type if (tableModel != null) { for (Map.Entry<String, Map<String, Object>> entry : metadata.entrySet()) { + String columnName = entry.getKey(); + + // Saving original data type (used for consistency checking) + Map<String, Object> columnMetadata = entry.getValue(); + String originalDataType = (String) columnMetadata.get(Column.DATATYPE_KEY); + columnMetadata.put(Column.ORIGINAL_DATATYPE_KEY, originalDataType); + + // Override data type using model definition String adqlType = tableModel.get(columnName).getType(); - String tapDataType = TypesMapping.getDataType(adqlType, dataTypeMode); - entry.getValue().put(Column.DATATYPE_KEY, tapDataType); + String definedDataType = TypesMapping.getDataType(adqlType, dataTypeMode); + columnMetadata.put(Column.DATATYPE_KEY, definedDataType); } } @@ -1005,4 +1013,41 @@ public abstract class DBBrokerTemplate implements DBBroker { ps.executeUpdate(); } } + + protected String getEnumDefinition(List<String> enumValues) { + StringBuilder sb = new StringBuilder(); + + boolean first = true; + for (String enumValue : enumValues) { + if (!first) { + sb.append(','); + } + sb.append(String.format("'%s'", enumValue)); + first = false; + } + + return sb.toString(); + } + + private String getCheckConstraint(ColumnModel columnModel) { + if (columnModel.getMinValue() != null && columnModel.getMaxValue() != null) { + return String.format("CHECK (%s >= %s AND %s <= %s)", columnModel.getName(), + columnModel.getMinValue(), columnModel.getName(), columnModel.getMaxValue()); + } else if (columnModel.getMinValue() != null && columnModel.getMaxValue() == null) { + return String.format("CHECK (%s >= %s)", columnModel.getName(), columnModel.getMinValue()); + } else if (columnModel.getMinValue() == null && columnModel.getMaxValue() != null) { + return String.format("CHECK (%s <= %s)", columnModel.getName(), columnModel.getMaxValue()); + } + return null; + } + + protected void appendCheckConstraints(StringBuilder querySb, TableModel tableModel) { + for (ColumnModel cm : tableModel.getColumns()) { + String checkConstraint = getCheckConstraint(cm); + if (checkConstraint != null) { + querySb.append(",\n"); + querySb.append(checkConstraint); + } + } + } } diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java index 4c0443b..816e002 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/mysql/MySQLDBBroker.java @@ -50,6 +50,7 @@ import org.slf4j.LoggerFactory; public class MySQLDBBroker extends DBBrokerTemplate { private static final Logger LOG = LoggerFactory.getLogger(MySQLDBBroker.class); + private static final int DEFAULT_VARCHAR_SIZE = 255; public MySQLDBBroker(DataSource dataSource, DataTypeMode mode) { super(dataSource, '`', mode); @@ -170,10 +171,21 @@ public class MySQLDBBroker extends DBBrokerTemplate { querySb.append(cm.getName()); querySb.append(" "); - String mySQLType = TypesMapping.getMySQLTypeFromADQLType(cm.getType()).toUpperCase(); - querySb.append(mySQLType); - if (mySQLType.equals("VARCHAR") || mySQLType.equals("CHAR")) { - appendSize(querySb, cm.getSize()); + String mySQLType; + if (cm.getEnumValues() == null) { + mySQLType = TypesMapping.getMySQLTypeFromADQLType(cm.getType()).toUpperCase(); + querySb.append(mySQLType); + Integer size = cm.getSize(); + if (mySQLType.equals("VARCHAR") && size == null) { + size = DEFAULT_VARCHAR_SIZE; + } + if (size != null) { + appendSize(querySb, size); + } + } else { + querySb.append("ENUM ("); + querySb.append(getEnumDefinition(cm.getEnumValues())); + querySb.append(")"); } if (cm.isNullable()) { @@ -183,6 +195,7 @@ public class MySQLDBBroker extends DBBrokerTemplate { } } } + appendCheckConstraints(querySb, tableModel); querySb.append(")"); @@ -284,4 +297,21 @@ public class MySQLDBBroker extends DBBrokerTemplate { protected String getTableTypesQuery(String schemaName) { return "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = '" + schemaName + "'"; } + + @Override + public void alterDataType(String schemaName, String tableName, String columnName, String adqlDataType, Integer size) throws SQLException { + + String mySQLDataType = TypesMapping.getMySQLTypeFromADQLType(adqlDataType); + if (size != null) { + mySQLDataType = String.format("%s(%s)", mySQLDataType, size); + } + + String query = String.format("ALTER TABLE %s.%s MODIFY %s %s", escape(schemaName), escape(tableName), escape(columnName), mySQLDataType); + + try (Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement()) { + LOG.debug("Executing query: {}", query); + statement.executeUpdate(query); + } + } } diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/pgsql/PostgresDBBroker.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/pgsql/PostgresDBBroker.java index 81236c0..fe87f81 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/pgsql/PostgresDBBroker.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/datalayer/pgsql/PostgresDBBroker.java @@ -32,6 +32,7 @@ import it.inaf.ia2.tsm.model.ColumnModel; import it.inaf.ia2.tsm.model.TableModel; import it.inaf.ia2.tsm.model.TypesMapping; import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -64,8 +65,56 @@ public class PostgresDBBroker extends DBBrokerTemplate { return TypesMapping.getPostgresSQLTypeFromADQLType(adqlType); } + private boolean enumTypeExists(String enumName) throws SQLException { + + String query = "SELECT 1 FROM pg_type WHERE typname = ?"; + + try (Connection conn = dataSource.getConnection(); + PreparedStatement ps = conn.prepareStatement(query)) { + ps.setString(1, enumName); + + LOG.debug("Executing query {}", query); + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + return true; + } + } + } + return false; + } + + private void createEnumType(String enumName, List<String> values) throws SQLException { + + String query = String.format("CREATE TYPE %s AS ENUM (%s)", enumName, getEnumDefinition(values)); + + try (Connection conn = dataSource.getConnection(); + Statement stat = conn.createStatement()) { + + LOG.debug("Executing query {}", query); + stat.executeUpdate(query); + } + } + + private String getEnumName(String schemaName, String tableName, String columnName) { + // WARNING: for some reasons enum names are stored ONLY lower case in Postgres + return String.format("TASMAN_%s_%s_%s", schemaName, tableName, columnName).toLowerCase(); + } + @Override protected void createTable(String schemaName, TableModel tableModel, Connection conn) throws SQLException { + + // Checking for enum + Map<String, String> enumNames = new HashMap<>(); + for (ColumnModel column : tableModel.getColumns()) { + if (column.getEnumValues() != null) { + String enumName = getEnumName(schemaName, tableModel.getName(), column.getName()); + if (!enumTypeExists(enumName)) { + createEnumType(enumName, column.getEnumValues()); + } + enumNames.put(column.getName(), enumName); + } + } + StringBuilder querySb = new StringBuilder(); querySb.append("CREATE TABLE IF NOT EXISTS "); @@ -85,10 +134,14 @@ public class PostgresDBBroker extends DBBrokerTemplate { querySb.append(cm.getName()); querySb.append(" "); - String pgsqlType = TypesMapping.getPostgresSQLTypeFromADQLType(cm.getType()).toLowerCase(); - querySb.append(pgsqlType); - if (pgsqlType.equals("character varying") || pgsqlType.equals("character")) { - appendSize(querySb, cm.getSize()); + if (cm.getEnumValues() == null) { + String pgsqlType = TypesMapping.getPostgresSQLTypeFromADQLType(cm.getType()).toLowerCase(); + querySb.append(pgsqlType); + if (cm.getSize() != null) { + appendSize(querySb, cm.getSize()); + } + } else { + querySb.append(enumNames.get(cm.getName())); } if (cm.isNullable()) { @@ -98,6 +151,7 @@ public class PostgresDBBroker extends DBBrokerTemplate { } } } + appendCheckConstraints(querySb, tableModel); querySb.append(")"); @@ -382,4 +436,21 @@ public class PostgresDBBroker extends DBBrokerTemplate { protected String getAllTablesNamesQuery(String schemaName) { return String.format("SELECT tablename FROM pg_catalog.pg_tables where schemaname = '%s'", schemaName); } + + @Override + public void alterDataType(String schemaName, String tableName, String columnName, String adqlDataType, Integer size) throws SQLException { + + String psqlDataType = TypesMapping.getPostgresSQLTypeFromADQLType(adqlDataType); + if (size != null) { + psqlDataType = String.format("%s(%s)", psqlDataType, size); + } + + String query = String.format("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s", escape(schemaName), escape(tableName), escape(columnName), psqlDataType); + + try (Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement()) { + LOG.debug("Executing query: {}", query); + statement.executeUpdate(query); + } + } } diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/ColumnModel.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/ColumnModel.java index 904f9cd..670e0f0 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/ColumnModel.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/ColumnModel.java @@ -23,9 +23,11 @@ package it.inaf.ia2.tsm.model; import java.io.Serializable; +import java.util.List; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlTransient; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; /** * @@ -49,6 +51,9 @@ public class ColumnModel implements Serializable { private String utype; private String unit; private boolean principal; + private List<String> enumValues; + private Integer minValue; + private Integer maxValue; public ColumnModel() { // default values @@ -184,6 +189,34 @@ public class ColumnModel implements Serializable { this.principal = principal; } + @XmlElement(name = "enum-values", nillable = true, required = false) + @XmlJavaTypeAdapter(CommaSeparatedListAdapter.class) + public List<String> getEnumValues() { + return enumValues; + } + + public void setEnumValues(List<String> enumValues) { + this.enumValues = enumValues; + } + + @XmlElement(name = "min", nillable = true, required = false) + public Integer getMinValue() { + return minValue; + } + + public void setMinValue(Integer minValue) { + this.minValue = minValue; + } + + @XmlElement(name = "max", nillable = true, required = false) + public Integer getMaxValue() { + return maxValue; + } + + public void setMaxValue(Integer maxValue) { + this.maxValue = maxValue; + } + @XmlTransient public Object getDefaultValue() { if (defaultValueString == null) { diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/CommaSeparatedListAdapter.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/CommaSeparatedListAdapter.java new file mode 100644 index 0000000..450e734 --- /dev/null +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/CommaSeparatedListAdapter.java @@ -0,0 +1,59 @@ +/* + * _____________________________________________________________________________ + * + * INAF - OATS National Institute for Astrophysics - Astronomical Observatory of + * Trieste INAF - IA2 Italian Center for Astronomical Archives + * _____________________________________________________________________________ + * + * Copyright (C) 2017 Istituto Nazionale di Astrofisica + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License Version 3 as published by the + * Free Software Foundation. + * + * This program 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 + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package it.inaf.ia2.tsm.model; + +import java.util.Arrays; +import java.util.List; +import javax.xml.bind.annotation.adapters.XmlAdapter; + +/** + * + * @author Sonia Zorba {@literal <zorba at oats.inaf.it>} + */ +public class CommaSeparatedListAdapter extends XmlAdapter<String, List<String>> { + + @Override + public List<String> unmarshal(String value) throws Exception { + if (value == null) { + return null; + } + + return Arrays.asList(value.split(",")); + } + + @Override + public String marshal(List<String> values) throws Exception { + if (values == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (String value : values) { + if (!first) { + sb.append(","); + } + sb.append(value); + } + return sb.toString(); + } +} diff --git a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/TypesMapping.java b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/TypesMapping.java index ec8988e..484b480 100644 --- a/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/TypesMapping.java +++ b/TASMAN-core/src/main/java/it/inaf/ia2/tsm/model/TypesMapping.java @@ -111,6 +111,26 @@ public class TypesMapping { } } + public static TypeMapping getTypeMapping(String dataType, DataTypeMode mode) { + for (TypeMapping typeMapping : TYPES) { + switch (mode) { + case ADQL: + if (dataType.equals(typeMapping.getAdqlType())) { + return typeMapping; + } + break; + case VOTABLE: + if (dataType.equals(typeMapping.getVoTableType())) { + return typeMapping; + } + break; + default: + throw new UnsupportedOperationException("DataTypeMode " + mode + " not supported yet"); + } + } + throw new RuntimeException("Unable to get TypeMapping for datatype " + dataType + " [" + mode + "]"); + } + private static abstract class DataTypeFromDBTypeMapper { private final DataTypeMode mode; diff --git a/TASMAN-core/src/main/resources/schema_definition/ivoa-1_1.xml b/TASMAN-core/src/main/resources/schema_definition/ivoa-1_1.xml index 295aa94..8feb50a 100644 --- a/TASMAN-core/src/main/resources/schema_definition/ivoa-1_1.xml +++ b/TASMAN-core/src/main/resources/schema_definition/ivoa-1_1.xml @@ -25,7 +25,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <table name="obscore"> <column name="dataproduct_type"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Logical data product type (image etc.)</description> <standard>true</standard> @@ -33,10 +32,10 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <utype>ObsDataset.dataProductType</utype> <ucd>meta.id</ucd> <principal>true</principal> + <enum-values>image,cube,spectrum,sed,timeseries,visibility,event,measurements</enum-values> </column> <column name="dataproduct_subtype"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Data product specific type</description> <standard>true</standard> @@ -55,10 +54,11 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <utype>ObsDataset.calibLevel</utype> <ucd>meta.code;obs.calib</ucd> <principal>true</principal> + <min>0</min> + <max>4</max> </column> <column name="obs_collection"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <nullable>false</nullable> <description>Name of the data collection</description> @@ -70,7 +70,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="obs_id"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <nullable>false</nullable> <description>Internal ID given by the ObsTAP service</description> @@ -82,7 +81,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="obs_title"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Brief description of dataset in free format</description> <standard>true</standard> @@ -103,7 +101,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="obs_creator_name"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Name of the creator of the data</description> <standard>true</standard> @@ -114,7 +111,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="obs_creator_did"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>IVOA dataset identifier given by the creator</description> <standard>true</standard> @@ -135,7 +131,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="publisher_id"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>IVOA-ID for the Publisher</description> <standard>true</standard> @@ -146,7 +141,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="bib_reference"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Service bibliographic reference</description> <standard>true</standard> @@ -157,7 +151,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="data_rights"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Public/Secure/Proprietary</description> <standard>true</standard> @@ -168,7 +161,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="obs_publisher_did"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <nullable>false</nullable> <description>Dataset identifier given by the publisher</description> @@ -180,7 +172,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="access_url"> <type>CLOB</type> - <size>255</size> <updatable>true</updatable> <description>URL used to access (download) dataset</description> <standard>true</standard> @@ -191,7 +182,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="access_format"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Content format of the dataset</description> <standard>true</standard> @@ -214,7 +204,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="target_name"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Astronomical object observed, if any</description> <standard>true</standard> @@ -225,7 +214,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="target_class"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Class of the Target object as in SSA</description> <standard>true</standard> @@ -272,7 +260,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="s_region"> <type>REGION</type> - <size>255</size> <updatable>true</updatable> <description>Sky region covered by the data product (expressed in ICRS frame)</description> <standard>true</standard> @@ -303,7 +290,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="s_ucd"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>UCD for the nature of the spatial axis (pos or u,v data)</description> <standard>true</standard> @@ -314,7 +300,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="s_unit"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Unit used for spatial axis</description> <standard>true</standard> @@ -358,7 +343,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="s_calib_status"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Type of calibration along the spatial axis</description> <standard>true</standard> @@ -436,7 +420,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="t_calib_status"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Type of time coordinate calibration</description> <standard>true</standard> @@ -468,7 +451,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="t_refpos"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Time Axis Reference Position as defined in STC REC</description> <standard>true</standard> @@ -560,7 +542,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="em_ucd"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Nature of the spectral axis</description> <standard>true</standard> @@ -571,7 +552,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="em_unit"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Units along the spectral axis</description> <standard>true</standard> @@ -582,7 +562,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="em_calib_status"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Type of spectral coord calibration</description> <standard>true</standard> @@ -593,7 +572,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="o_ucd"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>UCD of the observable axis (e.g. phot.flux.density, phot.count, etc.)</description> <standard>true</standard> @@ -604,7 +582,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="o_unit"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Units used for the observable values</description> <standard>true</standard> @@ -615,7 +592,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="o_calib_status"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Type of calibration for the observable coordinate</description> <standard>true</standard> @@ -637,7 +613,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="pol_states"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>List of polarization states present in the data file or NULL if not applicable</description> <standard>true</standard> @@ -658,7 +633,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="facility_name"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Name of the facility used for this observation</description> <standard>true</standard> @@ -669,7 +643,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="instrument_name"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>The name of the instrument used for the observation</description> <standard>true</standard> @@ -680,7 +653,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="proposal_id"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>Identifier of proposal to which observation belongs</description> <standard>false</standard> diff --git a/TASMAN-core/src/main/resources/schema_definition/tap_schema-1.xml b/TASMAN-core/src/main/resources/schema_definition/tap_schema-1.xml index 07dc153..85d28d9 100644 --- a/TASMAN-core/src/main/resources/schema_definition/tap_schema-1.xml +++ b/TASMAN-core/src/main/resources/schema_definition/tap_schema-1.xml @@ -34,7 +34,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="utype"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>lists the utypes of schemas in the tableset</description> <standard>true</standard> @@ -75,7 +74,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="utype"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>lists the utype of tables in the tableset</description> <standard>true</standard> @@ -131,7 +129,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="utype"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>lists the utypes of columns in the tableset</description> <standard>true</standard> @@ -208,7 +205,6 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. </column> <column name="utype"> <type>VARCHAR</type> - <size>255</size> <updatable>true</updatable> <description>lists the utype of keys in the tableset</description> <standard>true</standard> diff --git a/TASMAN-core/src/main/resources/schema_definition/tap_schema-1_1.xml b/TASMAN-core/src/main/resources/schema_definition/tap_schema-1_1.xml index f5b8a73..ca0050a 100644 --- a/TASMAN-core/src/main/resources/schema_definition/tap_schema-1_1.xml +++ b/TASMAN-core/src/main/resources/schema_definition/tap_schema-1_1.xml @@ -34,13 +34,11 @@ Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <type>VARCHAR</type> <updatable>false</updatable> <key>arraysize</key> - <size>255</size> <standard>true</standard> </column> <column name="xtype"> <type>VARCHAR</type> <updatable>true</updatable> - <size>255</size> <standard>true</standard> </column> <column name="column_index"> diff --git a/TASMAN-core/src/test/java/it/inaf/ia2/tsm/TestAll.java b/TASMAN-core/src/test/java/it/inaf/ia2/tsm/TestAll.java index ee2b2b2..3cafafd 100644 --- a/TASMAN-core/src/test/java/it/inaf/ia2/tsm/TestAll.java +++ b/TASMAN-core/src/test/java/it/inaf/ia2/tsm/TestAll.java @@ -459,12 +459,6 @@ public class TestAll { operations = new UpdateOperations(tapSchema); assertFalse(operations.getHasOperations()); - // Checking size and arraysize detection - Column descriptionColumn = tapSchema.getChild(tapSchema.getName()).getChild("columns").getChild("utype"); - assertEquals("char", descriptionColumn.getProperty("datatype").getValue(String.class)); - assertEquals(255, descriptionColumn.getProperty("size").getValue(Integer.class)); - assertEquals("255*", descriptionColumn.getProperty("arraysize").getValue(String.class)); - // reloading LOG.debug("----- Reloading saved TAP_SCHEMA -----"); tapSchema = new TapSchema(dbWrapper, settings, true); diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/ConsistencyChecksBean.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/ConsistencyChecksBean.java index ec52620..47f7616 100644 --- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/ConsistencyChecksBean.java +++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/ConsistencyChecksBean.java @@ -53,14 +53,14 @@ public class ConsistencyChecksBean implements Serializable { this.tapSchema = tapSchema; } - public boolean isTapSchemaContainsOnlyTapSchema() { - return tapSchema.getChildren().size() == 1 - && tapSchema.getChildren().get(0).getName().equals(tapSchema.getName()); - } - public String proceed() throws SQLException { TapSchemaMender.amendTapSchema(tapSchema); tapSchema.save(); + tapSchema.load(); + if (tapSchema.getConsistencyChecks().isInconsistent()) { + // Show inconsistencies again + return null; + } tapSchemaEditingBean.setTapSchema(tapSchema); return "tapSchemaEditing.xhtml?faces-redirect=true"; } diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java index e4cbfee..e404102 100644 --- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java +++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaEditingBean.java @@ -404,6 +404,18 @@ public class TapSchemaEditingBean implements Serializable { } } + public boolean isSchemaRemovable(Schema schema) { + return !schema.getName().equals(tapSchema.getName()) && !schema.getName().equals("ivoa"); + } + + public boolean isColumnRemovable(Column column) { + boolean parentSchemaRemovable = isSchemaRemovable(column.getParent().getParent()); + if (!parentSchemaRemovable) { + return !column.isMandatory(); + } + return true; + } + public void reload() { if (tapSchema.exists()) { diff --git a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaLoader.java b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaLoader.java index 0c3559d..9461743 100644 --- a/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaLoader.java +++ b/TASMAN-webapp/src/main/java/it/inaf/ia2/tsm/webapp/TapSchemaLoader.java @@ -22,6 +22,7 @@ */ package it.inaf.ia2.tsm.webapp; +import it.inaf.ia2.tsm.ConsistencyChecks; import it.inaf.ia2.tsm.TapSchema; import it.inaf.ia2.tsm.TapSchemaSettings; import it.inaf.ia2.tsm.datalayer.DBBroker; @@ -84,14 +85,22 @@ public class TapSchemaLoader implements Serializable { DataTypeMode dataTypeMode = SchemaModels.getTapSchemaModel(tapCredentials.getTapSchemaVersion()).getDataTypeMode(); DBBroker broker = DBBrokerFactory.getDBBroker(dbWrapper.getTapSchemaDataSourceWrapper(), dataTypeMode); boolean tapSchemaExists = false; + boolean ivoaSchemaExists = false; for (String schemaName : broker.getAllSchemaNames()) { if (schemaName.equals(tapCredentials.getTapSchemaName())) { tapSchemaExists = true; + } + // Check for ivoa schema existence only if the user wants obscore + if (tapCredentials.isHasObscore() && schemaName.equals("ivoa")) { + ivoaSchemaExists = true; + } + if (tapSchemaExists && ivoaSchemaExists) { break; } } CustomPartialResponseWriter.getCurrentInstance().addCustomJSUpdate("tap_schema_existence", String.valueOf(tapSchemaExists)); + CustomPartialResponseWriter.getCurrentInstance().addCustomJSUpdate("ivoa_schema_existence", String.valueOf(ivoaSchemaExists)); if (tapSchemaExists) { edit(); @@ -174,7 +183,8 @@ public class TapSchemaLoader implements Serializable { } public String openLoaded() { - if (loadedTapSchema.getConsistencyChecks().isInconsistent()) { + ConsistencyChecks checks = loadedTapSchema.getConsistencyChecks(); + if (checks != null && (checks.isInconsistent() || checks.isHasWarnings())) { consistencyChecksBean.setTapSchema(loadedTapSchema); return "consistencyChecks.xhtml?faces-redirect=true"; } else { diff --git a/TASMAN-webapp/src/main/webapp/consistencyChecks.xhtml b/TASMAN-webapp/src/main/webapp/consistencyChecks.xhtml index 80e28b2..36dbd1c 100644 --- a/TASMAN-webapp/src/main/webapp/consistencyChecks.xhtml +++ b/TASMAN-webapp/src/main/webapp/consistencyChecks.xhtml @@ -11,7 +11,13 @@ <div class="container"> <div class="row"> <div class="col-xs-12"> - <h1>Consistency problems detected in #{consistency.tapSchema.name}</h1> + <h:panelGroup rendered="#{consistency.tapSchema.consistencyChecks.inconsistent}"> + <h1>Consistency problems detected in #{consistency.tapSchema.name}</h1> + </h:panelGroup> + <h:panelGroup rendered="#{!consistency.tapSchema.consistencyChecks.inconsistent and consistency.tapSchema.consistencyChecks.hasWarnings}"> + <h1>Warnings - #{consistency.tapSchema.name}</h1> + </h:panelGroup> + <h:form id="main"> <h:panelGroup rendered="#{consistency.tapSchema.consistencyChecks.inconsistencies.size() gt 0}"> @@ -116,21 +122,51 @@ </ul> </h:panelGroup> + <h:panelGroup rendered="#{consistency.tapSchema.consistencyChecks.wrongDataTypes.size() gt 0}"> + <h2>Wrong data type in original table</h2> + <table class="table table-bordered"> + <thead> + <tr> + <th>Schema</th> + <th>Table</th> + <th>Column</th> + <th>Wrong data type</th> + <th>Correct data type</th> + </tr> + </thead> + <tbody> + <ui:repeat value="#{consistency.tapSchema.consistencyChecks.wrongDataTypes}" var="wdt"> + <tr> + <td>${wdt.columnHolder.schemaName}</td> + <td>${wdt.columnHolder.tableName}</td> + <td>${wdt.columnHolder.columnName}</td> + <td class="text-danger">${wdt.wrongDataType}</td> + <td class="text-success">${wdt.correctDataType}</td> + </tr> + </ui:repeat> + </tbody> + </table> + </h:panelGroup> + <h:panelGroup rendered="#{consistency.tapSchema.consistencyChecks.missingObscore or consistency.tapSchema.consistencyChecks.obscoreToAdd}"> <h2>ObsCore to add</h2> <span class="glyphicon glyphicon-check"></span> </h:panelGroup> <br/> - <h:panelGroup rendered="#{consistency.tapSchemaContainsOnlyTapSchema}" layout="block" class="alert alert-danger text-center"> - <span class="glyphicon glyphicon-warning-sign"></span> - <strong>If you proceed this TAP_SCHEMA will contain only itself! You may have selected wrong source credentials.</strong> + <h:panelGroup rendered="#{consistency.tapSchema.consistencyChecks.unaddedOptionalColumns.size() gt 0}"> + <h2>Unadded optional columns</h2> + <ul> + <ui:repeat value="#{consistency.tapSchema.consistencyChecks.unaddedOptionalColumns.toArray()}" var="column"> + <li>${column}</li> + </ui:repeat> + </ul> </h:panelGroup> - <div class="alert alert-warning text-center"> + <h:panelGroup rendered="#{consistency.tapSchema.consistencyChecks.inconsistent}" layout="block" class="alert alert-warning text-center"> <span class="glyphicon glyphicon-warning-sign"></span> <strong>If you proceed the TAP_SCHEMA Manager will fix these values.</strong> - </div> + </h:panelGroup> <div class="text-center"> <h:commandLink action="#{consistency.back()}" class="btn btn-default"> diff --git a/TASMAN-webapp/src/main/webapp/credentialsEditing.xhtml b/TASMAN-webapp/src/main/webapp/credentialsEditing.xhtml index 577bccd..f20e2ae 100644 --- a/TASMAN-webapp/src/main/webapp/credentialsEditing.xhtml +++ b/TASMAN-webapp/src/main/webapp/credentialsEditing.xhtml @@ -300,7 +300,11 @@ <h4 class="modal-title">Create TAP_SCHEMA</h4> </div> <div class="modal-body"> - The TAP_SCHEMA <strong>#{tapSchemaLoader.tapCredentials.tapSchemaName}</strong> doesn't exists. Do you want to create it? + <p>The TAP_SCHEMA <strong>#{tapSchemaLoader.tapCredentials.tapSchemaName}</strong> doesn't exists. Do you want to create it?</p> + <p class="ivoa-schema-warning text-warning hide"> + <span class="glyphicon glyphicon-alert"></span> + <strong>WARNING</strong>: existing ivoa schema detected. Next changes could alter an existing ObsCore table. + </p> </div> <div class="modal-footer"> <h:commandButton class="btn btn-success" value="Yes" action="#{tapSchemaLoader.create()}"> diff --git a/TASMAN-webapp/src/main/webapp/resources/js/async-loader.js b/TASMAN-webapp/src/main/webapp/resources/js/async-loader.js index 25697d8..e91652e 100644 --- a/TASMAN-webapp/src/main/webapp/resources/js/async-loader.js +++ b/TASMAN-webapp/src/main/webapp/resources/js/async-loader.js @@ -34,6 +34,9 @@ if ($tsExistenceEl.text() === 'true') { periodicCheck(); } else { + var $ivoaExistenceEl = $(event.responseXML).find('jsupdate[src="ivoa_schema_existence"]'); + var ivoaSchemaExists = $ivoaExistenceEl.text() === 'true'; + $('#modal-confirm-ts-creation .ivoa-schema-warning').toggleClass('hide', !ivoaSchemaExists) $('#modal-confirm-ts-creation').modal('show'); } } diff --git a/TASMAN-webapp/src/main/webapp/tapSchemaEditing.xhtml b/TASMAN-webapp/src/main/webapp/tapSchemaEditing.xhtml index 387d45d..9de0d52 100644 --- a/TASMAN-webapp/src/main/webapp/tapSchemaEditing.xhtml +++ b/TASMAN-webapp/src/main/webapp/tapSchemaEditing.xhtml @@ -77,11 +77,11 @@ <ul class="nav nav-tabs" id="schemas" role="tablist"> <ui:repeat value="#{tapSchemaEditing.tapSchema.addedOrRemovedChildren}" var="schema"> - <li role="presentation" class="removable-tab #{schema.name eq tapSchemaEditing.tapSchema.name ? 'unremovable-tab': ''} #{tapSchemaEditing.selectedSchema.name eq schema.name ? 'active': ''} #{tapSchemaEditing.toRemove(schema) ? 'to-remove' : ''}"> + <li role="presentation" class="removable-tab #{tapSchemaEditing.isSchemaRemovable(schema) ? '': 'unremovable-tab'} #{tapSchemaEditing.selectedSchema.name eq schema.name ? 'active': ''} #{tapSchemaEditing.toRemove(schema) ? 'to-remove' : ''}"> <h:commandLink role="tab" action="#{tapSchemaEditing.setSelectedSchema(schema)}"> <span class="#{tapSchemaEditing.toRemove(schema) ? 'strikeout':''}">#{schema.name}</span> <f:ajax execute="@form" render="@form" /> - <h:commandButton class="remove-btn" rendered="#{!tapSchemaEditing.toRemove(schema) and schema.name ne tapSchemaEditing.tapSchema.name}" action="#{tapSchemaEditing.tapSchema.removeChild(schema.name)}" value="×" onclick="TSM.stopPropagation(event)"> + <h:commandButton class="remove-btn" rendered="#{!tapSchemaEditing.toRemove(schema) and tapSchemaEditing.isSchemaRemovable(schema)}" action="#{tapSchemaEditing.tapSchema.removeChild(schema.name)}" value="×" onclick="TSM.stopPropagation(event)"> <f:ajax execute="@form" render="@form" /> </h:commandButton> </h:commandLink> @@ -144,11 +144,11 @@ <h:panelGroup id="tables_wrapper"> <ul class="nav nav-tabs" id="tables" role="tablist"> <ui:repeat value="#{tapSchemaEditing.selectedSchema.addedOrRemovedChildren}" var="table"> - <li role="presentation" class="removable-tab #{table.parent.name eq tapSchemaEditing.tapSchema.name ? 'unremovable-tab': ''} #{tapSchemaEditing.selectedTable.name eq table.name ? 'active':''} #{tapSchemaEditing.toRemove(table) ? 'to-remove':''}"> + <li role="presentation" class="removable-tab #{tapSchemaEditing.isSchemaRemovable(table.parent) ? '': 'unremovable-tab'} #{tapSchemaEditing.selectedTable.name eq table.name ? 'active':''} #{tapSchemaEditing.toRemove(table) ? 'to-remove':''}"> <h:commandLink role="tab" action="#{tapSchemaEditing.setSelectedTable(table)}"> <span class="#{tapSchemaEditing.toRemove(table) ? 'strikeout':''}">#{table.name}</span> <f:ajax execute="@form" render=":main:tables_wrapper" /> - <h:commandButton class="remove-btn" rendered="#{!tapSchemaEditing.toRemove(table) and table.parent.name ne tapSchemaEditing.tapSchema.name}" action="#{tapSchemaEditing.selectedSchema.removeChild(table.name)}" value="×" onclick="TSM.stopPropagation(event)"> + <h:commandButton class="remove-btn" rendered="#{!tapSchemaEditing.toRemove(table) and tapSchemaEditing.isSchemaRemovable(table.parent)}" action="#{tapSchemaEditing.selectedSchema.removeChild(table.name)}" value="×" onclick="TSM.stopPropagation(event)"> <f:ajax execute="@form" render=":main:tables_wrapper" /> </h:commandButton> </h:commandLink> @@ -236,7 +236,7 @@ <ui:repeat value="#{tapSchemaEditing.selectedTable.addedOrRemovedChildren}" var="column" id="columns-list"> <li role="presentation" class="#{tapSchemaEditing.selectedColumn.name eq column.name ? 'active': ''}"> <h:commandLink role="tab" action="#{tapSchemaEditing.setSelectedColumn(column)}" id="column-selector"> - <h:commandButton class="btn btn-link remove-btn" disabled="#{tapSchemaEditing.toRemove(column) or column.parent.parent.name eq tapSchemaEditing.tapSchema.name}" value="×" onclick="TSM.stopPropagation(event)" id="column-remover"> + <h:commandButton class="btn btn-link remove-btn" disabled="#{!tapSchemaEditing.isColumnRemovable(column)}" value="×" onclick="TSM.stopPropagation(event)" id="column-remover"> <f:ajax execute="@form" render=":main:tables_wrapper" listener="#{tapSchemaEditing.removeColumn(column.name)}" /> </h:commandButton> -- GitLab